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 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) + *

      + *
    1. + * 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. + *
    2. + *
    3. + * 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. + *
    4. + *
    + * + * @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) + *

      + *
    1. + * 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. + *
    2. + *
    + * + * @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 implements RenderParameter { + + private final String name; + private final Material material; + private final VarType type; + private T value; + + public MatRenderParam(String name, Material material, VarType type) { + this.name = name; + this.material = material; + this.type = type; + } + + @Override + public String getParameterName() { + return name; + } + @Override + public void accept(T value) { + this.value = value; + material.setParam(name, type, this.value); + } + @Override + public T produce() { + return value; + } + @Override + public void erase() { + value = null; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java new file mode 100644 index 0000000000..34793021d9 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java @@ -0,0 +1,85 @@ +/* + * 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.RenderManager; +import com.jme3.renderer.ViewPort; +import java.util.LinkedList; + +/** + * + * @author codex + */ +public class MyFrameGraph { + + private final LinkedList passes = new LinkedList<>(); + private final ParameterManager parameters = new ParameterManager(); + private final RenderContext context; + + public MyFrameGraph(RenderManager renderManager) { + context = new RenderContext(renderManager); + } + + public void execute(ViewPort vp) { + context.setViewPort(vp); + // prepare passes for execution + for (FGModule p : passes) { + p.prepare(context); + } + // execute + for (FGModule p : passes) { + // accept parameters as arguments to the pass + parameters.pull(p); + // execute pass + p.execute(context); + // apply resulting output parameters to connected input parameters + parameters.push(p); + } + // reset passes + for (FGModule p : passes) { + p.reset(); + } + } + + public void add(FGModule pass) { + pass.initialize(this); + passes.add(pass); + registerParameterGroup(pass); + } + + public ParameterManager getParameters() { + return parameters; + } + + public RenderContext getContext() { + return context; + } + + public T registerParameter(T param) { + parameters.register(param); + return param; + } + + public void registerParameterGroup(RenderParameterGroup group) { + parameters.register(group); + } + + public void bindToOutput(String target, RenderParameter input) { + parameters.bindToOutput(target, input); + } + + public void bindToInput(String target, RenderParameter output) { + parameters.bindToInput(target, output); + } + + public void removeParameter(RenderParameter param) { + parameters.remove(param); + } + + public void removeParameterGroup(RenderParameterGroup group) { + parameters.remove(group); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterBinding.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterBinding.java new file mode 100644 index 0000000000..507662c1cc --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterBinding.java @@ -0,0 +1,43 @@ +/* + * 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.Objects; + +/** + * + * @author codex + * @param + */ +public class ParameterBinding { + + private final RenderParameter output, input; + + public ParameterBinding(RenderParameter output, RenderParameter input) { + this.output = output; + this.input = input; + } + + public void applyOutputToInput() { + input.accept(output.produce()); + } + + public boolean isInput(RenderParameter input) { + return this.input == input; + } + + public boolean isOutput(RenderParameter output) { + return this.output == output; + } + + public boolean contains(RenderParameter p) { + return input == p || output == p; + } + + public boolean isViolating(ParameterBinding pb) { + return input == pb.input; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java new file mode 100644 index 0000000000..6511881f4b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java @@ -0,0 +1,124 @@ +/* + * 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.Iterator; +import java.util.LinkedList; + +/** + * + * @author codex + */ +public class ParameterManager { + + private final LinkedList parameters = new LinkedList<>(); + private final LinkedList bindings = new LinkedList<>(); + + public RenderParameter getParameter(String name, boolean failOnMiss) { + for (RenderParameter p : parameters) { + if (p.getParameterName().equals(name)) { + return p; + } + } + if (failOnMiss) { + throw new NullPointerException("Input parameter does not exist: "+name); + } + return null; + } + + public T register(T param) { + parameters.add(param); + return param; + } + + public void registerAll(RenderParameter... params) { + for (RenderParameter p : params) { + register(p); + } + } + + public void register(RenderParameterGroup group) { + for (RenderParameter p : group.getRenderParameters()) { + register(p); + } + } + + public ParameterBinding bindToOutput(String target, RenderParameter input) { + return createBinding(getParameter(target, false), input); + } + + public ParameterBinding bindToInput(String target, RenderParameter output) { + return createBinding(output, getParameter(target, false)); + } + + public ParameterBinding bind(RenderParameter output, RenderParameter input) { + return createBinding(output, input); + } + + private ParameterBinding createBinding(RenderParameter output, RenderParameter input) { + if (output == null || input == null) { + return null; + } + ParameterBinding binding = new ParameterBinding(output, input); + // remove previous bindings + for (Iterator it = bindings.iterator(); it.hasNext();) { + if (it.next().isViolating(binding)) { + it.remove(); + } + } + bindings.add(binding); + return binding; + } + + public void remove(RenderParameter param) { + parameters.remove(param); + for (Iterator it = bindings.iterator(); it.hasNext();) { + if (it.next().contains(param)) { + it.remove(); + } + } + } + + public void remove(RenderParameterGroup group) { + for (RenderParameter p : group.getRenderParameters()) { + remove(p); + } + } + + public void pull(RenderParameter input) { + for (ParameterBinding b : bindings) { + if (b.isInput(input)) { + b.applyOutputToInput(); + break; + } + } + } + + public void pull(RenderParameterGroup group) { + for (RenderParameter p : group.getRenderParameters()) { + pull(p); + } + } + + public void push(RenderParameter output) { + for (ParameterBinding b : bindings) { + if (b.isOutput(output)) { + b.applyOutputToInput(); + } + } + } + + public void push(RenderParameterGroup group) { + for (RenderParameter p : group.getRenderParameters()) { + push(p); + } + } + + public void clear() { + parameters.clear(); + bindings.clear(); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java similarity index 77% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java index cc0bf5ce6e..bbe83516c5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java @@ -40,35 +40,30 @@ * 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 { - - protected static class FGPipelineObjectState { - - public float startDepth; - public float endDepth; - - public FGPipelineObjectState(float startDepth, float endDepth) { - this.startDepth = startDepth; - this.endDepth = endDepth; - } - - } +public class RenderContext { private final RenderManager renderManager; private ViewPort viewPort; - protected FGPipelineObjectState currentPSO; + private final DepthRange depth = new DepthRange(); - public FGRenderContext(RenderManager renderManager, ViewPort viewPort) { + public RenderContext(RenderManager renderManager, ViewPort viewPort) { this.renderManager = renderManager; this.viewPort = viewPort; - currentPSO = new FGPipelineObjectState(0, 1); + } + public RenderContext(RenderManager renderManager) { + this(renderManager, null); + } + + public void setDepthRange(float start, float end) { + if (!depth.equals(start, end)) { + depth.set(start, end); + renderManager.getRenderer().setDepthRange(depth); + } } - 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 setDepthRange(DepthRange depth) { + if (!this.depth.equals(depth)) { + renderManager.getRenderer().setDepthRange(this.depth.set(depth)); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java new file mode 100644 index 0000000000..3e829eed74 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java @@ -0,0 +1,66 @@ +/* + * 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 codex + * @param + */ +public interface RenderParameter { + + /** + * Returns the name this parameter is identified by. + * + * @return + */ + public String getParameterName(); + + /** + * Applies the given value to this parameter. + * + * @param value + */ + public void accept(T value); + + /** + * Returns the value held by this parameter. + * + * @return + */ + public T produce(); + + /** + * Deletes the value held by this parameter. + */ + public default void erase() { + accept(null); + } + + /** + * Returns the next value + * + * @return + */ + public default boolean validate() { + return produce() != null; + } + + /** + * Returns the value returned by {@link #produce()} if {@link #validate()} + * returns true, otherwise returns the given value. + * + * @param value + * @return + */ + public default T produceOrElse(T value) { + if (validate()) { + return produce(); + } else { + return value; + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameterGroup.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameterGroup.java new file mode 100644 index 0000000000..9453f2386e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameterGroup.java @@ -0,0 +1,17 @@ +/* + * 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.Collection; + +/** + * + * @author codex + */ +public interface RenderParameterGroup { + + public Collection getRenderParameters(); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java new file mode 100644 index 0000000000..e8c3507e06 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java @@ -0,0 +1,51 @@ +/* + * 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.pass.RenderGeometry; +import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.RenderQueue; + +/** + * + * @author codex + */ +public abstract class RenderQueueModule extends AbstractModule implements RenderGeometry { + + protected ViewPort forcedViewPort; + protected GeometryList drawCommands; + protected boolean canExecute = false; + + public abstract void dispatchPassSetup(RenderQueue queue); + + public abstract void executeDrawCommands(RenderContext context); + + @Override + public void execute(RenderContext context) { + context.getRenderManager().setRenderGeometryHandler(this); + dispatchPassSetup(context.getRenderQueue()); + if (canExecute) { + executeDrawCommands(context); + } + context.getRenderManager().setRenderGeometryHandler(null); + } + + @Override + public void reset() { + if (drawCommands != null && drawCommands.size() > 0) { + drawCommands.clear(); + } + } + + public void setForcedViewPort(ViewPort vp) { + this.forcedViewPort = vp; + } + + public ViewPort getForcedViewPort() { + return forcedViewPort; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureTargetParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureTargetParam.java new file mode 100644 index 0000000000..494a5b7ea1 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureTargetParam.java @@ -0,0 +1,54 @@ +/* + * 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.FrameBufferTextureTarget; +import com.jme3.texture.Texture; + +/** + * + * @author codex + */ +public class TextureTargetParam implements RenderParameter { + + private final String name; + private FrameBufferTextureTarget target; + + public TextureTargetParam(String name, FrameBufferTextureTarget target) { + this.name = name; + this.target = target; + } + + @Override + public Texture produce() { + if (target != null) { + return target.getTexture(); + } else { + return null; + } + } + + @Override + public String getParameterName() { + return name; + } + + @Override + public void accept(Texture value) {} + + @Override + public void erase() { + target = null; + } + + public void setTextureTarget(FrameBufferTextureTarget target) { + this.target = target; + } + + public FrameBufferTextureTarget getTextureTarget() { + return target; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java new file mode 100644 index 0000000000..7a135a8a5a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java @@ -0,0 +1,38 @@ +/* + * 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 class ValueRenderParam implements RenderParameter { + + private final String name; + private T value; + + public ValueRenderParam(String name) { + this(name, null); + } + public ValueRenderParam(String name, T value) { + this.name = name; + this.value = value; + } + + @Override + public String getParameterName() { + return name; + } + @Override + public void accept(T value) { + this.value = value; + } + @Override + public T produce() { + return value; + } + +} 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 813b09a920..b01d431e4d 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,7 +6,7 @@ import com.jme3.light.LightList; import com.jme3.renderer.framegraph.FGBindable; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; /** * @@ -25,6 +25,6 @@ public LightList getLightData() { } @Override - public void bind(FGRenderContext renderContext) {} + public void bind(RenderContext renderContext) {} } 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 682b40d337..2fd3e395fc 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 @@ -31,19 +31,17 @@ */ package com.jme3.renderer.pass; -import com.jme3.renderer.framegraph.FGBindable; -import com.jme3.renderer.framegraph.FGContainerBindableSink; -import java.util.ArrayList; +import com.jme3.renderer.framegraph.BindableSink; -public class DeferredLightDataSink extends FGContainerBindableSink { +public class DeferredLightDataSink extends BindableSink { - public DeferredLightDataSink(String registeredName, ArrayList container, int index) { - super(registeredName, container, index); + public DeferredLightDataSink(String registeredName) { + super(registeredName); } @Override public void postLinkValidate() { - bLinkValidate = bindableProxy.targetBindable != null; + bLinkValidate = target != null; } } 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 cb20f8573a..83f0754a9b 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,7 +33,7 @@ import com.jme3.light.LightList; import com.jme3.renderer.framegraph.FGBindable; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.AbstractFGSource; public class DeferredLightDataSource extends AbstractFGSource { @@ -68,7 +68,7 @@ public LightList getLightData() { } @Override - public void bind(FGRenderContext renderContext) {} + public void bind(RenderContext renderContext) {} } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java new file mode 100644 index 0000000000..4726c0e4a8 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -0,0 +1,121 @@ +/* + * 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.pass; + +import com.jme3.asset.AssetManager; +import com.jme3.light.LightList; +import com.jme3.material.Material; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FGGlobal; +import com.jme3.renderer.framegraph.FrameBufferParam; +import com.jme3.renderer.framegraph.MatRenderParam; +import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.framegraph.ValueRenderParam; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.shader.VarType; +import com.jme3.ui.Picture; + +/** + * + * @author codex + */ +public class DeferredShadingModule extends ScreenModule { + + public final static String RT_0 = "Context_InGBuff0"; + public final static String RT_1 = "Context_InGBuff1"; + public final static String RT_2 = "Context_InGBuff2"; + public final static String RT_3 = "Context_InGBuff3"; + public final static String RT_4 = "Context_InGBuff4"; + public final static String LIGHT_DATA = "LIGHT_DATA"; + public final static String EXECUTE_STATE = "EXECUTE_STATE"; + protected final static String S_DEFERRED_PASS = "DeferredPass"; + private static final String MATDEF = "Common/MatDefs/ShadingCommon/DeferredShading.j3md"; + + protected MatRenderParam[] matParams = new MatRenderParam[5]; + protected ValueRenderParam lightList; + protected ValueRenderParam executeState; + protected FrameBufferParam frameBuffer; + + public DeferredShadingModule(AssetManager assetManager) { + super(assetManager, RenderQueue.Bucket.Opaque); + } + + @Override + public void initialize(MyFrameGraph frameGraph) { + + screenMat = createMaterial(); + screenRect = new Picture("DeferredShadingRect"); + screenRect.setWidth(1); + screenRect.setHeight(1); + screenRect.setMaterial(screenMat); + + // material render parameters automatically apply their values + matParams[0] = addParameter(new MatRenderParam(RT_0, screenMat, VarType.Texture2D)); + matParams[1] = addParameter(new MatRenderParam(RT_1, screenMat, VarType.Texture2D)); + matParams[2] = addParameter(new MatRenderParam(RT_2, screenMat, VarType.Texture2D)); + matParams[3] = addParameter(new MatRenderParam(RT_3, screenMat, VarType.Texture2D)); + matParams[4] = addParameter(new MatRenderParam(RT_4, screenMat, VarType.Texture2D)); + lightList = addParameter(new ValueRenderParam<>(LIGHT_DATA)); + executeState = addParameter(new ValueRenderParam<>(EXECUTE_STATE)); + frameBuffer = addParameter(new FrameBufferParam(FGGlobal.S_DEFAULT_FB, false, true, true)); + bindParameters(frameGraph); + + } + + protected Material createMaterial() { + return new Material(assetManager, MATDEF); + } + + protected void bindParameters(MyFrameGraph frameGraph) { + for (int i = 0; i < matParams.length; i++) { + frameGraph.bindToOutput(GBufferPass.RENDER_TARGETS[i], matParams[i]); + } + frameGraph.bindToOutput(GBufferPass.LIGHT_DATA, lightList); + frameGraph.bindToOutput(GBufferPass.EXECUTE_STATE, executeState); + frameGraph.bindToOutput(GBufferPass.G_FRAME_BUFFER, frameBuffer); + } + + @Override + public void prepare(RenderContext context) { + super.prepare(context); + ViewPort vp = forcedViewPort; + if (vp == null) { + vp = context.getViewPort(); + } + frameBuffer.accept(vp.getOutputFrameBuffer()); + executeState.accept(false); + lightList.erase(); + } + + @Override + public void executeDrawCommands(RenderContext renderContext) { + screenMat.selectTechnique(S_DEFERRED_PASS, renderContext.getRenderManager()); + 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, lightList.produce(), renderContext.getRenderManager()); + screenMat.getAdditionalRenderState().setDepthWrite(depthWrite); + screenMat.getAdditionalRenderState().setDepthTest(depthTest); + } + + @Override + public void dispatchPassSetup(RenderQueue queue) { + boolean exState = executeState.validate() && executeState.produce(); + boolean hasLightData = lightList.validate() && lightList.produce().size() > 0; + canExecute = hasLightData || exState; + } + + @Override + public boolean drawGeometry(RenderManager rm, Geometry geom) { + return true; + } + +} 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 b01ff7c1fa..b054edfbb8 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 @@ -65,7 +65,7 @@ public DeferredShadingPass(String name) { } @Override - public void prepare(FGRenderContext renderContext) { + public void prepare(RenderContext renderContext) { super.prepare(renderContext); ViewPort vp = renderContext.getViewPort(); if(forceViewPort != null){ @@ -89,18 +89,18 @@ 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())); + registerBindableSink(new MatParamSink(S_RT_0, screenMat, VarType.Texture2D)); + registerBindableSink(new MatParamSink(S_RT_1, screenMat, VarType.Texture2D)); + registerBindableSink(new MatParamSink(S_RT_2, screenMat, VarType.Texture2D)); + registerBindableSink(new MatParamSink(S_RT_3, screenMat, VarType.Texture2D)); + registerBindableSink(new MatParamSink(S_RT_4, screenMat, VarType.Texture2D)); + registerBindableSink(new DeferredLightDataSink(S_LIGHT_DATA)); + registerBindableSink(new FGVarBindableSink(S_EXECUTE_STATE)); + registerBindableSink(new FGFramebufferCopyBindableSink(FGGlobal.S_DEFAULT_FB, null, false, true, true)); } @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext renderContext) { screenMat.selectTechnique(_S_DEFERRED_PASS, renderContext.getRenderManager()); DeferredLightDataSink deferredLightDataSink = (DeferredLightDataSink) getSink(S_LIGHT_DATA); DeferredLightDataSource.DeferredLightDataProxy deferredLightDataProxy = (DeferredLightDataSource.DeferredLightDataProxy) deferredLightDataSink.getBind(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java new file mode 100644 index 0000000000..2f9d13a387 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java @@ -0,0 +1,66 @@ +/* + * 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.pass; + +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.framegraph.RenderQueueModule; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; + +/** + * + * @author codex + */ +public class ForwardModule extends RenderQueueModule { + + private final RenderQueue.Bucket bucket; + protected DepthRange depth; + + public ForwardModule(RenderQueue.Bucket bucket) { + this(bucket, null); + } + public ForwardModule(RenderQueue.Bucket bucket, DepthRange depth) { + this.bucket = bucket; + this.depth = depth; + } + + @Override + public void dispatchPassSetup(RenderQueue queue) { + canExecute = !queue.isQueueEmpty(bucket); + } + @Override + public void executeDrawCommands(RenderContext context) { + if (!canExecute) { + return; + } + if (depth != null) { + context.setDepthRange(depth); + } + context.getRenderQueue().renderQueue(bucket, context.getRenderManager(), context.getViewPort().getCamera(), true); + } + @Override + public void initialize(MyFrameGraph frameGraph) {} + @Override + public void prepare(RenderContext context) {} + @Override + public boolean drawGeometry(RenderManager rm, Geometry geom) { + rm.renderGeometry(geom); + return true; + } + + public static ForwardModule sky() { + return new ForwardModule(RenderQueue.Bucket.Sky, new DepthRange(1, 1)); + } + public static ForwardModule transparent() { + return new ForwardModule(RenderQueue.Bucket.Transparent, DepthRange.IDENTITY); + } + public static ForwardModule translucent() { + return new ForwardModule(RenderQueue.Bucket.Translucent, DepthRange.IDENTITY); + } + +} 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 c094857e9d..059918ef30 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 @@ -33,7 +33,7 @@ import com.jme3.renderer.Camera; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.FGRenderQueuePass; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; @@ -49,7 +49,7 @@ public ForwardPass(String name, RenderQueue.Bucket bucket) { } @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext renderContext) { if (!canExecute) { return; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java new file mode 100644 index 0000000000..fc1bb2d085 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java @@ -0,0 +1,164 @@ +/* + * 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.pass; + +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.MyFrameGraph; +import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.framegraph.TextureTargetParam; +import com.jme3.renderer.framegraph.ValueRenderParam; +import com.jme3.scene.Geometry; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture2D; +import java.util.ArrayList; + +/** + * + * @author codex + */ +public class GBufferModule extends OpaqueModule { + + 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 ArrayList tempLights = new ArrayList<>(); + private ValueRenderParam hasDraw; + private FrameBuffer gBuffer; + private ValueRenderParam bufferParam; + private final TextureTargetParam[] targets = new TextureTargetParam[5]; + private final ColorRGBA mask = new ColorRGBA(0, 0, 0, 0); + private int width = -1, height = -1; + + @Override + public void initialize(MyFrameGraph frameGraph) { + super.initialize(frameGraph); + for (int i = 0; i < targets.length; i++) { + targets[i] = addParameter(new TextureTargetParam(RENDER_TARGETS[i], null)); + } + addParameter(new ValueRenderParam<>(LIGHT_DATA, lightData)); + hasDraw = addParameter(new ValueRenderParam<>(EXECUTE_STATE, false)); + bufferParam = addParameter(new ValueRenderParam<>(G_FRAME_BUFFER, gBuffer)); + } + + @Override + public void prepare(RenderContext context) { + super.prepare(context); + ViewPort vp = getViewPort(context); + reshape(context.getRenderer(), vp.getCamera().getWidth(), vp.getCamera().getHeight()); + } + + @Override + public void executeDrawCommands(RenderContext context) { + if(canExecute){ + hasDraw.accept(false); + tempLights.clear(); + lightData.clear(); + ViewPort vp = getViewPort(context); + //reshape(context.getRenderer(), vp.getCamera().getWidth(), vp.getCamera().getHeight()); + FrameBuffer opfb = vp.getOutputFrameBuffer(); + vp.setOutputFrameBuffer(gBuffer); + ColorRGBA opClearColor = vp.getBackgroundColor(); + mask.set(opClearColor); + mask.a = 0.0f; + context.getRenderer().setFrameBuffer(gBuffer); + context.getRenderer().setBackgroundColor(mask); + context.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); + String techOrig = context.getRenderManager().getForcedTechnique(); + context.getRenderManager().setForcedTechnique(GBUFFER_PASS); + super.executeDrawCommands(context); + context.getRenderManager().setForcedTechnique(techOrig); + vp.setOutputFrameBuffer(opfb); + context.getRenderer().setBackgroundColor(opClearColor); + context.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer()); + //bHasDrawVarSource.setValue(bHasDraw); + if (hasDraw.produce()) { + for(Light light : tempLights){ + lightData.add(light); + } + //context.getRenderer().copyFrameBuffer(gBuffer, vp.getOutputFrameBuffer(), false, true); + } + } + } + + @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){ + if(material.getMaterialDef().getTechniqueDefs(GBUFFER_PASS) != null){ + LightList lights = geom.getFilterWorldLights(); + for(Light light : lights){ + if(!tempLights.contains(light)){ + tempLights.add(light); + } + } + // Whether it has lights or not, material objects containing GBufferPass will perform + // DeferredShading, and shade according to shadingModelId + hasDraw.accept(true); + return true; + } + } + return false; + } + + @Override + public void reset() { + super.reset(); + tempLights.clear(); + lightData.clear(); + hasDraw.accept(false); + } + + protected void reshape(Renderer renderer, int w, int h) { + if (width == w && height == h) { + return; + } + width = w; + height = h; + if (gBuffer != null) { + gBuffer.dispose(); + gBuffer.deleteObject(renderer); + } + gBuffer = new FrameBuffer(w, h, 1); + // To ensure accurate results, 32bit is used here for generalization. + Texture2D[] textures = new Texture2D[5]; + textures[0] = new Texture2D(w, h, Image.Format.RGBA16F); + textures[1] = new Texture2D(w, h, Image.Format.RGBA16F); + textures[2] = new Texture2D(w, h, Image.Format.RGBA16F); + // The third buffer provides 32-bit floating point to store high-precision information, such as normals + textures[3] = new Texture2D(w, h, Image.Format.RGBA32F); + // 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. + textures[4] = new Texture2D(w, h, Image.Format.Depth); + for (int i = 0; i < textures.length; i++) { + FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget(textures[i]); + gBuffer.addColorTarget(t); + targets[i].setTextureTarget(t); + } + gBuffer.setMultiTarget(true); + bufferParam.accept(gBuffer); + } + + protected ViewPort getViewPort(RenderContext context) { + if (forcedViewPort == null) { + return context.getViewPort(); + } else { + return forcedViewPort; + } + } + +} 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 8bfe8e2364..8bd9eec117 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 @@ -39,8 +39,8 @@ import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.FramebufferSource; -import com.jme3.renderer.framegraph.FGRenderContext; -import com.jme3.renderer.framegraph.FGRenderTargetSource; +import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.framegraph.FGShaderResource; import com.jme3.renderer.framegraph.FGVarSource; import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; @@ -75,7 +75,7 @@ public GBufferPass() { } @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext renderContext) { if(canExecute){ bHasDraw = false; tempLights.clear(); @@ -97,7 +97,7 @@ public void executeDrawCommandList(FGRenderContext renderContext) { renderContext.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); String techOrig = renderContext.getRenderManager().getForcedTechnique(); renderContext.getRenderManager().setForcedTechnique(GBUFFER_PASS); - super.executeDrawCommandList(renderContext); + super.executeDrawCommands(renderContext); renderContext.getRenderManager().setForcedTechnique(techOrig); vp.setOutputFrameBuffer(opfb); renderContext.getRenderer().setBackgroundColor(opClearColor); @@ -149,10 +149,11 @@ public void reshape(Renderer renderer, ViewPort vp, int w, int h){ // 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); + //gBuffer.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(Image.Format.RGBA8)); 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.addColorTarget(target); + //registerSource(new FGRenderTargetSource(RENDER_TARGETS[i], target)); } gBuffer.setMultiTarget(true); registerSource(new DeferredLightDataSource(LIGHT_DATA, lightData)); @@ -184,7 +185,7 @@ public boolean drawGeometry(RenderManager rm, Geometry geom) { } @Override - public void prepare(FGRenderContext renderContext) { + public void prepare(RenderContext renderContext) { super.prepare(renderContext); ViewPort vp; if(forceViewPort != null){ diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java new file mode 100644 index 0000000000..da2f6eb96b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java @@ -0,0 +1,39 @@ +/* + * 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.pass; + +import com.jme3.renderer.Camera; +import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.queue.RenderQueue; + +/** + * + * @author codex + */ +public class GuiModule extends ForwardModule { + + public GuiModule() { + super(RenderQueue.Bucket.Gui); + } + + @Override + public void executeDrawCommands(RenderContext context) { + Camera cam; + if (forcedViewPort != null) { + cam = forcedViewPort.getCamera(); + } else { + cam = context.getViewPort().getCamera(); + } + if (canExecute) { + context.setDepthRange(0, 0); + context.getRenderManager().setCamera(cam, true); + } + super.executeDrawCommands(context); + if (canExecute) { + context.getRenderManager().setCamera(cam, false); + } + } + +} 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 eeca3c4f42..e50d378b59 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 @@ -32,7 +32,7 @@ package com.jme3.renderer.pass; import com.jme3.renderer.Camera; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.queue.RenderQueue; /** @@ -40,21 +40,21 @@ */ public class GuiPass extends ForwardPass{ @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext context) { Camera cam = null; if(forceViewPort != null){ cam = forceViewPort.getCamera(); } else{ - cam = renderContext.getViewPort().getCamera(); + cam = context.getViewPort().getCamera(); } if(canExecute){ - renderContext.setDepthRange(0, 0); - renderContext.getRenderManager().setCamera(cam, true); + context.setDepthRange(0, 0); + context.getRenderManager().setCamera(cam, true); } - super.executeDrawCommandList(renderContext); + super.executeDrawCommands(context); if(canExecute){ - renderContext.getRenderManager().setCamera(cam, false); + context.getRenderManager().setCamera(cam, false); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/OpaqueModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/OpaqueModule.java new file mode 100644 index 0000000000..c771ed844f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/OpaqueModule.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.pass; + +import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.queue.RenderQueue; + +/** + * + * @author codex + */ +public class OpaqueModule extends ForwardModule { + + public OpaqueModule() { + super(RenderQueue.Bucket.Opaque); + } + + @Override + public void executeDrawCommands(RenderContext renderContext) { + if (canExecute) { + renderContext.setDepthRange(0, 1); + } + super.executeDrawCommands(renderContext); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java index f4c98956aa..f31888aaaf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java @@ -31,7 +31,7 @@ */ package com.jme3.renderer.pass; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.queue.RenderQueue; /** @@ -43,11 +43,11 @@ public OpaquePass(String name) { } @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext renderContext) { if(canExecute){ renderContext.setDepthRange(0, 1); } - super.executeDrawCommandList(renderContext); + super.executeDrawCommands(renderContext); } public OpaquePass() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java new file mode 100644 index 0000000000..bdbeffc502 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java @@ -0,0 +1,68 @@ +/* + * 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.pass; + +import com.jme3.post.SceneProcessor; +import com.jme3.profile.AppProfiler; +import com.jme3.profile.SpStep; +import com.jme3.profile.VpStep; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.AbstractModule; +import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.util.SafeArrayList; + +/** + * + * @author codex + */ +public class PostProcessingModule extends AbstractModule { + + private AppProfiler profiler; + + public PostProcessingModule() { + this(null); + } + public PostProcessingModule(AppProfiler profiler) { + this.profiler = profiler; + } + + @Override + public void initialize(MyFrameGraph frameGraph) {} + @Override + public void prepare(RenderContext context) {} + @Override + public void execute(RenderContext context) { + context.setDepthRange(DepthRange.IDENTITY); + ViewPort vp = context.getViewPort(); + SafeArrayList processors = vp.getProcessors(); + if (processors != null) { + if (profiler != null) { + profiler.vpStep(VpStep.PostFrame, vp, null); + } + for (SceneProcessor p : processors.getArray()) { + if (profiler != null) { + profiler.spStep(SpStep.ProcPostFrame, p.getClass().getSimpleName()); + } + p.postFrame(vp.getOutputFrameBuffer()); + } + if (profiler != null) { + profiler.vpStep(VpStep.ProcEndRender, vp, null); + } + } + } + @Override + public void reset() {} + + public void setProfiler(AppProfiler profiler) { + this.profiler = profiler; + } + + public AppProfiler getProfiler() { + return profiler; + } + +} 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 2604f72f9d..4746fe82e3 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 @@ -34,7 +34,7 @@ import com.jme3.post.SceneProcessor; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.AbstractFGPass; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; import com.jme3.util.SafeArrayList; /** @@ -47,7 +47,7 @@ public PostProcessorPass(String name) { } @Override - public void execute(FGRenderContext renderContext) { + public void execute(RenderContext renderContext) { renderContext.setDepthRange(0, 1); ViewPort vp = renderContext.getViewPort(); SafeArrayList processors = vp.getProcessors(); @@ -62,6 +62,6 @@ public void execute(FGRenderContext renderContext) { } @Override - public void prepare(FGRenderContext renderContext) {} + public void prepare(RenderContext renderContext) {} } 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 ad2c2d9c3d..b0e1739175 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 @@ -59,7 +59,7 @@ public void dispatchPassSetup(RenderQueue renderQueue) { } @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext renderContext) { renderContext.getRenderer().setFrameBuffer(null); boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite(); boolean depthTest = screenMat.getAdditionalRenderState().isDepthTest(); @@ -89,7 +89,7 @@ public void init() { 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())); + registerBindableSink(new MatParamSink(S_SCENE_COLOR_RT, screenMat, VarType.Texture2D)); + registerBindableSink(new FGFramebufferCopyBindableSink(FGGlobal.S_DEFAULT_FB, null, false, true, true)); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenModule.java new file mode 100644 index 0000000000..a6c3d42fea --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenModule.java @@ -0,0 +1,31 @@ +/* + * 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.pass; + +import com.jme3.asset.AssetManager; +import com.jme3.material.Material; +import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.ui.Picture; + +/** + * + * @author codex + */ +public abstract class ScreenModule extends ForwardModule { + + protected final AssetManager assetManager; + protected Material screenMat; + protected Picture screenRect; + + public ScreenModule(AssetManager assetManager, RenderQueue.Bucket bucket) { + super(bucket); + this.assetManager = assetManager; + } + + @Override + public abstract void initialize(MyFrameGraph frameGraph); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java index 17f0dda921..79a11ebbdc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java @@ -31,7 +31,7 @@ */ package com.jme3.renderer.pass; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.queue.RenderQueue; /** @@ -43,10 +43,10 @@ public SkyPass() { } @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext context) { if(canExecute){ - renderContext.setDepthRange(1, 1); + context.setDepthRange(1, 1); } - super.executeDrawCommandList(renderContext); + super.executeDrawCommands(context); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java new file mode 100644 index 0000000000..93c1e818ab --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java @@ -0,0 +1,47 @@ +/* + * 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.pass; + +import com.jme3.asset.AssetManager; +import com.jme3.material.Material; +import com.jme3.renderer.framegraph.RenderContext; + +/** + * + * @author codex + */ +public class TileDeferredShadingModule extends DeferredShadingModule { + + private static final String MATDEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"; + protected final static String PASS = "TileBasedDeferredPass"; + + public TileDeferredShadingModule(AssetManager assetManager) { + super(assetManager); + } + + @Override + protected Material createMaterial() { + return new Material(assetManager, MATDEF); + } + + @Override + public void executeDrawCommands(RenderContext context) { + + // Handle FullScreenLights + screenMat.selectTechnique(PASS, context.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, lightList.produce(), context.getRenderManager()); + screenMat.getAdditionalRenderState().setDepthTest(depthTest); + screenMat.getAdditionalRenderState().setDepthWrite(depthWrite); + + // Handle non-fullscreen lights + } + +} 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 20e2fcc4cd..1f18888c68 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 @@ -34,11 +34,11 @@ import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.material.MaterialDef; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; public class TileDeferredShadingPass extends DeferredShadingPass{ - private static final String MAT_DEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"; + private static final String MATDEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"; protected final static String PASS = "TileBasedDeferredPass"; public TileDeferredShadingPass() { @@ -47,13 +47,13 @@ public TileDeferredShadingPass() { @Override protected Material getMaterial() { - MaterialDef def = (MaterialDef) assetManager.loadAsset(MAT_DEF); + MaterialDef def = (MaterialDef) assetManager.loadAsset(MATDEF); screenMat = new Material(def); return screenMat; } @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext renderContext) { DeferredLightDataSink deferredLightDataSink = (DeferredLightDataSink) getSink(S_LIGHT_DATA); DeferredLightDataSource.DeferredLightDataProxy deferredLightDataProxy = (DeferredLightDataSource.DeferredLightDataProxy) deferredLightDataSink.getBind(); LightList lights = deferredLightDataProxy.getLightData(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java index 67a2f1e9c1..8f9d19c245 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java @@ -31,16 +31,16 @@ */ package com.jme3.renderer.pass; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.queue.RenderQueue; public class TranslucentPass extends ForwardPass{ @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext renderContext) { if(canExecute){ renderContext.setDepthRange(0, 1); } - super.executeDrawCommandList(renderContext); + super.executeDrawCommands(renderContext); } public TranslucentPass() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java index 5496bdebb5..117b65335f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java @@ -31,7 +31,7 @@ */ package com.jme3.renderer.pass; -import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.queue.RenderQueue; /** @@ -39,11 +39,11 @@ */ public class TransparentPass extends ForwardPass{ @Override - public void executeDrawCommandList(FGRenderContext renderContext) { + public void executeDrawCommands(RenderContext renderContext) { if(canExecute){ renderContext.setDepthRange(0, 1); } - super.executeDrawCommandList(renderContext); + super.executeDrawCommands(renderContext); } public TransparentPass() { diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java index 450feb0384..66181ff35e 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java @@ -449,15 +449,15 @@ private void setUpLights() { directionalLight.setColor(ColorRGBA.White); rootNode.addLight(directionalLight); - 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); - p.setColor(ColorRGBA.randomColor()); - rootNode.addLight(p); - } - } +// 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); +// p.setColor(ColorRGBA.randomColor()); +// rootNode.addLight(p); +// } +// } ambientLight = new AmbientLight(); directionalLight.setColor(ColorRGBA.White); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/CustomPass.java b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/CustomPass.java deleted file mode 100644 index 44a352e59f..0000000000 --- a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/CustomPass.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 index 7f47aef17f..22756fa1b2 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java @@ -15,6 +15,8 @@ public class FrameGraphSandbox extends SimpleApplication { @Override public void simpleInitApp() { + + } } From 60c5def861d749215c38760ba457569a1354145b Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 19 Apr 2024 12:29:33 -0400 Subject: [PATCH 034/111] fixed framebuffer attachments bug --- .../java/com/jme3/renderer/RenderManager.java | 32 ++++++++- .../renderer/framegraph/MatParamSink.java | 2 +- .../renderer/framegraph/MatRenderParam.java | 8 +++ .../framegraph/RenderPipelineFactory.java | 69 +++++++++++++++++++ .../renderer/pass/DeferredShadingModule.java | 7 +- .../com/jme3/renderer/pass/GBufferModule.java | 30 ++++++-- .../pass/TileDeferredShadingModule.java | 7 ++ .../jme3test/renderpath/TestShadingModel.java | 55 +++++++++------ 8 files changed, 176 insertions(+), 34 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.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 7e064b7e47..c78ac0ba27 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -50,6 +50,7 @@ import com.jme3.renderer.framegraph.FGGlobal; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; @@ -108,6 +109,7 @@ public class RenderManager { private TranslucentPass translucentPass; private GuiPass guiPass; private PostProcessorPass postProcessorPass; + private MyFrameGraph myGraph; // frameGraph=============================================================================↑ // RenderPath @@ -217,6 +219,15 @@ public int getForceTileSize() { public final void enableFramegraph(boolean useFramegraph){ this.useFramegraph = useFramegraph; } + + /** + * Sets the framegraph used in the rendering process. + * + * @param frameGraph + */ + public void setFrameGraph(MyFrameGraph frameGraph) { + this.myGraph = frameGraph; + } /** * 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. @@ -237,11 +248,21 @@ public int getMaxDeferredShadingLights() { * @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){ + private void setTileInfo(int tileSize, int tileWidth, int tileHeight, int tileNum){ if(tileInfo == null){ tileInfo = new TileBasedDeferredSinglePassLightingLogic.TileInfo(tileSize, tileWidth, tileHeight, tileNum); } } + + /** + * Calculates tiling info. + */ + public void calculateTileInfo() { + curTileSize = (forceTileSize > 0 ? forceTileSize : (getCurrentCamera().getWidth() / numberTileDivisions)); + int tileWidth = viewWidth / curTileSize; + int tileHeight = viewHeight / curTileSize; + setTileInfo(curTileSize, tileWidth, tileHeight, tileWidth * tileHeight); + } /** * update tile size.
    @@ -1394,8 +1415,13 @@ public void renderViewPort(ViewPort vp, float tpf) { p.postQueue(vp.getQueue()); } } - - if(useFramegraph){ + + if (myGraph != null) { + + // to execute the rendering process, simply call execute on the framegraph + myGraph.execute(vp); + + } else if (useFramegraph) { RenderPath curRenderPath = vp.getRenderPath() == RenderPath.None ? renderPath : vp.getRenderPath(); frameGraph.reset(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java index af8613ffa8..05ccf7ddbe 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java @@ -55,7 +55,7 @@ public void bind(FGSource src) { return; } linked = true; - value = ()((FGShaderResource)p).getResource(); + //value = ()((FGShaderResource)p).getResource(); //bindableProxy.targetBindable = proxy; target = this; } 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 index a63a13a169..7f8a22e574 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java @@ -17,6 +17,7 @@ public class MatRenderParam implements RenderParameter { private final String name; private final Material material; private final VarType type; + private boolean debug = false; private T value; public MatRenderParam(String name, Material material, VarType type) { @@ -32,6 +33,9 @@ public String getParameterName() { @Override public void accept(T value) { this.value = value; + if (debug) { + System.out.println("assign to material: "+this.value); + } material.setParam(name, type, this.value); } @Override @@ -43,4 +47,8 @@ public void erase() { value = null; } + public void enableDebug() { + debug = true; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java new file mode 100644 index 0000000000..e17b8da472 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java @@ -0,0 +1,69 @@ +/* + * 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.app.Application; +import com.jme3.asset.AssetManager; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.RenderManager.RenderPath; +import com.jme3.renderer.pass.DeferredShadingModule; +import com.jme3.renderer.pass.ForwardModule; +import com.jme3.renderer.pass.GBufferModule; +import com.jme3.renderer.pass.GuiModule; +import com.jme3.renderer.pass.OpaqueModule; +import com.jme3.renderer.pass.PostProcessingModule; +import com.jme3.renderer.pass.TileDeferredShadingModule; + +/** + * Constructs basic framegraphs. + * + * @author codex + */ +public class RenderPipelineFactory { + + public static MyFrameGraph create(Application app, RenderPath path) { + RenderManager rm = app.getRenderManager(); + switch (path) { + case Forward: return createForwardPipeline(rm); + case ForwardPlus: return createForwardPlusPipeline(rm); + case Deferred: return createDeferredPipeline(app.getAssetManager(), rm); + case TiledDeferred: return createTileDeferredPipeline(app.getAssetManager(), rm); + default: return null; + } + } + + private static MyFrameGraph addBasicPasses(MyFrameGraph g) { + g.add(new OpaqueModule()); + g.add(ForwardModule.sky()); + g.add(ForwardModule.transparent()); + g.add(new GuiModule()); + g.add(new PostProcessingModule()); + g.add(ForwardModule.translucent()); + return g; + } + + public static MyFrameGraph createForwardPipeline(RenderManager rm) { + return addBasicPasses(new MyFrameGraph(rm)); + } + + public static MyFrameGraph createForwardPlusPipeline(RenderManager rm) { + throw new UnsupportedOperationException("ForwardPlus render pipeline is currently unsupported."); + } + + public static MyFrameGraph createDeferredPipeline(AssetManager am, RenderManager rm) { + MyFrameGraph g = new MyFrameGraph(rm); + g.add(new GBufferModule()); + g.add(new DeferredShadingModule(am)); + return addBasicPasses(g); + } + + public static MyFrameGraph createTileDeferredPipeline(AssetManager am, RenderManager rm) { + MyFrameGraph g = new MyFrameGraph(rm); + g.add(new GBufferModule()); + g.add(new TileDeferredShadingModule(am)); + return addBasicPasses(g); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java index 4726c0e4a8..a6e1ac0da2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -88,8 +88,8 @@ public void prepare(RenderContext context) { vp = context.getViewPort(); } frameBuffer.accept(vp.getOutputFrameBuffer()); - executeState.accept(false); - lightList.erase(); + //executeState.accept(false); + //lightList.erase(); } @Override @@ -101,7 +101,8 @@ public void executeDrawCommands(RenderContext renderContext) { screenMat.getAdditionalRenderState().setDepthTest(false); screenMat.setBoolean("UseLightsCullMode", false); screenRect.updateGeometricState(); - screenMat.render(screenRect, lightList.produce(), renderContext.getRenderManager()); + LightList lights = lightList.produce(); + 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/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java index fc1bb2d085..719fa583e0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java @@ -96,7 +96,9 @@ public void executeDrawCommands(RenderContext context) { @Override public boolean drawGeometry(RenderManager rm, Geometry geom) { Material material = geom.getMaterial(); - if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null)return false; + if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null) { + return false; + } rm.renderGeometry(geom); if(material.getActiveTechnique() != null){ if(material.getMaterialDef().getTechniqueDefs(GBUFFER_PASS) != null){ @@ -144,11 +146,27 @@ protected void reshape(Renderer renderer, int w, int h) { // 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. textures[4] = new Texture2D(w, h, Image.Format.Depth); - for (int i = 0; i < textures.length; i++) { - FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget(textures[i]); - gBuffer.addColorTarget(t); - targets[i].setTextureTarget(t); - } + //gBuffer.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(Image.Format.RGBA8)); + //for (int i = 0; i < textures.length; i++) { + // FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget(textures[i]); + // gBuffer.addColorTarget(t); + // targets[i].setTextureTarget(t); + //} + FrameBuffer.FrameBufferTextureTarget t0 = FrameBuffer.FrameBufferTarget.newTarget(textures[0]); + gBuffer.addColorTarget(t0); + targets[0].setTextureTarget(t0); + FrameBuffer.FrameBufferTextureTarget t1 = FrameBuffer.FrameBufferTarget.newTarget(textures[1]); + gBuffer.addColorTarget(t1); + targets[1].setTextureTarget(t1); + FrameBuffer.FrameBufferTextureTarget t2 = FrameBuffer.FrameBufferTarget.newTarget(textures[2]); + gBuffer.addColorTarget(t2); + targets[2].setTextureTarget(t2); + FrameBuffer.FrameBufferTextureTarget t3 = FrameBuffer.FrameBufferTarget.newTarget(textures[3]); + gBuffer.addColorTarget(t3); + targets[3].setTextureTarget(t3); + FrameBuffer.FrameBufferTextureTarget t4 = FrameBuffer.FrameBufferTarget.newTarget(textures[4]); + gBuffer.setDepthTarget(t4); + targets[4].setTextureTarget(t4); gBuffer.setMultiTarget(true); bufferParam.accept(gBuffer); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java index 93c1e818ab..5aad028648 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java @@ -6,6 +6,7 @@ import com.jme3.asset.AssetManager; import com.jme3.material.Material; +import com.jme3.renderer.Camera; import com.jme3.renderer.framegraph.RenderContext; /** @@ -44,4 +45,10 @@ public void executeDrawCommands(RenderContext context) { // Handle non-fullscreen lights } + @Override + public void prepare(RenderContext context) { + super.prepare(context); + context.getRenderManager().calculateTileInfo(); + } + } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index bdba06efa7..a6e285eb73 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -2,11 +2,7 @@ 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; @@ -14,11 +10,16 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.MatRenderParam; +import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.RenderPipelineFactory; +import com.jme3.renderer.pass.GBufferModule; 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.Quad; import com.jme3.scene.shape.Sphere; +import com.jme3.shader.VarType; import com.jme3.texture.plugins.ktx.KTXLoader; import com.jme3.util.SkyFactory; import com.jme3.util.TangentBinormalGenerator; @@ -41,7 +42,19 @@ public class TestShadingModel extends SimpleApplication { @Override public void simpleInitApp() { - + + MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); + renderManager.setFrameGraph(graph); + + Geometry debugView = new Geometry("debug", new Quad(200, 200)); + debugView.setLocalTranslation(0, 200, 0); + Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + debugView.setMaterial(debugMat); + MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); + //texParam.enableDebug(); + graph.bindToOutput(GBufferModule.RENDER_TARGETS[3], texParam); + guiNode.attachChild(debugView); + // UNLIT Material unlitMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); unlitMat.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg")); @@ -110,21 +123,21 @@ 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 == 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); } From a3af1e2dde7606ecef3931f6a5b8326a5e94f68e Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 19 Apr 2024 15:21:09 -0400 Subject: [PATCH 035/111] deferred shading usable --- .../framegraph/FrameBufferCopyParam.java | 66 +++++++++++++++++++ .../renderer/framegraph/MatRenderParam.java | 9 ++- .../renderer/framegraph/MyFrameGraph.java | 8 +-- .../renderer/framegraph/ParameterManager.java | 8 ++- .../renderer/framegraph/RenderParameter.java | 24 +++++++ .../renderer/pass/DeferredShadingModule.java | 54 ++++++++------- .../com/jme3/renderer/pass/GBufferModule.java | 13 ++-- .../pass/TileDeferredShadingModule.java | 2 +- .../ShadingCommon/DeferredShading.frag | 2 + .../com/jme3/material/plugins/J3MLoader.java | 1 + .../jme3test/renderpath/TestShadingModel.java | 36 +++++----- 11 files changed, 165 insertions(+), 58 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java new file mode 100644 index 0000000000..7c03b8559f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java @@ -0,0 +1,66 @@ +/* + * 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.Renderer; +import com.jme3.texture.FrameBuffer; + +/** + * + * @author codex + */ +public class FrameBufferCopyParam implements RenderParameter { + + private final String name; + private Renderer renderer; + private FrameBuffer target, source; + private final boolean copyColor, copyDepth; + + public FrameBufferCopyParam(String name, Renderer renderer, FrameBuffer target, boolean copyColor, boolean copyDepth) { + this.name = name; + this.renderer = renderer; + this.target = target; + this.copyColor = copyColor; + this.copyDepth = copyDepth; + } + + @Override + public String getParameterName() { + return name; + } + @Override + public void accept(FrameBuffer value) { + if (source != value) { + source = value; + System.out.println("incoming framebuffer source"); + if (source != null && target != null && renderer != null) { + System.out.println("make buffer copy"); + renderer.copyFrameBuffer(source, target, copyColor, copyDepth); + } + } + } + @Override + public FrameBuffer produce() { + return target; + } + + public void setRenderer(Renderer renderer) { + this.renderer = renderer; + } + public void setTarget(FrameBuffer target) { + this.target = target; + } + + public FrameBuffer getSource() { + return source; + } + public boolean isCopyColor() { + return copyColor; + } + public boolean isCopyDepth() { + return copyDepth; + } + +} 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 index 7f8a22e574..e15f1fed66 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java @@ -15,13 +15,18 @@ public class MatRenderParam implements RenderParameter { private final String name; + private final String matName; private final Material material; private final VarType type; private boolean debug = false; private T value; - + public MatRenderParam(String name, Material material, VarType type) { + this(name, material, name, type); + } + public MatRenderParam(String name, Material material, String matName, VarType type) { this.name = name; + this.matName = matName; this.material = material; this.type = type; } @@ -36,7 +41,7 @@ public void accept(T value) { if (debug) { System.out.println("assign to material: "+this.value); } - material.setParam(name, type, this.value); + material.setParam(matName, type, this.value); } @Override public T produce() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java index 34793021d9..902a09650e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java @@ -66,12 +66,12 @@ public void registerParameterGroup(RenderParameterGroup group) { parameters.register(group); } - public void bindToOutput(String target, RenderParameter input) { - parameters.bindToOutput(target, input); + public ParameterBinding bindToOutput(String target, RenderParameter input) { + return parameters.bindToOutput(target, input); } - public void bindToInput(String target, RenderParameter output) { - parameters.bindToInput(target, output); + public ParameterBinding bindToInput(String target, RenderParameter output) { + return parameters.bindToInput(target, output); } public void removeParameter(RenderParameter param) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java index 6511881f4b..e9bf039db1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java @@ -18,12 +18,12 @@ public class ParameterManager { public RenderParameter getParameter(String name, boolean failOnMiss) { for (RenderParameter p : parameters) { - if (p.getParameterName().equals(name)) { + if (p.isPubliclyNamed(name)) { return p; } } if (failOnMiss) { - throw new NullPointerException("Input parameter does not exist: "+name); + throw new NullPointerException("Input parameter \""+name+"\" does not exist or is private."); } return null; } @@ -121,4 +121,8 @@ public void clear() { bindings.clear(); } + public LinkedList getParameterList() { + return parameters; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java index 3e829eed74..97fad0b92e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java @@ -11,6 +11,11 @@ */ public interface RenderParameter { + /** + * When returned as the parameter name, other classes will be unable to access this parameter. + */ + public static final String PRIVATE = null; + /** * Returns the name this parameter is identified by. * @@ -63,4 +68,23 @@ public default T produceOrElse(T value) { } } + /** + * Returns true if this parameter is publicly accessible. + * + * @return + */ + public default boolean isPublic() { + return getParameterName() != null; + } + + /** + * Returns true if this parameter is public and named the given name. + * + * @param name + * @return + */ + public default boolean isPubliclyNamed(String name) { + return isPublic() && getParameterName().equals(name); + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java index a6e1ac0da2..e56a3ab745 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -8,12 +8,11 @@ import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.FGGlobal; -import com.jme3.renderer.framegraph.FrameBufferParam; +import com.jme3.renderer.framegraph.FrameBufferCopyParam; import com.jme3.renderer.framegraph.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.framegraph.RenderParameter; import com.jme3.renderer.framegraph.ValueRenderParam; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; @@ -31,15 +30,15 @@ public class DeferredShadingModule extends ScreenModule { public final static String RT_2 = "Context_InGBuff2"; public final static String RT_3 = "Context_InGBuff3"; public final static String RT_4 = "Context_InGBuff4"; - public final static String LIGHT_DATA = "LIGHT_DATA"; - public final static String EXECUTE_STATE = "EXECUTE_STATE"; - protected final static String S_DEFERRED_PASS = "DeferredPass"; + public final static String LIGHT_DATA = "DeferredShadingPass.LightData"; + public final static String EXECUTE_STATE = "DeferredShadingPass.ExecuteState"; + protected final static String DEFERRED_PASS = "DeferredPass"; private static final String MATDEF = "Common/MatDefs/ShadingCommon/DeferredShading.j3md"; protected MatRenderParam[] matParams = new MatRenderParam[5]; protected ValueRenderParam lightList; protected ValueRenderParam executeState; - protected FrameBufferParam frameBuffer; + protected FrameBufferCopyParam bufferParam; public DeferredShadingModule(AssetManager assetManager) { super(assetManager, RenderQueue.Bucket.Opaque); @@ -49,7 +48,7 @@ public DeferredShadingModule(AssetManager assetManager) { public void initialize(MyFrameGraph frameGraph) { screenMat = createMaterial(); - screenRect = new Picture("DeferredShadingRect"); + screenRect = new Picture("DeferredShadingPass_Rect"); screenRect.setWidth(1); screenRect.setHeight(1); screenRect.setMaterial(screenMat); @@ -62,7 +61,7 @@ public void initialize(MyFrameGraph frameGraph) { matParams[4] = addParameter(new MatRenderParam(RT_4, screenMat, VarType.Texture2D)); lightList = addParameter(new ValueRenderParam<>(LIGHT_DATA)); executeState = addParameter(new ValueRenderParam<>(EXECUTE_STATE)); - frameBuffer = addParameter(new FrameBufferParam(FGGlobal.S_DEFAULT_FB, false, true, true)); + bufferParam = addParameter(new FrameBufferCopyParam(RenderParameter.PRIVATE, null, null, false, true)); bindParameters(frameGraph); } @@ -73,45 +72,44 @@ protected Material createMaterial() { protected void bindParameters(MyFrameGraph frameGraph) { for (int i = 0; i < matParams.length; i++) { - frameGraph.bindToOutput(GBufferPass.RENDER_TARGETS[i], matParams[i]); + frameGraph.bindToOutput(GBufferModule.RENDER_TARGETS[i], matParams[i]); } - frameGraph.bindToOutput(GBufferPass.LIGHT_DATA, lightList); - frameGraph.bindToOutput(GBufferPass.EXECUTE_STATE, executeState); - frameGraph.bindToOutput(GBufferPass.G_FRAME_BUFFER, frameBuffer); + frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); + frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); + frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, bufferParam); } @Override public void prepare(RenderContext context) { super.prepare(context); - ViewPort vp = forcedViewPort; - if (vp == null) { - vp = context.getViewPort(); - } - frameBuffer.accept(vp.getOutputFrameBuffer()); + bufferParam.setRenderer(context.getRenderer()); + bufferParam.setTarget(context.getViewPort().getOutputFrameBuffer()); //executeState.accept(false); //lightList.erase(); } @Override - public void executeDrawCommands(RenderContext renderContext) { - screenMat.selectTechnique(S_DEFERRED_PASS, renderContext.getRenderManager()); - boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite(); - boolean depthTest = screenMat.getAdditionalRenderState().isDepthTest(); + public void executeDrawCommands(RenderContext context) { + + //context.getViewPort().setOutputFrameBuffer(dBuffer); + //context.getRenderer().setFrameBuffer(dBuffer); + //context.getRenderer().setFrameBuffer(null); + screenMat.selectTechnique(DEFERRED_PASS, context.getRenderManager()); screenMat.getAdditionalRenderState().setDepthWrite(false); screenMat.getAdditionalRenderState().setDepthTest(false); screenMat.setBoolean("UseLightsCullMode", false); screenRect.updateGeometricState(); LightList lights = lightList.produce(); - screenMat.render(screenRect, lights, renderContext.getRenderManager()); - screenMat.getAdditionalRenderState().setDepthWrite(depthWrite); - screenMat.getAdditionalRenderState().setDepthTest(depthTest); + screenMat.render(screenRect, lights, context.getRenderManager()); + } @Override public void dispatchPassSetup(RenderQueue queue) { - boolean exState = executeState.validate() && executeState.produce(); - boolean hasLightData = lightList.validate() && lightList.produce().size() > 0; - canExecute = hasLightData || exState; + //boolean exState = executeState.validate() && executeState.produce(); + //boolean hasLightData = lightList.validate() && lightList.produce().size() > 0; + //canExecute = hasLightData || exState; + canExecute = true; } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java index 719fa583e0..5c6efc89aa 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java @@ -28,10 +28,12 @@ public class GBufferModule extends OpaqueModule { 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"; + public final static String[] RENDER_TARGETS = { + "GBufferPass.RT0", "GBufferPass.RT1", "GBufferPass.RT2", "GBufferPass.RT3", "GBufferPass.RT4" + }; + public final static String G_FRAME_BUFFER = "GBufferPass.Framebuffer"; + public final static String LIGHT_DATA = "GBufferPass.LightData"; + public final static String EXECUTE_STATE = "GBufferPass.ExecuteState"; private final LightList lightData = new LightList(null); private final ArrayList tempLights = new ArrayList<>(); @@ -73,6 +75,7 @@ public void executeDrawCommands(RenderContext context) { ColorRGBA opClearColor = vp.getBackgroundColor(); mask.set(opClearColor); mask.a = 0.0f; + FrameBuffer rfb = context.getRenderer().getCurrentFrameBuffer(); context.getRenderer().setFrameBuffer(gBuffer); context.getRenderer().setBackgroundColor(mask); context.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); @@ -82,7 +85,7 @@ public void executeDrawCommands(RenderContext context) { context.getRenderManager().setForcedTechnique(techOrig); vp.setOutputFrameBuffer(opfb); context.getRenderer().setBackgroundColor(opClearColor); - context.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer()); + context.getRenderer().setFrameBuffer(rfb); //bHasDrawVarSource.setValue(bHasDraw); if (hasDraw.produce()) { for(Light light : tempLights){ diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java index 5aad028648..41744a005b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java @@ -29,7 +29,7 @@ protected Material createMaterial() { @Override public void executeDrawCommands(RenderContext context) { - + // Handle FullScreenLights screenMat.selectTechnique(PASS, context.getRenderManager()); boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite(); 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 a8e7b3eb84..3d22923ca1 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -218,4 +218,6 @@ void main(){ gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } + // debug + //gl_FragColor = vec4(1.0); } 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 0fef61733e..613d194673 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 @@ -670,6 +670,7 @@ private void readTechnique(Statement techStat) throws IOException{ technique.setLogic(new DeferredSinglePassLightingLogic(technique)); break; case TileBasedDeferredSinglePass: + System.out.println("assign deferred lighting logic"); technique.setLogic(new TileBasedDeferredSinglePassLightingLogic(technique)); break; case StaticPass: diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index a6e285eb73..e49c6bd230 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -2,7 +2,11 @@ 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; @@ -114,7 +118,7 @@ public void simpleInitApp() { final EnvironmentCamera envCam = new EnvironmentCamera(256, new Vector3f(0, 3f, 0)); stateManager.attach(envCam); - new RenderPathHelper(this); + //new RenderPathHelper(this); flyCam.setMoveSpeed(10.0f); } @@ -123,21 +127,21 @@ 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 == 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); } From 2f008e838709bfeb6259f998cfcb1bb5aeb3105d Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:11:44 -0400 Subject: [PATCH 036/111] deferred and tiled deferred are working for TestShadingModel.java --- .../framegraph/RenderPipelineFactory.java | 4 +- .../framegraph/RenderQueueModule.java | 4 +- .../renderer/pass/DeferredShadingModule.java | 20 ++++--- .../com/jme3/renderer/pass/GBufferModule.java | 54 +++++++++---------- .../com/jme3/renderer/pass/SkyModule.java | 28 ++++++++++ .../ShadingCommon/DeferredShading.frag | 6 ++- .../TileBasedDeferredShading.frag | 4 ++ .../jme3test/renderpath/TestShadingModel.java | 37 +++++++------ 8 files changed, 101 insertions(+), 56 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java index e17b8da472..db5acab844 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java @@ -14,6 +14,7 @@ import com.jme3.renderer.pass.GuiModule; import com.jme3.renderer.pass.OpaqueModule; import com.jme3.renderer.pass.PostProcessingModule; +import com.jme3.renderer.pass.SkyModule; import com.jme3.renderer.pass.TileDeferredShadingModule; /** @@ -36,7 +37,8 @@ public static MyFrameGraph create(Application app, RenderPath path) { private static MyFrameGraph addBasicPasses(MyFrameGraph g) { g.add(new OpaqueModule()); - g.add(ForwardModule.sky()); + //g.add(ForwardModule.sky()); + g.add(new SkyModule()); g.add(ForwardModule.transparent()); g.add(new GuiModule()); g.add(new PostProcessingModule()); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java index e8c3507e06..117efb264a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java @@ -27,9 +27,9 @@ public abstract class RenderQueueModule extends AbstractModule implements Render public void execute(RenderContext context) { context.getRenderManager().setRenderGeometryHandler(this); dispatchPassSetup(context.getRenderQueue()); - if (canExecute) { + //if (canExecute) { executeDrawCommands(context); - } + //} context.getRenderManager().setRenderGeometryHandler(null); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java index e56a3ab745..940f5e594f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -7,6 +7,8 @@ import com.jme3.asset.AssetManager; import com.jme3.light.LightList; import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.math.ColorRGBA; import com.jme3.renderer.RenderManager; import com.jme3.renderer.framegraph.FrameBufferCopyParam; import com.jme3.renderer.framegraph.MatRenderParam; @@ -76,14 +78,14 @@ protected void bindParameters(MyFrameGraph frameGraph) { } frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); - frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, bufferParam); + //frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, bufferParam); } @Override public void prepare(RenderContext context) { super.prepare(context); - bufferParam.setRenderer(context.getRenderer()); - bufferParam.setTarget(context.getViewPort().getOutputFrameBuffer()); + //bufferParam.setRenderer(context.getRenderer()); + //bufferParam.setTarget(context.getViewPort().getOutputFrameBuffer()); //executeState.accept(false); //lightList.erase(); } @@ -93,14 +95,20 @@ public void executeDrawCommands(RenderContext context) { //context.getViewPort().setOutputFrameBuffer(dBuffer); //context.getRenderer().setFrameBuffer(dBuffer); - //context.getRenderer().setFrameBuffer(null); + //context.getRenderer().setFrameBuffer(context.getViewPort().getOutputFrameBuffer()); + //context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); screenMat.selectTechnique(DEFERRED_PASS, context.getRenderManager()); + boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite(); + boolean depthTest = screenMat.getAdditionalRenderState().isDepthTest(); + //screenMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); screenMat.getAdditionalRenderState().setDepthWrite(false); screenMat.getAdditionalRenderState().setDepthTest(false); screenMat.setBoolean("UseLightsCullMode", false); + //screenMat.setTransparent(true); screenRect.updateGeometricState(); - LightList lights = lightList.produce(); - screenMat.render(screenRect, lights, context.getRenderManager()); + screenMat.render(screenRect, lightList.produce(), context.getRenderManager()); + screenMat.getAdditionalRenderState().setDepthWrite(depthWrite); + screenMat.getAdditionalRenderState().setDepthTest(depthTest); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java index 5c6efc89aa..d5b2ca33fc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java @@ -64,35 +64,33 @@ public void prepare(RenderContext context) { @Override public void executeDrawCommands(RenderContext context) { - if(canExecute){ - hasDraw.accept(false); - tempLights.clear(); - lightData.clear(); - ViewPort vp = getViewPort(context); - //reshape(context.getRenderer(), vp.getCamera().getWidth(), vp.getCamera().getHeight()); - FrameBuffer opfb = vp.getOutputFrameBuffer(); - vp.setOutputFrameBuffer(gBuffer); - ColorRGBA opClearColor = vp.getBackgroundColor(); - mask.set(opClearColor); - mask.a = 0.0f; - FrameBuffer rfb = context.getRenderer().getCurrentFrameBuffer(); - context.getRenderer().setFrameBuffer(gBuffer); - context.getRenderer().setBackgroundColor(mask); - context.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); - String techOrig = context.getRenderManager().getForcedTechnique(); - context.getRenderManager().setForcedTechnique(GBUFFER_PASS); - super.executeDrawCommands(context); - context.getRenderManager().setForcedTechnique(techOrig); - vp.setOutputFrameBuffer(opfb); - context.getRenderer().setBackgroundColor(opClearColor); - context.getRenderer().setFrameBuffer(rfb); - //bHasDrawVarSource.setValue(bHasDraw); - if (hasDraw.produce()) { - for(Light light : tempLights){ - lightData.add(light); - } - //context.getRenderer().copyFrameBuffer(gBuffer, vp.getOutputFrameBuffer(), false, true); + hasDraw.accept(false); + tempLights.clear(); + lightData.clear(); + ViewPort vp = getViewPort(context); + //reshape(context.getRenderer(), vp.getCamera().getWidth(), vp.getCamera().getHeight()); + FrameBuffer opfb = vp.getOutputFrameBuffer(); + vp.setOutputFrameBuffer(gBuffer); + ColorRGBA opClearColor = vp.getBackgroundColor(); + mask.set(opClearColor); + mask.a = 0.0f; + FrameBuffer rfb = context.getRenderer().getCurrentFrameBuffer(); + context.getRenderer().setFrameBuffer(gBuffer); + context.getRenderer().setBackgroundColor(mask); + context.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); + String techOrig = context.getRenderManager().getForcedTechnique(); + context.getRenderManager().setForcedTechnique(GBUFFER_PASS); + super.executeDrawCommands(context); + context.getRenderManager().setForcedTechnique(techOrig); + vp.setOutputFrameBuffer(opfb); + context.getRenderer().setBackgroundColor(opClearColor); + context.getRenderer().setFrameBuffer(rfb); + //bHasDrawVarSource.setValue(bHasDraw); + if (hasDraw.produce()) { + for(Light light : tempLights){ + lightData.add(light); } + //context.getRenderer().copyFrameBuffer(gBuffer, vp.getOutputFrameBuffer(), false, true); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java new file mode 100644 index 0000000000..7d1ec74760 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.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.pass; + +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; + +/** + * + * @author codex + */ +public class SkyModule extends ForwardModule { + + public SkyModule() { + super(RenderQueue.Bucket.Sky, new DepthRange(1, 1)); + } + + @Override + public boolean drawGeometry(RenderManager rm, Geometry geom) { + rm.renderGeometry(geom); + return true; + } + +} 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 3d22923ca1..0dab6ba2e3 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -218,6 +218,8 @@ void main(){ gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } - // debug - //gl_FragColor = vec4(1.0); + // added by codex128 + if (shadingInfo.a < 0.5) { + discard; + } } 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 d316ed90e2..a72595b1c6 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag @@ -370,4 +370,8 @@ void main(){ gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } + // added by codex128 + if (shadingInfo.a < 0.5) { + discard; + } } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index e49c6bd230..f7d346df4f 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -8,6 +8,7 @@ import com.jme3.light.DirectionalLight; import com.jme3.light.LightProbe; import com.jme3.material.Material; +import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; @@ -47,16 +48,18 @@ public class TestShadingModel extends SimpleApplication { @Override public void simpleInitApp() { - MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); + MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.TiledDeferred); renderManager.setFrameGraph(graph); Geometry debugView = new Geometry("debug", new Quad(200, 200)); debugView.setLocalTranslation(0, 200, 0); Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); + debugMat.setTransparent(true); debugView.setMaterial(debugMat); MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); //texParam.enableDebug(); - graph.bindToOutput(GBufferModule.RENDER_TARGETS[3], texParam); + graph.bindToOutput(GBufferModule.RENDER_TARGETS[2], texParam); guiNode.attachChild(debugView); // UNLIT @@ -127,21 +130,21 @@ 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 == 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); } From 2f4f92b49542e80bd7a9f246f1fb7b70ac8e4f4d Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 19 Apr 2024 17:38:12 -0400 Subject: [PATCH 037/111] debugging --- .../ShadingCommon/DeferredShading.frag | 6 ++-- .../TestDeferredShadingPathShadow.java | 4 +++ .../TestPBRTerrainAdvancedRenderPath.java | 9 +++--- ...thPointDirectionalAndSpotLightShadows.java | 6 +++- .../jme3test/renderpath/TestShadingModel.java | 2 +- .../TestSimpleDeferredLighting.java | 29 ++++++++++++++++--- 6 files changed, 43 insertions(+), 13 deletions(-) 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 0dab6ba2e3..a9c80d78f2 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -219,7 +219,7 @@ void main(){ gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } // added by codex128 - if (shadingInfo.a < 0.5) { - discard; - } + //if (shadingInfo.a < 0.5) { + // discard; + //} } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java index a22da79b91..76e026cc83 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java @@ -11,6 +11,7 @@ import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.RenderPipelineFactory; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; @@ -36,6 +37,9 @@ private void makeHudText() { @Override public void simpleInitApp() { + + renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); + 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); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java index 66181ff35e..1cafeb1941 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java @@ -40,11 +40,11 @@ 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.Vector3f; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.RenderPipelineFactory; import com.jme3.shader.VarType; import com.jme3.terrain.geomipmap.TerrainLodControl; import com.jme3.terrain.geomipmap.TerrainQuad; @@ -196,7 +196,8 @@ public void onAction(String name, boolean pressed, float tpf) { @Override public void simpleInitApp() { - renderManager.setRenderPath(RenderManager.RenderPath.TiledDeferred); + renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); + //renderManager.setRenderPath(RenderManager.RenderPath.TiledDeferred); setupKeys(); setUpTerrain(); setUpTerrainMaterial(); // <- This method contains the important info about using 'AdvancedPBRTerrain.j3md' @@ -469,7 +470,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); + //flyCam.setEnabled(false); + //inputManager.setCursorVisible(true); } } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java index 71b01573af..6e6908fce1 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java @@ -41,13 +41,14 @@ import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.RenderPipelineFactory; 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 @@ -65,6 +66,9 @@ public static void main(String[] args) { @Override public void simpleInitApp() { + + renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); + // 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); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index f7d346df4f..5d786d799e 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -48,7 +48,7 @@ public class TestShadingModel extends SimpleApplication { @Override public void simpleInitApp() { - MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.TiledDeferred); + MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); renderManager.setFrameGraph(graph); Geometry debugView = new Geometry("debug", new Quad(200, 200)); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 892876658b..744165ba66 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -48,10 +48,15 @@ import com.jme3.input.controls.KeyTrigger; import com.jme3.light.*; import com.jme3.material.Material; +import com.jme3.material.RenderState; import com.jme3.math.*; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.MatRenderParam; +import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.RenderPipelineFactory; +import com.jme3.renderer.pass.GBufferModule; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -60,6 +65,7 @@ import com.jme3.scene.instancing.InstancedGeometry; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; +import com.jme3.shader.VarType; import com.jme3.shadow.DirectionalLightShadowFilter; import com.jme3.system.AppSettings; import com.jme3.texture.Texture; @@ -375,7 +381,7 @@ private void testScene7(){ for (Light light : lightList) { nb++; PointLight p = (PointLight) light; - if (nb > 60) { + if (nb > 20) { n.removeLight(light); } else { int rand = FastMath.nextRandomInt(0, 3); @@ -384,13 +390,13 @@ private void testScene7(){ light.setColor(ColorRGBA.Red); break; case 1: - light.setColor(ColorRGBA.Yellow); + light.setColor(ColorRGBA.Blue); break; case 2: light.setColor(ColorRGBA.Green); break; case 3: - light.setColor(ColorRGBA.Orange); + light.setColor(ColorRGBA.Yellow); break; } } @@ -648,8 +654,23 @@ private void testScene11(){ @Override public void simpleInitApp() { + + MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); + renderManager.setFrameGraph(graph); + + Geometry debugView = new Geometry("debug", new Quad(200, 200)); + debugView.setLocalTranslation(0, 200, 0); + Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + //debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); + //debugMat.setTransparent(true); + debugView.setMaterial(debugMat); + MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); + //texParam.enableDebug(); + graph.bindToOutput(GBufferModule.RENDER_TARGETS[1], texParam); + guiNode.attachChild(debugView); + currentRenderPath = RenderManager.RenderPath.ForwardPlus; - renderManager.setRenderPath(currentRenderPath); + //renderManager.setRenderPath(currentRenderPath); testScene7(); // cam.setFrustumPerspective(45.0f, 4.0f / 3.0f, 0.01f, 100.0f); flyCam.setMoveSpeed(10.0f); From 31445ef1ea15670779a54759f25840dc1ada7bcb Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 20 Apr 2024 13:23:29 -0400 Subject: [PATCH 038/111] debugging deferred pipeline --- .../com/jme3/post/FilterPostProcessor.java | 1 + .../java/com/jme3/renderer/RenderManager.java | 91 +++++-------------- .../main/java/com/jme3/renderer/ViewPort.java | 13 +++ .../renderer/framegraph/AbstractModule.java | 6 ++ .../jme3/renderer/framegraph/DepthRange.java | 2 + .../jme3/renderer/framegraph/FGModule.java | 34 +++++++ .../framegraph/FrameBufferCopyParam.java | 11 ++- .../renderer/framegraph/MyFrameGraph.java | 18 +++- .../renderer/framegraph/RenderContext.java | 48 +++++++++- .../framegraph/RenderPipelineFactory.java | 13 ++- .../com/jme3/renderer/opengl/GLRenderer.java | 1 + .../renderer/pass/DeferredShadingModule.java | 56 +++++++----- .../com/jme3/renderer/pass/ForwardModule.java | 6 +- .../com/jme3/renderer/pass/GBufferModule.java | 36 +++----- .../renderer/pass/PostProcessingModule.java | 70 +++++++++----- .../com/jme3/renderer/pass/SkyModule.java | 2 +- .../ShadingCommon/DeferredShading.frag | 8 +- .../TileBasedDeferredShading.frag | 4 - .../TestDeferredShadingPathShadow.java | 2 +- .../jme3test/renderpath/TestShadingModel.java | 48 ++++++---- 20 files changed, 292 insertions(+), 178 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java index 7da3453b8f..24dbe5df94 100644 --- a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java +++ b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java @@ -261,6 +261,7 @@ private void renderFilterChain(Renderer r, FrameBuffer sceneFb) { boolean msDepth = depthTexture != null && depthTexture.getImage().getMultiSamples() > 1; for (int i = 0; i < filters.size(); i++) { Filter filter = filters.get(i); + System.out.println("render filter: "+filter); if (prof != null) prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName()); if (filter.isEnabled()) { if (filter.getPostRenderPasses() != null) { 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 c78ac0ba27..345764771c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -1370,20 +1370,30 @@ public void renderViewPort(ViewPort vp, float tpf) { if (processors.isEmpty()) { processors = null; } - - if (processors != null) { + + MyFrameGraph fg = vp.getFrameGraph(); + if (fg == null) { + fg = myGraph; + } + + if (fg != null) { + + fg.getContext().update(vp, prof, tpf); + fg.preFrame(); + + } else if (processors != null) { if (prof != null) { prof.vpStep(VpStep.PreFrame, vp, null); } - for (SceneProcessor proc : processors.getArray()) { - if (!proc.isInitialized()) { - proc.initialize(this, vp); + for (SceneProcessor p : processors.getArray()) { + if (!p.isInitialized()) { + p.initialize(this, vp); } - proc.setProfiler(this.prof); + p.setProfiler(this.prof); if (prof != null) { - prof.spStep(SpStep.ProcPreFrame, proc.getClass().getSimpleName()); + prof.spStep(SpStep.ProcPreFrame, p.getClass().getSimpleName()); } - proc.preFrame(tpf); + p.preFrame(tpf); } } @@ -1404,7 +1414,11 @@ public void renderViewPort(ViewPort vp, float tpf) { renderScene(scenes.get(i), vp); } - if (processors != null) { + if (fg != null) { + + fg.postQueue(); + + } else if (processors != null) { if (prof != null) { prof.vpStep(VpStep.PostQueue, vp, null); } @@ -1416,64 +1430,9 @@ public void renderViewPort(ViewPort vp, float tpf) { } } - if (myGraph != null) { - - // to execute the rendering process, simply call execute on the framegraph - myGraph.execute(vp); - - } else if (useFramegraph) { - RenderPath curRenderPath = vp.getRenderPath() == RenderPath.None ? renderPath : vp.getRenderPath(); - - frameGraph.reset(); - frameGraph.getRenderContext().setViewPort(vp); + if (fg != null) { - if (curRenderPath == RenderPath.Deferred) { - frameGraph.addPass(gBufferPass); - 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) { - 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.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); - 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.finalizePasses(); - frameGraph.execute(); + fg.execute(); } else { 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 7fb6a49be4..5f0ea23c69 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java +++ b/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java @@ -33,6 +33,7 @@ import com.jme3.math.ColorRGBA; import com.jme3.post.SceneProcessor; +import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; @@ -84,6 +85,10 @@ public class ViewPort { * Scene processors currently applied. */ protected final SafeArrayList processors = new SafeArrayList<>(SceneProcessor.class); + /** + * Dedicated framegraph. + */ + protected MyFrameGraph framegraph; /** * FrameBuffer for output. */ @@ -438,5 +443,13 @@ public void setEnabled(boolean enable) { public boolean isEnabled() { return enabled; } + + public void setFrameGraph(MyFrameGraph framegraph) { + this.framegraph = framegraph; + } + + public MyFrameGraph getFrameGraph() { + return framegraph; + } } 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 index 33a456e408..bd926cbcd3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java @@ -20,6 +20,12 @@ public Collection getRenderParameters() { return parameters; } + @Override + public void preFrame(RenderContext context) {} + + @Override + public void postQueue(RenderContext context) {} + protected final T addParameter(T p) { parameters.add(p); return p; 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 index 2dc85fd3d5..b77adb5437 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java @@ -11,6 +11,8 @@ public class DepthRange { public static final DepthRange IDENTITY = new DepthRange(); + public static final DepthRange FRONT = new DepthRange(0, 0); + public static final DepthRange REAR = new DepthRange(1, 1); private float start, end; 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 index 5ed5b64ddc..1412712e0a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java @@ -11,12 +11,46 @@ */ public interface FGModule extends RenderParameterGroup { + /** + * Initializes the pass to the framegraph. + *

    + * This is called when the pass is first added to the framegraph. + * + * @param frameGraph + */ public void initialize(T frameGraph); + /** + * Called before the render queue is rendered. + * + * @param context + */ + public void preFrame(RenderContext context); + + /** + * Called after the render queue is rendered. + * + * @param context + */ + public void postQueue(RenderContext context); + + /** + * Prepares the pass for execution. + * + * @param context + */ public void prepare(RenderContext context); + /** + * Executes this pass. + * + * @param context + */ public void execute(RenderContext context); + /** + * Resets the pass after execution. + */ public void reset(); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java index 7c03b8559f..1444ebfd12 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java @@ -17,6 +17,7 @@ public class FrameBufferCopyParam implements RenderParameter { private Renderer renderer; private FrameBuffer target, source; private final boolean copyColor, copyDepth; + private boolean ready = true; public FrameBufferCopyParam(String name, Renderer renderer, FrameBuffer target, boolean copyColor, boolean copyDepth) { this.name = name; @@ -32,12 +33,11 @@ public String getParameterName() { } @Override public void accept(FrameBuffer value) { - if (source != value) { + if (source != value || ready) { source = value; - System.out.println("incoming framebuffer source"); - if (source != null && target != null && renderer != null) { - System.out.println("make buffer copy"); + if ((source != null || target != null) && renderer != null) { renderer.copyFrameBuffer(source, target, copyColor, copyDepth); + ready = false; } } } @@ -52,6 +52,9 @@ public void setRenderer(Renderer renderer) { public void setTarget(FrameBuffer target) { this.target = target; } + public void setReady(boolean ready) { + this.ready = ready; + } public FrameBuffer getSource() { return source; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java index 902a09650e..510ea0fc8f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java @@ -22,8 +22,20 @@ public MyFrameGraph(RenderManager renderManager) { context = new RenderContext(renderManager); } - public void execute(ViewPort vp) { - context.setViewPort(vp); + public void preFrame() { + for (FGModule p : passes) { + p.preFrame(context); + } + } + + public void postQueue() { + for (FGModule p : passes) { + p.postQueue(context); + } + } + + public void execute() { + System.out.println("start framegraph execution"); // prepare passes for execution for (FGModule p : passes) { p.prepare(context); @@ -41,6 +53,8 @@ public void execute(ViewPort vp) { for (FGModule p : passes) { p.reset(); } + context.getRenderManager().setRenderGeometryHandler(null); + System.out.println("end framegraph execution"); } public void add(FGModule pass) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java index bbe83516c5..b39a331b47 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java @@ -31,6 +31,8 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.profile.AppProfiler; +import com.jme3.renderer.Camera; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; @@ -44,16 +46,34 @@ public class RenderContext { private final RenderManager renderManager; private ViewPort viewPort; + private AppProfiler profiler; private final DepthRange depth = new DepthRange(); + private float tpf; + private int width, height; + private boolean sizeChanged = false; public RenderContext(RenderManager renderManager, ViewPort viewPort) { this.renderManager = renderManager; this.viewPort = viewPort; + width = height = -1; } public RenderContext(RenderManager renderManager) { this(renderManager, null); } + public void update(ViewPort vp, AppProfiler profiler, float tpf) { + this.viewPort = vp; + this.profiler = profiler; + this.tpf = tpf; + if (viewPort == null) { + throw new NullPointerException("ViewPort cannot be null."); + } + Camera cam = viewPort.getCamera(); + sizeChanged = width != cam.getWidth() || height != cam.getHeight(); + width = cam.getWidth(); + height = cam.getHeight(); + } + public void setDepthRange(float start, float end) { if (!depth.equals(start, end)) { depth.set(start, end); @@ -67,10 +87,6 @@ public void setDepthRange(DepthRange depth) { } } - public void setViewPort(ViewPort viewPort) { - this.viewPort = viewPort; - } - public RenderManager getRenderManager() { return renderManager; } @@ -79,6 +95,14 @@ public ViewPort getViewPort() { return viewPort; } + public AppProfiler getProfiler() { + return profiler; + } + + public float getTpf() { + return tpf; + } + public Renderer getRenderer() { return renderManager.getRenderer(); } @@ -91,4 +115,20 @@ public RenderQueue getRenderQueue() { } } + public boolean isProfilerAvailable() { + return profiler != null; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public boolean isSizeChanged() { + return sizeChanged; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java index db5acab844..c478ceb019 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java @@ -36,9 +36,8 @@ public static MyFrameGraph create(Application app, RenderPath path) { } private static MyFrameGraph addBasicPasses(MyFrameGraph g) { - g.add(new OpaqueModule()); - //g.add(ForwardModule.sky()); - g.add(new SkyModule()); + g.add(ForwardModule.opaque()); + g.add(ForwardModule.sky()); g.add(ForwardModule.transparent()); g.add(new GuiModule()); g.add(new PostProcessingModule()); @@ -58,7 +57,13 @@ public static MyFrameGraph createDeferredPipeline(AssetManager am, RenderManager MyFrameGraph g = new MyFrameGraph(rm); g.add(new GBufferModule()); g.add(new DeferredShadingModule(am)); - return addBasicPasses(g); + //g.add(ForwardModule.opaque()); + g.add(ForwardModule.sky()); + g.add(ForwardModule.transparent()); + g.add(new GuiModule()); + //g.add(new PostProcessingModule()); + //g.add(ForwardModule.translucent()); + return g; } public static MyFrameGraph createTileDeferredPipeline(AssetManager am, RenderManager rm) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 60e6b30265..39131b820a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -1831,6 +1831,7 @@ public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyColor, src = mainFbOverride; } if (dst == null) { + System.out.println("assign mainfpOverride to destination framebuffer"); dst = mainFbOverride; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java index 940f5e594f..77af39c685 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -10,15 +10,16 @@ import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.FrameBufferCopyParam; import com.jme3.renderer.framegraph.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.RenderParameter; +import com.jme3.renderer.framegraph.TextureTargetParam; import com.jme3.renderer.framegraph.ValueRenderParam; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.shader.VarType; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; /** @@ -34,13 +35,17 @@ public class DeferredShadingModule extends ScreenModule { public final static String RT_4 = "Context_InGBuff4"; public final static String LIGHT_DATA = "DeferredShadingPass.LightData"; public final static String EXECUTE_STATE = "DeferredShadingPass.ExecuteState"; + public final static String IN_FRAME_BUFFER = "DeferredShadingPass.InFrameBuffer"; + public final static String DEPTH_DEBUG = "DeferredShadingPass.DepthDebug"; protected final static String DEFERRED_PASS = "DeferredPass"; private static final String MATDEF = "Common/MatDefs/ShadingCommon/DeferredShading.j3md"; protected MatRenderParam[] matParams = new MatRenderParam[5]; protected ValueRenderParam lightList; protected ValueRenderParam executeState; - protected FrameBufferCopyParam bufferParam; + protected ValueRenderParam gBuffer; + private FrameBuffer debug; + private TextureTargetParam depthCopy; public DeferredShadingModule(AssetManager assetManager) { super(assetManager, RenderQueue.Bucket.Opaque); @@ -55,6 +60,13 @@ public void initialize(MyFrameGraph frameGraph) { screenRect.setHeight(1); screenRect.setMaterial(screenMat); + RenderState rs = screenMat.getAdditionalRenderState(); + rs.setDepthWrite(false); + rs.setDepthTest(false); + //rs.setBlendMode(RenderState.BlendMode.Alpha); + //screenMat.setTransparent(true); + screenMat.setBoolean("UseLightsCullMode", false); + // material render parameters automatically apply their values matParams[0] = addParameter(new MatRenderParam(RT_0, screenMat, VarType.Texture2D)); matParams[1] = addParameter(new MatRenderParam(RT_1, screenMat, VarType.Texture2D)); @@ -63,7 +75,10 @@ public void initialize(MyFrameGraph frameGraph) { matParams[4] = addParameter(new MatRenderParam(RT_4, screenMat, VarType.Texture2D)); lightList = addParameter(new ValueRenderParam<>(LIGHT_DATA)); executeState = addParameter(new ValueRenderParam<>(EXECUTE_STATE)); - bufferParam = addParameter(new FrameBufferCopyParam(RenderParameter.PRIVATE, null, null, false, true)); + gBuffer = addParameter(new ValueRenderParam<>(IN_FRAME_BUFFER)); + + depthCopy = addParameter(new TextureTargetParam(DEPTH_DEBUG, null)); + bindParameters(frameGraph); } @@ -78,37 +93,34 @@ protected void bindParameters(MyFrameGraph frameGraph) { } frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); - //frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, bufferParam); + frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, gBuffer); } @Override public void prepare(RenderContext context) { super.prepare(context); - //bufferParam.setRenderer(context.getRenderer()); - //bufferParam.setTarget(context.getViewPort().getOutputFrameBuffer()); - //executeState.accept(false); - //lightList.erase(); + if (debug == null) { + debug = new FrameBuffer(context.getWidth(), context.getHeight(), 1); + FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget( + new Texture2D(context.getWidth(), context.getHeight(), GBufferModule.DEPTH_FORMAT)); + debug.setDepthTarget(t); + depthCopy.setTextureTarget(t); + } } @Override public void executeDrawCommands(RenderContext context) { - //context.getViewPort().setOutputFrameBuffer(dBuffer); - //context.getRenderer().setFrameBuffer(dBuffer); - //context.getRenderer().setFrameBuffer(context.getViewPort().getOutputFrameBuffer()); - //context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); + context.getRenderer().copyFrameBuffer(gBuffer.produce(), + context.getViewPort().getOutputFrameBuffer(), false, true); + + System.out.println("render deferred lighting"); + context.getRenderer().copyFrameBuffer(gBuffer.produce(), debug, false, true); + + context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); screenMat.selectTechnique(DEFERRED_PASS, context.getRenderManager()); - boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite(); - boolean depthTest = screenMat.getAdditionalRenderState().isDepthTest(); - //screenMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); - screenMat.getAdditionalRenderState().setDepthWrite(false); - screenMat.getAdditionalRenderState().setDepthTest(false); - screenMat.setBoolean("UseLightsCullMode", false); - //screenMat.setTransparent(true); screenRect.updateGeometricState(); screenMat.render(screenRect, lightList.produce(), context.getRenderManager()); - screenMat.getAdditionalRenderState().setDepthWrite(depthWrite); - screenMat.getAdditionalRenderState().setDepthTest(depthTest); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java index 2f9d13a387..1b3506ff2d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java @@ -36,11 +36,12 @@ public void dispatchPassSetup(RenderQueue queue) { @Override public void executeDrawCommands(RenderContext context) { if (!canExecute) { - return; + //return; } if (depth != null) { context.setDepthRange(depth); } + System.out.println("render queue (forward): "+bucket.name()); context.getRenderQueue().renderQueue(bucket, context.getRenderManager(), context.getViewPort().getCamera(), true); } @Override @@ -53,6 +54,9 @@ public boolean drawGeometry(RenderManager rm, Geometry geom) { return true; } + public static ForwardModule opaque() { + return new ForwardModule(RenderQueue.Bucket.Opaque, DepthRange.IDENTITY); + } public static ForwardModule sky() { return new ForwardModule(RenderQueue.Bucket.Sky, new DepthRange(1, 1)); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java index d5b2ca33fc..9f1d602175 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java @@ -34,6 +34,7 @@ public class GBufferModule extends OpaqueModule { public final static String G_FRAME_BUFFER = "GBufferPass.Framebuffer"; public final static String LIGHT_DATA = "GBufferPass.LightData"; public final static String EXECUTE_STATE = "GBufferPass.ExecuteState"; + public final static Image.Format DEPTH_FORMAT = Image.Format.Depth; private final LightList lightData = new LightList(null); private final ArrayList tempLights = new ArrayList<>(); @@ -64,33 +65,18 @@ public void prepare(RenderContext context) { @Override public void executeDrawCommands(RenderContext context) { - hasDraw.accept(false); - tempLights.clear(); - lightData.clear(); ViewPort vp = getViewPort(context); - //reshape(context.getRenderer(), vp.getCamera().getWidth(), vp.getCamera().getHeight()); - FrameBuffer opfb = vp.getOutputFrameBuffer(); - vp.setOutputFrameBuffer(gBuffer); - ColorRGBA opClearColor = vp.getBackgroundColor(); - mask.set(opClearColor); - mask.a = 0.0f; - FrameBuffer rfb = context.getRenderer().getCurrentFrameBuffer(); + String tempFT = context.getRenderManager().getForcedTechnique(); context.getRenderer().setFrameBuffer(gBuffer); - context.getRenderer().setBackgroundColor(mask); + context.getRenderer().setBackgroundColor(mask.set(vp.getBackgroundColor()).setAlpha(0)); context.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); - String techOrig = context.getRenderManager().getForcedTechnique(); context.getRenderManager().setForcedTechnique(GBUFFER_PASS); super.executeDrawCommands(context); - context.getRenderManager().setForcedTechnique(techOrig); - vp.setOutputFrameBuffer(opfb); - context.getRenderer().setBackgroundColor(opClearColor); - context.getRenderer().setFrameBuffer(rfb); - //bHasDrawVarSource.setValue(bHasDraw); - if (hasDraw.produce()) { - for(Light light : tempLights){ - lightData.add(light); - } - //context.getRenderer().copyFrameBuffer(gBuffer, vp.getOutputFrameBuffer(), false, true); + context.getRenderManager().setForcedTechnique(tempFT); + context.getRenderer().setBackgroundColor(vp.getBackgroundColor()); + context.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer()); + for(Light light : tempLights){ + lightData.add(light); } } @@ -111,7 +97,7 @@ public boolean drawGeometry(RenderManager rm, Geometry geom) { } // Whether it has lights or not, material objects containing GBufferPass will perform // DeferredShading, and shade according to shadingModelId - hasDraw.accept(true); + //hasDraw.accept(true); return true; } } @@ -123,7 +109,7 @@ public void reset() { super.reset(); tempLights.clear(); lightData.clear(); - hasDraw.accept(false); + //hasDraw.accept(false); } protected void reshape(Renderer renderer, int w, int h) { @@ -146,7 +132,7 @@ protected void reshape(Renderer renderer, int w, int h) { textures[3] = new Texture2D(w, h, Image.Format.RGBA32F); // 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. - textures[4] = new Texture2D(w, h, Image.Format.Depth); + textures[4] = new Texture2D(w, h, DEPTH_FORMAT); //gBuffer.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(Image.Format.RGBA8)); //for (int i = 0; i < textures.length; i++) { // FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget(textures[i]); diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java index bdbeffc502..04765f04ed 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java @@ -21,48 +21,70 @@ */ public class PostProcessingModule extends AbstractModule { - private AppProfiler profiler; - - public PostProcessingModule() { - this(null); - } - public PostProcessingModule(AppProfiler profiler) { - this.profiler = profiler; - } - @Override public void initialize(MyFrameGraph frameGraph) {} @Override + public void preFrame(RenderContext context) { + ViewPort vp = context.getViewPort(); + SafeArrayList processors = vp.getProcessors(); + AppProfiler prof = context.getProfiler(); + if (processors != null && !processors.isEmpty()) { + if (prof != null) { + prof.vpStep(VpStep.PreFrame, vp, null); + } + for (SceneProcessor p : processors.getArray()) { + if (!p.isInitialized()) { + p.initialize(context.getRenderManager(), vp); + } + p.setProfiler(context.getProfiler()); + if (prof != null) { + prof.spStep(SpStep.ProcPreFrame, p.getClass().getSimpleName()); + } + p.preFrame(context.getTpf()); + } + } + } + @Override + public void postQueue(RenderContext context) { + ViewPort vp = context.getViewPort(); + SafeArrayList processors = vp.getProcessors(); + AppProfiler prof = context.getProfiler(); + if (processors != null && !processors.isEmpty()) { + 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()); + } + } + } + @Override public void prepare(RenderContext context) {} @Override public void execute(RenderContext context) { context.setDepthRange(DepthRange.IDENTITY); ViewPort vp = context.getViewPort(); SafeArrayList processors = vp.getProcessors(); - if (processors != null) { - if (profiler != null) { - profiler.vpStep(VpStep.PostFrame, vp, null); + AppProfiler prof = context.getProfiler(); + if (processors != null && !processors.isEmpty()) { + if (prof != null) { + prof.vpStep(VpStep.PostFrame, vp, null); } for (SceneProcessor p : processors.getArray()) { - if (profiler != null) { - profiler.spStep(SpStep.ProcPostFrame, p.getClass().getSimpleName()); + if (prof != null) { + prof.spStep(SpStep.ProcPostFrame, p.getClass().getSimpleName()); } p.postFrame(vp.getOutputFrameBuffer()); } - if (profiler != null) { - profiler.vpStep(VpStep.ProcEndRender, vp, null); + if (prof != null) { + prof.vpStep(VpStep.ProcEndRender, vp, null); } } } @Override public void reset() {} - public void setProfiler(AppProfiler profiler) { - this.profiler = profiler; - } - - public AppProfiler getProfiler() { - return profiler; - } - } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java index 7d1ec74760..8dec8325c1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java @@ -16,7 +16,7 @@ public class SkyModule extends ForwardModule { public SkyModule() { - super(RenderQueue.Bucket.Sky, new DepthRange(1, 1)); + super(RenderQueue.Bucket.Sky, DepthRange.REAR); } @Override 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 a9c80d78f2..12399f76dc 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -218,8 +218,8 @@ void main(){ gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } - // added by codex128 - //if (shadingInfo.a < 0.5) { - // discard; - //} + if (innerTexCoord.y > 0.5) { + //discard; + } + //gl_FragColor.a = 0.5; } 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 a72595b1c6..d316ed90e2 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag @@ -370,8 +370,4 @@ void main(){ gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } - // added by codex128 - if (shadingInfo.a < 0.5) { - discard; - } } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java index 76e026cc83..6846e3e616 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java @@ -38,7 +38,7 @@ private void makeHudText() { @Override public void simpleInitApp() { - renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); + renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Forward)); Material boxMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index 5d786d799e..c9ba743e7e 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -2,29 +2,28 @@ 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.EnvironmentProbeControl; +import com.jme3.light.AmbientLight; import com.jme3.light.DirectionalLight; -import com.jme3.light.LightProbe; import com.jme3.material.Material; import com.jme3.material.RenderState; 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.renderer.framegraph.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderPipelineFactory; -import com.jme3.renderer.pass.GBufferModule; +import com.jme3.renderer.pass.DeferredShadingModule; +import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; import com.jme3.shader.VarType; +import com.jme3.shadow.DirectionalLightShadowRenderer; import com.jme3.texture.plugins.ktx.KTXLoader; import com.jme3.util.SkyFactory; import com.jme3.util.TangentBinormalGenerator; @@ -51,25 +50,31 @@ public void simpleInitApp() { MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); renderManager.setFrameGraph(graph); - Geometry debugView = new Geometry("debug", new Quad(200, 200)); + Geometry debugView = new Geometry("debug", new Quad(150, 150)); debugView.setLocalTranslation(0, 200, 0); Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); - debugMat.setTransparent(true); + //debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); + //debugMat.setTransparent(true); debugView.setMaterial(debugMat); MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); //texParam.enableDebug(); - graph.bindToOutput(GBufferModule.RENDER_TARGETS[2], texParam); + graph.bindToOutput(DeferredShadingModule.DEPTH_DEBUG, texParam); guiNode.attachChild(debugView); // UNLIT Material unlitMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); unlitMat.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg")); + //unlitMat.setColor("Color", new ColorRGBA(0, 0, 1, .5f)); + //unlitMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); + //unlitMat.getAdditionalRenderState().setDepthWrite(false); + //unlitMat.getAdditionalRenderState().setDepthTest(false); + unlitMat.setTransparent(true); 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); + unlitSphere.setQueueBucket(RenderQueue.Bucket.Transparent); rootNode.attachChild(unlitSphere); // LEGACY_LIGHTING @@ -78,6 +83,7 @@ public void simpleInitApp() { Material lightMat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); lightSphere.setLocalTranslation(5, 0, 0); lightSphere.setMaterial(lightMat); + lightSphere.setQueueBucket(RenderQueue.Bucket.Inherit); rootNode.attachChild(lightSphere); // STANDARD_LIGHTING @@ -96,6 +102,9 @@ public void simpleInitApp() { dl.setColor(ColorRGBA.White); modelNode.setLocalScale(0.3f); rootNode.attachChild(modelNode); + + AmbientLight al = new AmbientLight(ColorRGBA.White.mult(0.1f)); + rootNode.addLight(al); FilterPostProcessor fpp = new FilterPostProcessor(assetManager); int numSamples = context.getSettings().getSamples(); @@ -104,15 +113,20 @@ public void simpleInitApp() { } // fpp.addFilter(new FXAAFilter()); - fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(1.0f))); + //fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(1.0f))); // fpp.addFilter(new SSAOFilter(0.5f, 3, 0.2f, 0.2f)); - viewPort.addProcessor(fpp); + //viewPort.addProcessor(fpp); + + DirectionalLightShadowRenderer dr = new DirectionalLightShadowRenderer(assetManager, 1024, 2); + dr.setLight(dl); + viewPort.addProcessor(dr); //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); + EnvironmentProbeControl.tagGlobal(sky); pbrMat = assetManager.loadMaterial("Models/Tank/tank.j3m"); model.setMaterial(pbrMat); @@ -130,7 +144,7 @@ public void simpleRender(RenderManager rm) { super.simpleRender(rm); frame++; -// if (frame == 2) { + if (frame == 2) { // modelNode.removeFromParent(); // final LightProbe probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, new JobProgressAdapter() { // @@ -142,9 +156,11 @@ public void simpleRender(RenderManager rm) { // }); // probe.getArea().setRadius(100); // rootNode.addLight(probe); -// //getStateManager().getState(EnvironmentManager.class).addEnvProbe(probe); -// -// } + //getStateManager().getState(EnvironmentManager.class).addEnvProbe(probe); + + rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); + + } if (frame > 10 && modelNode.getParent() == null) { rootNode.attachChild(modelNode); } From dfd386638f708551e40ac1d4bc463263e54a8023 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 20 Apr 2024 22:10:57 -0400 Subject: [PATCH 039/111] more debugging --- .../java/com/jme3/renderer/RenderManager.java | 8 ++- .../renderer/framegraph/MyFrameGraph.java | 2 - .../framegraph/RenderPipelineFactory.java | 20 +++++-- .../pass/BackgroundScreenTestModule.java | 60 +++++++++++++++++++ .../renderer/pass/DeferredShadingModule.java | 3 +- .../resources/Common/MatDefs/Misc/Screen.frag | 21 +++++++ .../resources/Common/MatDefs/Misc/Screen.j3md | 18 ++++++ .../resources/Common/MatDefs/Misc/Screen.vert | 13 ++++ .../ShadingCommon/DeferredShading.frag | 5 +- .../jme3test/renderpath/TestShadingModel.java | 22 ++----- 10 files changed, 142 insertions(+), 30 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/BackgroundScreenTestModule.java create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.frag create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.j3md create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.vert 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 345764771c..749125c5b3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -41,6 +41,7 @@ import com.jme3.material.Technique; import com.jme3.material.TechniqueDef; import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic; +import com.jme3.math.ColorRGBA; import com.jme3.math.Matrix4f; import com.jme3.post.SceneProcessor; import com.jme3.profile.AppProfiler; @@ -109,7 +110,7 @@ public class RenderManager { private TranslucentPass translucentPass; private GuiPass guiPass; private PostProcessorPass postProcessorPass; - private MyFrameGraph myGraph; + private MyFrameGraph myFrameGraph; // frameGraph=============================================================================↑ // RenderPath @@ -226,7 +227,7 @@ public final void enableFramegraph(boolean useFramegraph){ * @param frameGraph */ public void setFrameGraph(MyFrameGraph frameGraph) { - this.myGraph = frameGraph; + this.myFrameGraph = frameGraph; } /** @@ -1373,7 +1374,7 @@ public void renderViewPort(ViewPort vp, float tpf) { MyFrameGraph fg = vp.getFrameGraph(); if (fg == null) { - fg = myGraph; + fg = myFrameGraph; } if (fg != null) { @@ -1409,6 +1410,7 @@ public void renderViewPort(ViewPort vp, float tpf) { if (prof != null) { prof.vpStep(VpStep.RenderScene, vp, null); } + // flatten scenes into render queue List scenes = vp.getScenes(); for (int i = scenes.size() - 1; i >= 0; i--) { renderScene(scenes.get(i), vp); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java index 510ea0fc8f..498d80bfde 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java @@ -35,7 +35,6 @@ public void postQueue() { } public void execute() { - System.out.println("start framegraph execution"); // prepare passes for execution for (FGModule p : passes) { p.prepare(context); @@ -54,7 +53,6 @@ public void execute() { p.reset(); } context.getRenderManager().setRenderGeometryHandler(null); - System.out.println("end framegraph execution"); } public void add(FGModule pass) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java index c478ceb019..886926d5c0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java @@ -8,13 +8,12 @@ import com.jme3.asset.AssetManager; import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager.RenderPath; +import com.jme3.renderer.pass.BackgroundScreenTestModule; import com.jme3.renderer.pass.DeferredShadingModule; import com.jme3.renderer.pass.ForwardModule; import com.jme3.renderer.pass.GBufferModule; import com.jme3.renderer.pass.GuiModule; -import com.jme3.renderer.pass.OpaqueModule; import com.jme3.renderer.pass.PostProcessingModule; -import com.jme3.renderer.pass.SkyModule; import com.jme3.renderer.pass.TileDeferredShadingModule; /** @@ -57,12 +56,11 @@ public static MyFrameGraph createDeferredPipeline(AssetManager am, RenderManager MyFrameGraph g = new MyFrameGraph(rm); g.add(new GBufferModule()); g.add(new DeferredShadingModule(am)); - //g.add(ForwardModule.opaque()); g.add(ForwardModule.sky()); g.add(ForwardModule.transparent()); g.add(new GuiModule()); - //g.add(new PostProcessingModule()); - //g.add(ForwardModule.translucent()); + g.add(new PostProcessingModule()); + g.add(ForwardModule.translucent()); return g; } @@ -73,4 +71,16 @@ public static MyFrameGraph createTileDeferredPipeline(AssetManager am, RenderMan return addBasicPasses(g); } + public static MyFrameGraph createBackroundScreenTest(AssetManager am, RenderManager rm) { + MyFrameGraph g = new MyFrameGraph(rm); + g.add(new BackgroundScreenTestModule(am)); + g.add(ForwardModule.opaque()); + g.add(ForwardModule.sky()); + g.add(ForwardModule.transparent()); + g.add(new GuiModule()); + g.add(new PostProcessingModule()); + g.add(ForwardModule.translucent()); + return g; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/BackgroundScreenTestModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/BackgroundScreenTestModule.java new file mode 100644 index 0000000000..7de42ac0da --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/BackgroundScreenTestModule.java @@ -0,0 +1,60 @@ +/* + * 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.pass; + +import com.jme3.asset.AssetManager; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.renderer.framegraph.AbstractModule; +import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.texture.Texture2D; +import com.jme3.ui.Picture; + +/** + * + * @author codex + */ +public class BackgroundScreenTestModule extends AbstractModule { + + private final AssetManager assetManager; + private Picture screen; + + public BackgroundScreenTestModule(AssetManager assetManager) { + this.assetManager = assetManager; + } + + @Override + public void initialize(MyFrameGraph frameGraph) { + + screen = new Picture("TestScreen"); + screen.setWidth(1f); + screen.setHeight(1f); + + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Screen.j3md"); + mat.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg")); + screen.setMaterial(mat); + + RenderState rs = screen.getMaterial().getAdditionalRenderState(); + rs.setDepthTest(!true); + rs.setDepthWrite(!true); + //rs.setDepthFunc(RenderState.TestFunction.Less); + + } + @Override + public void prepare(RenderContext context) {} + @Override + public void execute(RenderContext context) { + + //context.setDepthRange(1, 1); + screen.updateGeometricState(); + screen.getMaterial().render(screen, screen.getLocalLightList(), context.getRenderManager()); + //context.getRenderer().clearBuffers(false, true, false); + + } + @Override + public void reset() {} + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java index 77af39c685..94ca4af029 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -110,13 +110,14 @@ public void prepare(RenderContext context) { @Override public void executeDrawCommands(RenderContext context) { - + context.getRenderer().copyFrameBuffer(gBuffer.produce(), context.getViewPort().getOutputFrameBuffer(), false, true); System.out.println("render deferred lighting"); context.getRenderer().copyFrameBuffer(gBuffer.produce(), debug, false, true); + //context.setDepthRange(1, 1); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); screenMat.selectTechnique(DEFERRED_PASS, context.getRenderManager()); screenRect.updateGeometricState(); diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.frag b/jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.frag new file mode 100644 index 0000000000..5740c7370a --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.frag @@ -0,0 +1,21 @@ + +#import "Common/ShaderLib/GLSLCompat.glsllib" + +#ifdef MAP + uniform sampler2D m_ColorMap; +#else + uniform vec4 m_Color; +#endif + +varying vec2 texCoord; + +void main(){ + if (texCoord.y > 0.5) { + discard; + } + #ifdef MAP + gl_FragColor = texture2D(m_ColorMap, texCoord); + #else + gl_FragColor = m_Color; + #endif +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.j3md new file mode 100644 index 0000000000..51ffe4907d --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.j3md @@ -0,0 +1,18 @@ +MaterialDef Screen { + + MaterialParameters { + Texture2D ColorMap + Color Color : 1.0 1.0 1.0 1.0 + } + + Technique { + VertexShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Misc/Screen.vert + FragmentShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Misc/Screen.frag + WorldParameters { + } + Defines { + MAP : ColorMap + } + } + +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.vert b/jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.vert new file mode 100644 index 0000000000..6bc2540dae --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Screen.vert @@ -0,0 +1,13 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" + +attribute vec3 inPosition; +attribute vec2 inTexCoord; + +varying vec2 texCoord; + +void main(){ + + texCoord = inTexCoord; + gl_Position = vec4(sign(inPosition.xy-vec2(0.5)), 0.0, 1.0); + +} 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 12399f76dc..7d5eaec6a3 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -218,8 +218,9 @@ void main(){ gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } - if (innerTexCoord.y > 0.5) { + //if (innerTexCoord.y > 0.5) { //discard; - } + //} + //discard; //gl_FragColor.a = 0.5; } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index c9ba743e7e..7693d543b6 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -25,6 +25,7 @@ import com.jme3.shader.VarType; import com.jme3.shadow.DirectionalLightShadowRenderer; import com.jme3.texture.plugins.ktx.KTXLoader; +import com.jme3.ui.Picture; import com.jme3.util.SkyFactory; import com.jme3.util.TangentBinormalGenerator; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; @@ -48,8 +49,12 @@ public class TestShadingModel extends SimpleApplication { public void simpleInitApp() { MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); + //MyFrameGraph graph = RenderPipelineFactory.createBackroundScreenTest(assetManager, renderManager); renderManager.setFrameGraph(graph); + viewPort.setBackgroundColor(ColorRGBA.Green.mult(0.2f)); + //viewPort.setBackgroundColor(ColorRGBA.White); + Geometry debugView = new Geometry("debug", new Quad(150, 150)); debugView.setLocalTranslation(0, 200, 0); Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); @@ -90,7 +95,6 @@ public void simpleInitApp() { 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); @@ -131,10 +135,6 @@ public void simpleInitApp() { 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); } @@ -145,18 +145,6 @@ public void simpleRender(RenderManager 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); rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); From 097309de6bb5cb73e9e4d5820c6f695271de7df8 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sun, 21 Apr 2024 07:16:30 -0400 Subject: [PATCH 040/111] more debugging --- .../com/jme3/renderer/pass/DeferredShadingModule.java | 11 ++++++----- .../java/com/jme3/renderer/pass/ForwardModule.java | 1 - .../java/jme3test/renderpath/TestShadingModel.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java index 94ca4af029..fbece1016f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -61,8 +61,9 @@ public void initialize(MyFrameGraph frameGraph) { screenRect.setMaterial(screenMat); RenderState rs = screenMat.getAdditionalRenderState(); - rs.setDepthWrite(false); - rs.setDepthTest(false); + rs.setDepthWrite(true); + rs.setDepthTest(true); + rs.setDepthFunc(RenderState.TestFunction.Greater); //rs.setBlendMode(RenderState.BlendMode.Alpha); //screenMat.setTransparent(true); screenMat.setBoolean("UseLightsCullMode", false); @@ -114,14 +115,14 @@ public void executeDrawCommands(RenderContext context) { context.getRenderer().copyFrameBuffer(gBuffer.produce(), context.getViewPort().getOutputFrameBuffer(), false, true); - System.out.println("render deferred lighting"); context.getRenderer().copyFrameBuffer(gBuffer.produce(), debug, false, true); - //context.setDepthRange(1, 1); + context.setDepthRange(1, 1); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); screenMat.selectTechnique(DEFERRED_PASS, context.getRenderManager()); screenRect.updateGeometricState(); - screenMat.render(screenRect, lightList.produce(), context.getRenderManager()); + context.getRenderManager().renderGeometry(screenRect); + //screenMat.render(screenRect, lightList.produce(), context.getRenderManager()); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java index 1b3506ff2d..11a283a1f0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java @@ -41,7 +41,6 @@ public void executeDrawCommands(RenderContext context) { if (depth != null) { context.setDepthRange(depth); } - System.out.println("render queue (forward): "+bucket.name()); context.getRenderQueue().renderQueue(bucket, context.getRenderManager(), context.getViewPort().getCamera(), true); } @Override diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index 7693d543b6..ca3460bd21 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -64,7 +64,7 @@ public void simpleInitApp() { MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); //texParam.enableDebug(); graph.bindToOutput(DeferredShadingModule.DEPTH_DEBUG, texParam); - guiNode.attachChild(debugView); + //guiNode.attachChild(debugView); // UNLIT Material unlitMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); From 7d14e6846107480e47d91e13602177c8eb93139d Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:04:27 -0400 Subject: [PATCH 041/111] cleanup code --- .../DeferredSinglePassLightingLogic.java | 258 +++++++++--------- .../java/com/jme3/renderer/RenderManager.java | 115 +++----- .../framegraph/FGRenderQueuePass.java | 10 +- .../jme3/renderer/framegraph/FrameGraph.java | 2 +- .../renderer/framegraph/MyFrameGraph.java | 6 +- .../framegraph/RenderQueueModule.java | 8 +- .../renderer/pass/DeferredShadingModule.java | 56 ++-- .../renderer/pass/DeferredShadingPass.java | 2 +- .../com/jme3/renderer/pass/ForwardModule.java | 25 +- .../com/jme3/renderer/pass/ForwardPass.java | 2 +- .../com/jme3/renderer/pass/GBufferModule.java | 40 ++- .../com/jme3/renderer/pass/GBufferPass.java | 2 +- ...ometry.java => GeometryRenderHandler.java} | 4 +- .../com/jme3/renderer/pass/GuiModule.java | 23 +- .../com/jme3/renderer/pass/OpaqueModule.java | 28 -- .../renderer/pass/ResolveSceneColorPass.java | 2 +- .../com/jme3/renderer/pass/ScreenModule.java | 31 --- .../com/jme3/renderer/pass/SkyModule.java | 28 -- .../pass/TileDeferredShadingModule.java | 2 +- .../com/jme3/renderer/queue/RenderQueue.java | 62 ++--- .../ShadingCommon/DeferredShading.frag | 1 + .../Common/MatDefs/Post/DepthDebug.frag | 15 + .../Common/MatDefs/Post/DepthDebug.j3md | 22 ++ .../jme3test/renderpath/TestShadingModel.java | 26 +- 24 files changed, 324 insertions(+), 446 deletions(-) rename jme3-core/src/main/java/com/jme3/renderer/pass/{RenderGeometry.java => GeometryRenderHandler.java} (94%) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/OpaqueModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/ScreenModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/DepthDebug.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/DepthDebug.j3md 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 ce3b10db3e..a031c1c60a 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 @@ -74,7 +74,8 @@ * @author JohnKkk */ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLogic { - private final static String _S_LIGHT_CULL_DRAW_STAGE = "Light_Cull_Draw_Stage"; + + private final static String 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"; @@ -82,21 +83,14 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo 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; - // Avoid too many lights - private static final int MAX_LIGHT_NUM = 9046; - // Use textures to store large amounts of light data at once, avoiding multiple draw calls - private Texture2D lightData1; - private Texture2D lightData2; - private Texture2D lightData3; - private ImageRaster lightDataUpdateIO1; - private ImageRaster lightDataUpdateIO2; - private ImageRaster lightDataUpdateIO3; + + private final Texture2D[] lightTextures = new Texture2D[3]; + private final ImageRaster[] lightTexRasters = new ImageRaster[3]; + private boolean packAsTextures = true; private int lightNum; private boolean useAmbientLight; - - private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1); - final private List skyLightAndReflectionProbes = new ArrayList<>(3); + private final ColorRGBA ambientColor = new ColorRGBA(0, 0, 0, 1); + private final List probes = new ArrayList<>(3); static { ADDITIVE_LIGHT.setBlendMode(BlendMode.AlphaAdditive); @@ -113,75 +107,76 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) { super(techniqueDef); singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean); - if(bUseTexturePackMode){ + if (packAsTextures) { packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int); packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean); prepareLightData(1024); - } - else{ + } else { 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(){ - if(this.lightData1 != null){ - this.lightData1.getImage().dispose(); + private void cleanupLightData() { + if (lightTextures[0] != null) { + lightTextures[0].getImage().dispose(); } - if(this.lightData2 != null){ - this.lightData2.getImage().dispose(); + if (lightTextures[1] != null) { + lightTextures[1].getImage().dispose(); } - if(this.lightData3 != null){ - this.lightData3.getImage().dispose(); + if (lightTextures[2] != null) { + lightTextures[2].getImage().dispose(); } } /** - * 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.

    + * Creates textures to accomodate light data. + *

    + * Currently, a large amount of light information is stored in textures, divided into three texture1d, + * lightData[0] stores lightColor (rgb stores lightColor, a stores lightType), lightData[1] stores lightPosition + + * invRange/lightDir, lightData[2] 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){ + private void prepareLightData(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); + lightTextures[0] = new Texture2D(lightNum, 1, Image.Format.RGBA32F); + lightTextures[0].setMinFilter(Texture.MinFilter.NearestNoMipMaps); + lightTextures[0].setMagFilter(Texture.MagFilter.Nearest); + lightTextures[0].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); + lightTextures[0].setImage(convertedImage); + lightTextures[0].getImage().setMipmapsGenerated(false); + lightTexRasters[0] = ImageRaster.create(lightTextures[0].getImage()); + + lightTextures[1] = new Texture2D(lightNum, 1, Image.Format.RGBA32F); + lightTextures[1].setMinFilter(Texture.MinFilter.NearestNoMipMaps); + lightTextures[1].setMagFilter(Texture.MagFilter.Nearest); + lightTextures[1].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); + lightTextures[1].setImage(convertedImage2); + lightTextures[1].getImage().setMipmapsGenerated(false); + lightTexRasters[1] = ImageRaster.create(lightTextures[1].getImage()); + + lightTextures[2] = new Texture2D(lightNum, 1, Image.Format.RGBA32F); + lightTextures[2].setMinFilter(Texture.MinFilter.NearestNoMipMaps); + lightTextures[2].setMagFilter(Texture.MagFilter.Nearest); + lightTextures[2].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()); + lightTextures[2].setImage(convertedImage3); + lightTextures[2].getImage().setMipmapsGenerated(false); + lightTexRasters[2] = ImageRaster.create(lightTextures[2].getImage()); } @Override public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { - if(bUseTexturePackMode){ + if(packAsTextures){ defines.set(packNbLightsDefineId, this.lightNum); defines.set(packTextureModeDefineId, true); } @@ -193,24 +188,26 @@ 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) { - useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, false); - defines.set(nbSkyLightAndReflectionProbesDefineId, skyLightAndReflectionProbes.size()); + useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientColor, probes, false); + defines.set(nbSkyLightAndReflectionProbesDefineId, probes.size()); defines.set(useAmbientLightDefineId, useAmbientLight); } 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
    + * Packs light data into textures. + *

    + * lightData[0]:
    + * - rgb stores lightColor
    + * - a stores lightTypeId
    + * lightData[1]:
    + * - directionalLightDirection
    + * - pointLightPosition + invRadius
    + * - spotLightPosition + invRadius
    + * lightData[2]:
    + * - 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 @@ -221,25 +218,26 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager * @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) { + 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(); + //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, ambientLightColor); + //extractSkyLightAndReflectionProbes(lightList,true); + ambientColor.setValue(VarType.Vector4, ambientColor); } // render skyLights and reflectionProbes - if(!skyLightAndReflectionProbes.isEmpty()){ + if(!probes.isEmpty()){ // Matrix4f Uniform skyLightData = shader.getUniform("g_SkyLightData"); Uniform skyLightData2 = shader.getUniform("g_SkyLightData2"); @@ -252,15 +250,18 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList 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); + LightProbe skyLight = probes.get(0); + lastTexUnit = SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData( + rm, lastTexUnit, skyLightData, shCoeffs, reflectionProbePemMap, skyLight); + if (probes.size() > 1) { + skyLight = probes.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); + if (probes.size() > 2) { + skyLight = probes.get(2); + SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData( + rm, lastTexUnit, skyLightData3, shCoeffs3, reflectionProbePemMap3, skyLight); } } else { Uniform skyLightData = shader.getUniform("g_SkyLightData"); @@ -273,7 +274,6 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList 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++; @@ -285,8 +285,7 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList temp.g = color.getGreen(); temp.b = color.getBlue(); temp.a = l.getType().getId(); - lightDataUpdateIO1.setPixel(curIndex, 0, temp); - + lightTexRasters[0].setPixel(curIndex, 0, temp); switch (l.getType()) { case Directional: DirectionalLight dl = (DirectionalLight) l; @@ -295,7 +294,7 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList temp.g = dir.getY(); temp.b = dir.getZ(); temp.a = -1; - lightDataUpdateIO2.setPixel(curIndex, 0, temp); + lightTexRasters[1].setPixel(curIndex, 0, temp); break; case Point: PointLight pl = (PointLight) l; @@ -305,7 +304,7 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList temp.g = pos.getY(); temp.b = pos.getZ(); temp.a = invRadius; - lightDataUpdateIO2.setPixel(curIndex, 0, temp); + lightTexRasters[1].setPixel(curIndex, 0, temp); break; case Spot: SpotLight sl = (SpotLight) l; @@ -317,7 +316,7 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList temp.g = pos2.getY(); temp.b = pos2.getZ(); temp.a = invRange; - lightDataUpdateIO2.setPixel(curIndex, 0, temp); + lightTexRasters[1].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 @@ -326,35 +325,31 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList temp.g = dir2.getY(); temp.b = dir2.getZ(); temp.a = spotAngleCos; - lightDataUpdateIO3.setPixel(curIndex, 0, temp); + lightTexRasters[2].setPixel(curIndex, 0, temp); break; default: 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 = lightTexRasters[0].getPixel(curIndex, 0); + // if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break; + // lightTexRasters[0].setPixel(curIndex, 0, temp); + // lightTexRasters[1].setPixel(curIndex, 0, temp); + // lightTexRasters[2].setPixel(curIndex, 0, temp); + //} 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); + lightTextures[0].getImage().setUpdateNeeded(); + lightTextures[1].getImage().setUpdateNeeded(); + lightTextures[2].getImage().setUpdateNeeded(); + g.getMaterial().setTexture("LightPackData1", lightTextures[0]); + g.getMaterial().setTexture("LightPackData2", lightTextures[1]); + g.getMaterial().setTexture("LightPackData3", lightTextures[2]); return curIndex; } @@ -380,7 +375,8 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, 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) { + 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; } @@ -394,7 +390,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, ambientLightColor); + ambientColor.setValue(VarType.Vector4, ambientColor); } int lightDataIndex = 0; @@ -467,12 +463,13 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light } @Override - public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnit) { - int nbRenderedLights = 0; + public void render(RenderManager renderManager, Shader shader, Geometry geometry, + LightList lights, BindUnits lastBindUnit) { + int numLights = 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(geometry.getUserData(LIGHT_CULL_DRAW_STAGE) != null){ + isLightCullStageDraw = geometry.getUserData(LIGHT_CULL_DRAW_STAGE); } // todo: One optimization approach here is: // todo: Use uniform array storage scheme: @@ -487,13 +484,13 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry // 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.getMaxDeferredShadingLights()){ + if(packAsTextures){ + if (lightNum != renderManager.getMaxDeferredShadingLights()) { cleanupLightData(); prepareLightData(renderManager.getMaxDeferredShadingLights()); } // 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) - useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true); + useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientColor, probes, 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"); @@ -501,32 +498,27 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry // lightCount.setValue(VarType.Int, this.lightNum); geometry.getMaterial().setInt("NBLight", count); if(count == 0){ - nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastBindUnit.textureUnit); + numLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, numLights, isLightCullStageDraw, lastBindUnit.textureUnit); + renderer.setShader(shader); + renderMeshFromGeometry(renderer, geometry); + } else while (numLights < 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) + numLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, numLights, isLightCullStageDraw, lastBindUnit.textureUnit); 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, lastBindUnit.textureUnit); - renderer.setShader(shader); - renderMeshFromGeometry(renderer, geometry); - } - } - } - else{ + } 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); - } + } else while (numLights < lights.size()) { + numLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, numLights, isLightCullStageDraw); + renderer.setShader(shader); + renderMeshFromGeometry(renderer, geometry); } } } + } 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 749125c5b3..2a1dead153 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -41,16 +41,12 @@ import com.jme3.material.Technique; import com.jme3.material.TechniqueDef; import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic; -import com.jme3.math.ColorRGBA; 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.RenderContext; -import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; @@ -74,7 +70,6 @@ import java.util.Collections; import java.util.List; import java.util.function.Predicate; -import java.util.logging.Logger; /** * A high-level rendering interface that is @@ -88,30 +83,13 @@ */ public class RenderManager { - // Maximum total number of light sources for deferred rendering + private GeometryRenderHandler renderGeometry; + private MyFrameGraph myFrameGraph; private int maxDeferredLights = 1024; - // TileInfo private TileBasedDeferredSinglePassLightingLogic.TileInfo tileInfo; - // 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; - // frameGraph=============================================================================↓ - private RenderGeometry renderGeometry; - 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; - private MyFrameGraph myFrameGraph; - // frameGraph=============================================================================↑ // RenderPath public enum RenderPath { @@ -135,9 +113,7 @@ public String getInfo(){ return info; } } - private RenderPath renderPath = RenderPath.Forward; - private static final Logger logger = Logger.getLogger(RenderManager.class.getName()); private final Renderer renderer; private final UniformBindingManager uniformBindingManager = new UniformBindingManager(); private final ArrayList preViewPorts = new ArrayList<>(); @@ -173,18 +149,6 @@ public String getInfo(){ public RenderManager(Renderer renderer) { this.renderer = renderer; this.forcedOverrides.add(boundDrawBufferId); - if(useFramegraph){ - frameGraph = new FrameGraph(new RenderContext(this, 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"); - } } /** @@ -212,14 +176,6 @@ public void setForceTileSize(int forceTileSize) { public int getForceTileSize() { return forceTileSize; } - - /** - * EnableFrameGraph? - * @param useFramegraph - */ - public final void enableFramegraph(boolean useFramegraph){ - this.useFramegraph = useFramegraph; - } /** * Sets the framegraph used in the rendering process. @@ -282,36 +238,16 @@ public TileBasedDeferredSinglePassLightingLogic.TileInfo getTileInfo() { * Set an IRenderGeometry for executing drawing call interfaces for the specified FGPass. * * @param renderGeometry - * @see RenderGeometry + * @see GeometryRenderHandler */ - public final void setRenderGeometryHandler(RenderGeometry renderGeometry){ + public final void setGeometryRenderHandler(GeometryRenderHandler renderGeometry){ this.renderGeometry = renderGeometry; } - public RenderGeometry getRenderGeometryHandler() { + public GeometryRenderHandler getGeometryRenderHandler() { return renderGeometry; } - /** - * 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. @@ -822,7 +758,33 @@ public void updateUniformBindings(Shader shader) { * @see com.jme3.material.Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager) */ public void renderGeometry(Geometry geom) { - if (renderFilter != null && !renderFilter.test(geom)) return; + + if (renderFilter != null && !renderFilter.test(geom)) { + return; + } + + LightList lightList = geom.getWorldLightList(); + if (lightFilter != null) { + filteredLightList.clear(); + lightFilter.filterLights(geom, filteredLightList); + lightList = filteredLightList; + } + + renderGeometry(geom, lightList); + + } + + /** + * + * @param geom + * @param lightList + */ + public void renderGeometry(Geometry geom, LightList lightList) { + + if (renderFilter != null && !renderFilter.test(geom)) { + return; + } + this.renderer.pushDebugGroup(geom.getName()); if (geom.isIgnoreTransform()) { setWorldMatrix(Matrix4f.IDENTITY); @@ -830,20 +792,13 @@ 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) + // 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(); - - if (lightFilter != null) { - filteredLightList.clear(); - lightFilter.filterLights(geom, filteredLightList); - lightList = filteredLightList; - } + // updateFilterLight geom.setFilterLight(lightList); 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 a2bdb7cf34..ae61b2a9f6 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,14 +34,14 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; -import com.jme3.renderer.pass.RenderGeometry; +import com.jme3.renderer.pass.GeometryRenderHandler; /** * All passes that need to perform rendering must inherit from this class.. * * @author JohnKkk */ -public abstract class FGRenderQueuePass extends FGBindingPass implements RenderGeometry { +public abstract class FGRenderQueuePass extends FGBindingPass implements GeometryRenderHandler { 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. @@ -72,10 +72,10 @@ public void setForceViewPort(ViewPort forceViewPort) { @Override public void execute(RenderContext renderContext) { - renderContext.getRenderManager().setRenderGeometryHandler(this); + renderContext.getRenderManager().setGeometryRenderHandler(this); dispatchPassSetup(renderContext.getRenderQueue()); if(!canExecute){ - renderContext.getRenderManager().setRenderGeometryHandler(null); + renderContext.getRenderManager().setGeometryRenderHandler(null); return; } bindAll(renderContext); @@ -85,7 +85,7 @@ public void execute(RenderContext renderContext) { // drawcall //} executeDrawCommands(renderContext); - renderContext.getRenderManager().setRenderGeometryHandler(null); + renderContext.getRenderManager().setGeometryRenderHandler(null); } /** 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 baf85f4893..493bb1443a 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 @@ -198,7 +198,7 @@ public void reset(){ } passes.clear(); if(renderContext != null) { - renderContext.getRenderManager().setRenderGeometryHandler(null); + renderContext.getRenderManager().setGeometryRenderHandler(null); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java index 498d80bfde..d6f693c82b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java @@ -5,7 +5,6 @@ package com.jme3.renderer.framegraph; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.ViewPort; import java.util.LinkedList; /** @@ -47,12 +46,15 @@ public void execute() { p.execute(context); // apply resulting output parameters to connected input parameters parameters.push(p); + // reset depth render range + context.setDepthRange(DepthRange.IDENTITY); + // reset geometry handler + context.getRenderManager().setGeometryRenderHandler(null); } // reset passes for (FGModule p : passes) { p.reset(); } - context.getRenderManager().setRenderGeometryHandler(null); } public void add(FGModule pass) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java index 117efb264a..9ecb7ee767 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java @@ -5,15 +5,15 @@ package com.jme3.renderer.framegraph; import com.jme3.renderer.ViewPort; -import com.jme3.renderer.pass.RenderGeometry; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; +import com.jme3.renderer.pass.GeometryRenderHandler; /** * * @author codex */ -public abstract class RenderQueueModule extends AbstractModule implements RenderGeometry { +public abstract class RenderQueueModule extends AbstractModule implements GeometryRenderHandler { protected ViewPort forcedViewPort; protected GeometryList drawCommands; @@ -25,12 +25,12 @@ public abstract class RenderQueueModule extends AbstractModule implements Render @Override public void execute(RenderContext context) { - context.getRenderManager().setRenderGeometryHandler(this); + context.getRenderManager().setGeometryRenderHandler(this); dispatchPassSetup(context.getRenderQueue()); //if (canExecute) { executeDrawCommands(context); //} - context.getRenderManager().setRenderGeometryHandler(null); + context.getRenderManager().setGeometryRenderHandler(null); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java index fbece1016f..10107eb699 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -8,15 +8,13 @@ import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.material.RenderState; -import com.jme3.math.ColorRGBA; -import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.AbstractModule; import com.jme3.renderer.framegraph.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.TextureTargetParam; import com.jme3.renderer.framegraph.ValueRenderParam; import com.jme3.renderer.queue.RenderQueue; -import com.jme3.scene.Geometry; import com.jme3.shader.VarType; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture2D; @@ -26,7 +24,7 @@ * * @author codex */ -public class DeferredShadingModule extends ScreenModule { +public class DeferredShadingModule extends AbstractModule { public final static String RT_0 = "Context_InGBuff0"; public final static String RT_1 = "Context_InGBuff1"; @@ -40,6 +38,9 @@ public class DeferredShadingModule extends ScreenModule { protected final static String DEFERRED_PASS = "DeferredPass"; private static final String MATDEF = "Common/MatDefs/ShadingCommon/DeferredShading.j3md"; + protected final AssetManager assetManager; + protected Material screenMat; + protected Picture screenRect; protected MatRenderParam[] matParams = new MatRenderParam[5]; protected ValueRenderParam lightList; protected ValueRenderParam executeState; @@ -48,7 +49,7 @@ public class DeferredShadingModule extends ScreenModule { private TextureTargetParam depthCopy; public DeferredShadingModule(AssetManager assetManager) { - super(assetManager, RenderQueue.Bucket.Opaque); + this.assetManager = assetManager; } @Override @@ -58,10 +59,11 @@ public void initialize(MyFrameGraph frameGraph) { screenRect = new Picture("DeferredShadingPass_Rect"); screenRect.setWidth(1); screenRect.setHeight(1); + screenRect.setIgnoreTransform(true); screenRect.setMaterial(screenMat); RenderState rs = screenMat.getAdditionalRenderState(); - rs.setDepthWrite(true); + rs.setDepthWrite(!true); rs.setDepthTest(true); rs.setDepthFunc(RenderState.TestFunction.Greater); //rs.setBlendMode(RenderState.BlendMode.Alpha); @@ -83,23 +85,8 @@ public void initialize(MyFrameGraph frameGraph) { bindParameters(frameGraph); } - - protected Material createMaterial() { - return new Material(assetManager, MATDEF); - } - - protected void bindParameters(MyFrameGraph frameGraph) { - for (int i = 0; i < matParams.length; i++) { - frameGraph.bindToOutput(GBufferModule.RENDER_TARGETS[i], matParams[i]); - } - frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); - frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); - frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, gBuffer); - } - @Override public void prepare(RenderContext context) { - super.prepare(context); if (debug == null) { debug = new FrameBuffer(context.getWidth(), context.getHeight(), 1); FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget( @@ -108,9 +95,8 @@ public void prepare(RenderContext context) { depthCopy.setTextureTarget(t); } } - @Override - public void executeDrawCommands(RenderContext context) { + public void execute(RenderContext context) { context.getRenderer().copyFrameBuffer(gBuffer.produce(), context.getViewPort().getOutputFrameBuffer(), false, true); @@ -118,25 +104,25 @@ public void executeDrawCommands(RenderContext context) { context.getRenderer().copyFrameBuffer(gBuffer.produce(), debug, false, true); context.setDepthRange(1, 1); - context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); screenMat.selectTechnique(DEFERRED_PASS, context.getRenderManager()); screenRect.updateGeometricState(); - context.getRenderManager().renderGeometry(screenRect); + context.getRenderManager().renderGeometry(screenRect, lightList.produce()); //screenMat.render(screenRect, lightList.produce(), context.getRenderManager()); } - @Override - public void dispatchPassSetup(RenderQueue queue) { - //boolean exState = executeState.validate() && executeState.produce(); - //boolean hasLightData = lightList.validate() && lightList.produce().size() > 0; - //canExecute = hasLightData || exState; - canExecute = true; - } + public void reset() {} - @Override - public boolean drawGeometry(RenderManager rm, Geometry geom) { - return true; + protected Material createMaterial() { + return new Material(assetManager, MATDEF); + } + protected void bindParameters(MyFrameGraph frameGraph) { + for (int i = 0; i < matParams.length; i++) { + frameGraph.bindToOutput(GBufferModule.RENDER_TARGETS[i], matParams[i]); + } + frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); + frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); + frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, gBuffer); } } 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 b054edfbb8..6733182fe6 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 @@ -124,7 +124,7 @@ public void dispatchPassSetup(RenderQueue renderQueue) { } @Override - public boolean drawGeometry(RenderManager rm, Geometry geom) { + public boolean renderGeometry(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/pass/ForwardModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java index 11a283a1f0..66d45d5dcc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java @@ -5,6 +5,7 @@ package com.jme3.renderer.pass; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.AbstractModule; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; @@ -16,13 +17,13 @@ * * @author codex */ -public class ForwardModule extends RenderQueueModule { +public class ForwardModule extends AbstractModule { private final RenderQueue.Bucket bucket; protected DepthRange depth; public ForwardModule(RenderQueue.Bucket bucket) { - this(bucket, null); + this(bucket, DepthRange.IDENTITY); } public ForwardModule(RenderQueue.Bucket bucket, DepthRange depth) { this.bucket = bucket; @@ -30,28 +31,18 @@ public ForwardModule(RenderQueue.Bucket bucket, DepthRange depth) { } @Override - public void dispatchPassSetup(RenderQueue queue) { - canExecute = !queue.isQueueEmpty(bucket); - } + public void initialize(MyFrameGraph frameGraph) {} @Override - public void executeDrawCommands(RenderContext context) { - if (!canExecute) { - //return; - } + public void prepare(RenderContext context) {} + @Override + public void execute(RenderContext context) { if (depth != null) { context.setDepthRange(depth); } context.getRenderQueue().renderQueue(bucket, context.getRenderManager(), context.getViewPort().getCamera(), true); } @Override - public void initialize(MyFrameGraph frameGraph) {} - @Override - public void prepare(RenderContext context) {} - @Override - public boolean drawGeometry(RenderManager rm, Geometry geom) { - rm.renderGeometry(geom); - return true; - } + public void reset() {} public static ForwardModule opaque() { return new ForwardModule(RenderQueue.Bucket.Opaque, DepthRange.IDENTITY); 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 059918ef30..46fdd30a3c 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 @@ -69,7 +69,7 @@ public void dispatchPassSetup(RenderQueue renderQueue) { } @Override - public boolean drawGeometry(RenderManager rm, Geometry geom) { + public boolean renderGeometry(RenderManager rm, Geometry geom) { rm.renderGeometry(geom); return true; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java index 9f1d602175..550168a8fb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java @@ -15,6 +15,7 @@ import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.TextureTargetParam; import com.jme3.renderer.framegraph.ValueRenderParam; +import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; @@ -25,7 +26,7 @@ * * @author codex */ -public class GBufferModule extends OpaqueModule { +public class GBufferModule extends ForwardModule implements GeometryRenderHandler { private final static String GBUFFER_PASS = "GBufferPass"; public final static String[] RENDER_TARGETS = { @@ -42,8 +43,11 @@ public class GBufferModule extends OpaqueModule { private FrameBuffer gBuffer; private ValueRenderParam bufferParam; private final TextureTargetParam[] targets = new TextureTargetParam[5]; - private final ColorRGBA mask = new ColorRGBA(0, 0, 0, 0); - private int width = -1, height = -1; + private final ColorRGBA mask = new ColorRGBA(); + + public GBufferModule() { + super(RenderQueue.Bucket.Opaque); + } @Override public void initialize(MyFrameGraph frameGraph) { @@ -59,29 +63,32 @@ public void initialize(MyFrameGraph frameGraph) { @Override public void prepare(RenderContext context) { super.prepare(context); - ViewPort vp = getViewPort(context); - reshape(context.getRenderer(), vp.getCamera().getWidth(), vp.getCamera().getHeight()); + if (context.isSizeChanged() || gBuffer == null) { + reshape(context.getRenderer(), context.getWidth(), context.getHeight()); + } } @Override - public void executeDrawCommands(RenderContext context) { - ViewPort vp = getViewPort(context); + public void execute(RenderContext context) { + ViewPort vp = context.getViewPort(); String tempFT = context.getRenderManager().getForcedTechnique(); context.getRenderer().setFrameBuffer(gBuffer); context.getRenderer().setBackgroundColor(mask.set(vp.getBackgroundColor()).setAlpha(0)); context.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); context.getRenderManager().setForcedTechnique(GBUFFER_PASS); - super.executeDrawCommands(context); + context.getRenderManager().setGeometryRenderHandler(this); + super.execute(context); + context.getRenderManager().setGeometryRenderHandler(null); context.getRenderManager().setForcedTechnique(tempFT); context.getRenderer().setBackgroundColor(vp.getBackgroundColor()); context.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer()); - for(Light light : tempLights){ + for (Light light : tempLights) { lightData.add(light); } } @Override - public boolean drawGeometry(RenderManager rm, Geometry geom) { + public boolean renderGeometry(RenderManager rm, Geometry geom) { Material material = geom.getMaterial(); if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null) { return false; @@ -113,11 +120,6 @@ public void reset() { } protected void reshape(Renderer renderer, int w, int h) { - if (width == w && height == h) { - return; - } - width = w; - height = h; if (gBuffer != null) { gBuffer.dispose(); gBuffer.deleteObject(renderer); @@ -158,12 +160,4 @@ protected void reshape(Renderer renderer, int w, int h) { bufferParam.accept(gBuffer); } - protected ViewPort getViewPort(RenderContext context) { - if (forcedViewPort == null) { - return context.getViewPort(); - } else { - return forcedViewPort; - } - } - } 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 8bd9eec117..2ea04db9ad 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 @@ -164,7 +164,7 @@ public void reshape(Renderer renderer, ViewPort vp, int w, int h){ } @Override - public boolean drawGeometry(RenderManager rm, Geometry geom) { + public boolean renderGeometry(RenderManager rm, Geometry geom) { Material material = geom.getMaterial(); if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null)return false; rm.renderGeometry(geom); diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/RenderGeometry.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GeometryRenderHandler.java similarity index 94% rename from jme3-core/src/main/java/com/jme3/renderer/pass/RenderGeometry.java rename to jme3-core/src/main/java/com/jme3/renderer/pass/GeometryRenderHandler.java index b858c6da8b..1425bef605 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/RenderGeometry.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GeometryRenderHandler.java @@ -37,12 +37,12 @@ /** * @author JohnKkk */ -public interface RenderGeometry { +public interface GeometryRenderHandler { /** * 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); + public boolean renderGeometry(RenderManager rm, Geometry geom); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java index da2f6eb96b..bc154d85c2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java @@ -5,6 +5,7 @@ package com.jme3.renderer.pass; import com.jme3.renderer.Camera; +import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.queue.RenderQueue; @@ -15,25 +16,15 @@ public class GuiModule extends ForwardModule { public GuiModule() { - super(RenderQueue.Bucket.Gui); + super(RenderQueue.Bucket.Gui, DepthRange.IDENTITY); } @Override - public void executeDrawCommands(RenderContext context) { - Camera cam; - if (forcedViewPort != null) { - cam = forcedViewPort.getCamera(); - } else { - cam = context.getViewPort().getCamera(); - } - if (canExecute) { - context.setDepthRange(0, 0); - context.getRenderManager().setCamera(cam, true); - } - super.executeDrawCommands(context); - if (canExecute) { - context.getRenderManager().setCamera(cam, false); - } + public void execute(RenderContext context) { + Camera cam = context.getViewPort().getCamera(); + context.getRenderManager().setCamera(cam, true); + super.execute(context); + context.getRenderManager().setCamera(cam, false); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/OpaqueModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/OpaqueModule.java deleted file mode 100644 index c771ed844f..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/OpaqueModule.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.pass; - -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.queue.RenderQueue; - -/** - * - * @author codex - */ -public class OpaqueModule extends ForwardModule { - - public OpaqueModule() { - super(RenderQueue.Bucket.Opaque); - } - - @Override - public void executeDrawCommands(RenderContext renderContext) { - if (canExecute) { - renderContext.setDepthRange(0, 1); - } - super.executeDrawCommands(renderContext); - } - -} 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 b0e1739175..94ea513465 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 @@ -75,7 +75,7 @@ public void updateExposure(float exposure){ } @Override - public boolean drawGeometry(RenderManager rm, Geometry geom) { + public boolean renderGeometry(RenderManager rm, Geometry geom) { return true; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenModule.java deleted file mode 100644 index a6c3d42fea..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenModule.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.pass; - -import com.jme3.asset.AssetManager; -import com.jme3.material.Material; -import com.jme3.renderer.framegraph.MyFrameGraph; -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.ui.Picture; - -/** - * - * @author codex - */ -public abstract class ScreenModule extends ForwardModule { - - protected final AssetManager assetManager; - protected Material screenMat; - protected Picture screenRect; - - public ScreenModule(AssetManager assetManager, RenderQueue.Bucket bucket) { - super(bucket); - this.assetManager = assetManager; - } - - @Override - public abstract void initialize(MyFrameGraph frameGraph); - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java deleted file mode 100644 index 8dec8325c1..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/SkyModule.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.pass; - -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.DepthRange; -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.scene.Geometry; - -/** - * - * @author codex - */ -public class SkyModule extends ForwardModule { - - public SkyModule() { - super(RenderQueue.Bucket.Sky, DepthRange.REAR); - } - - @Override - public boolean drawGeometry(RenderManager rm, Geometry geom) { - rm.renderGeometry(geom); - return true; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java index 41744a005b..e546138beb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java @@ -28,7 +28,7 @@ protected Material createMaterial() { } @Override - public void executeDrawCommands(RenderContext context) { + public void execute(RenderContext context) { // Handle FullScreenLights screenMat.selectTechnique(PASS, context.getRenderManager()); 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 c8e2107a45..be0c5300f2 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,9 +34,11 @@ import com.jme3.post.SceneProcessor; import com.jme3.renderer.Camera; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.pass.RenderGeometry; import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; +import java.util.Iterator; +import java.util.LinkedList; +import com.jme3.renderer.pass.GeometryRenderHandler; /** * RenderQueue is used to queue up and sort @@ -51,14 +53,12 @@ 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()); @@ -239,11 +239,10 @@ public GeometryComparator getGeometryComparator(Bucket bucket) { * Adds a geometry to the given 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() }. + * the geometry is determined by {@link Geometry#getQueueBucket()}. * * @param g The geometry to add - * @param bucket The bucket to add to, usually - * {@link Geometry#getQueueBucket() }. + * @param bucket The bucket to add to, usually {@link Geometry#getQueueBucket()}. */ public void addToQueue(Geometry g, Bucket bucket) { switch (bucket) { @@ -268,38 +267,31 @@ public void addToQueue(Geometry g, Bucket bucket) { } private void renderGeometryList(GeometryList list, RenderManager rm, Camera cam, boolean clear) { - RenderGeometry 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); + GeometryRenderHandler handler = rm.getGeometryRenderHandler(); + list.setCamera(cam); // select camera for sorting + list.sort(); + if (handler != null && clear) { + LinkedList saved = new LinkedList<>(); + for (Geometry g : list) { + assert g != null; + if (!handler.renderGeometry(rm, g)) { + saved.add(g); } - obj.queueDistance = Float.NEGATIVE_INFINITY; + g.queueDistance = Float.NEGATIVE_INFINITY; } - if (clear) { - list.clear(); - // In order to perform subsequent RenderPath rendering - if(tempList.size() > 0){ - for(int i = 0;i < tempList.size();i++){ - list.add(tempList.get(i)); - } - } + list.clear(); + for (Geometry g : saved) { + list.add(g); } - } - 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; + } else { + for (Geometry g : list) { + assert g != null; + if (handler != null) { + handler.renderGeometry(rm, g); + } else { + rm.renderGeometry(g); + } + g.queueDistance = Float.NEGATIVE_INFINITY; } if (clear) { list.clear(); 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 7d5eaec6a3..967ef1bd32 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -223,4 +223,5 @@ void main(){ //} //discard; //gl_FragColor.a = 0.5; + //gl_FragColor.a = 0.01; } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthDebug.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthDebug.frag new file mode 100644 index 0000000000..2820a12090 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthDebug.frag @@ -0,0 +1,15 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" +#import "Common/ShaderLib/MultiSample.glsllib" + +uniform COLORTEXTURE m_Texture; +uniform DEPTHTEXTURE m_DepthTexture; +varying vec2 texCoord; + +void main() { + vec3 val = getDepth(m_DepthTexture, texCoord).rrr; + if (val.r <= 1.0 && val.r >= 0.0) { + gl_FragColor.rgb = vec3(1.0) - val; + } else { + gl_FragColor.rgb = vec3(1.0, 0.0, 0.0); + } +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthDebug.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthDebug.j3md new file mode 100644 index 0000000000..21b13bf401 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthDebug.j3md @@ -0,0 +1,22 @@ +MaterialDef DepthDebug { + + MaterialParameters { + Int BoundDrawBuffer + Int NumSamples + Texture2D Texture; + Texture2D DepthTexture; + } + + Technique { + VertexShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Post/Post.vert + FragmentShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Post/DepthDebug.frag + + WorldParameters { + } + + Defines { + BOUND_DRAW_BUFFER: BoundDrawBuffer + } + } + +} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index ca3460bd21..690584d41d 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -1,6 +1,7 @@ package jme3test.renderpath; import com.jme3.app.SimpleApplication; +import com.jme3.asset.AssetManager; import com.jme3.environment.EnvironmentCamera; import com.jme3.environment.EnvironmentProbeControl; import com.jme3.light.AmbientLight; @@ -10,8 +11,10 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; +import com.jme3.post.Filter; import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderPipelineFactory; @@ -119,7 +122,8 @@ public void simpleInitApp() { // 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); + //fpp.addFilter(new DepthDebugFilter()); + viewPort.addProcessor(fpp); DirectionalLightShadowRenderer dr = new DirectionalLightShadowRenderer(assetManager, 1024, 2); dr.setLight(dl); @@ -158,4 +162,24 @@ public static void main(String[] args) { TestShadingModel testShadingModel = new TestShadingModel(); testShadingModel.start(); } + + private class DepthDebugFilter extends Filter { + + @Override + protected void initFilter(AssetManager assetManager, RenderManager renderManager, ViewPort vp, int w, int h) { + material = new Material(assetManager, "Common/MatDefs/Post/DepthDebug.j3md"); + } + + @Override + protected Material getMaterial() { + return material; + } + + @Override + protected boolean isRequiresDepthTexture() { + return true; + } + + } + } From 713ca9cff8b9e1a47d6f38833148ba1448189884 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 22 Apr 2024 21:47:35 -0400 Subject: [PATCH 042/111] more cleanup --- .../java/com/jme3/material/TechniqueDef.java | 4 +- .../DeferredSinglePassLightingLogic.java | 44 ++++++------ .../material/logic/TechniqueDefLogic.java | 2 +- ...eBasedDeferredSinglePassLightingLogic.java | 34 +++++---- .../renderer/pass/DeferredShadingModule.java | 8 ++- .../com/jme3/material/plugins/J3MLoader.java | 3 +- .../jme3test/renderpath/RenderPathHelper.java | 71 ------------------- .../TerrainTestAdvancedRenderPath.java | 1 - .../TerrainTestAndroidRenderPath.java | 2 - .../renderpath/TestDeferredPBRShading.java | 4 +- .../renderpath/TestDeferredShading.java | 2 +- .../TestDeferredShadingPathShadow.java | 4 +- .../TestPBRTerrainAdvancedRenderPath.java | 1 - .../renderpath/TestPBRTerrainRenderPath.java | 2 +- .../renderpath/TestRenderPathChanged.java | 4 +- ...thPointDirectionalAndSpotLightShadows.java | 1 - .../TestSimpleDeferredLighting.java | 4 +- .../TestTileBasedDeferredShading.java | 2 +- 18 files changed, 62 insertions(+), 131 deletions(-) delete mode 100644 jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java 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 cc2d2e93bb..f8b1355f31 100644 --- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java +++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java @@ -162,6 +162,7 @@ public enum LightMode { */ @Deprecated FixedPipeline, + /** * Similar to {@link #SinglePass} except the type of each light is known * at shader compile time. @@ -172,7 +173,8 @@ public enum LightMode { * shaders used balloons because of the variations in the number of * lights used by objects. */ - StaticPass + StaticPass, + } public enum ShadowMode { 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 a031c1c60a..0d42e14291 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 @@ -86,7 +86,7 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo private final Texture2D[] lightTextures = new Texture2D[3]; private final ImageRaster[] lightTexRasters = new ImageRaster[3]; - private boolean packAsTextures = true; + private final boolean useLightTextures; private int lightNum; private boolean useAmbientLight; private final ColorRGBA ambientColor = new ColorRGBA(0, 0, 0, 1); @@ -100,22 +100,26 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo private final int singlePassLightingDefineId; private int nbLightsDefineId; private int packNbLightsDefineId; - private int packTextureModeDefineId; - private final int nbSkyLightAndReflectionProbesDefineId; - private final int useAmbientLightDefineId; - - public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) { + private int textureModeDefine; + private final int probeDefine; + private final int ambientDefines; + +// public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) { +// this(techniqueDef, true); +// } + public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef, boolean useLightTextures) { super(techniqueDef); + this.useLightTextures = useLightTextures; singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean); - if (packAsTextures) { + if (this.useLightTextures) { packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int); - packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean); + textureModeDefine = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean); prepareLightData(1024); } else { 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); + probeDefine = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES, VarType.Int); + ambientDefines = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_AMBIENT_LIGHT, VarType.Boolean); } private void cleanupLightData() { @@ -176,9 +180,9 @@ private void prepareLightData(int lightNum) { @Override public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { - if(packAsTextures){ + if(useLightTextures){ defines.set(packNbLightsDefineId, this.lightNum); - defines.set(packTextureModeDefineId, true); + defines.set(textureModeDefine, true); } else{ defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3); @@ -189,8 +193,8 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager //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) { useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientColor, probes, false); - defines.set(nbSkyLightAndReflectionProbesDefineId, probes.size()); - defines.set(useAmbientLightDefineId, useAmbientLight); + defines.set(probeDefine, probes.size()); + defines.set(ambientDefines, useAmbientLight); } return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines); } @@ -218,22 +222,22 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager * @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, + private 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"); + Uniform ambClr = 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); + ambClr.setValue(VarType.Vector4, ColorRGBA.Black); } else { //extractSkyLightAndReflectionProbes(lightList,true); - ambientColor.setValue(VarType.Vector4, ambientColor); + ambClr.setValue(VarType.Vector4, ambientColor); } // render skyLights and reflectionProbes @@ -375,7 +379,7 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList * @param isLightCullStageDraw isLightCullStageDraw * @return the next starting index in the LightList */ - protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, + private 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; @@ -484,7 +488,7 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry // 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(packAsTextures){ + if(useLightTextures){ if (lightNum != renderManager.getMaxDeferredShadingLights()) { cleanupLightData(); prepareLightData(renderManager.getMaxDeferredShadingLights()); diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java index 31f970a176..097c1fb003 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java @@ -91,7 +91,7 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager * {@link #makeCurrent(com.jme3.asset.AssetManager, com.jme3.renderer.RenderManager, java.util.EnumSet, com.jme3.light.LightList, com.jme3.shader.DefineList)}. * @param geometry The geometry to render * @param lights Lights which influence the geometry. - * @param lastTexUnit the index of the most recently used texture unit + * @param lastBindUnits the index of the most recently used units */ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits); } 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 1393384fe2..759afa301e 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 @@ -74,10 +74,11 @@ * @author JohnKkk */ 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 final static String LIGHT_CULL_DRAW_STAGE = "Light_Cull_Draw_Stage"; + private final static String TILE_SIZE = "g_TileSize"; + private final static String TILE_WIDTH = "g_WidthTile"; + private final static String 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"; @@ -91,9 +92,7 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe // 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; - // Avoid too many lights - private static final int MAX_LIGHT_NUM = 9046; + private boolean packAsTextures = true; // Use textures to store large amounts of light data at once, avoiding multiple draw calls private Texture2D lightData1; private Texture2D lightData2; @@ -128,7 +127,6 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe private float viewPortWidth = -1; private float viewPortHeight = -1; private final float[] matArray1 = new float[16]; - private final float[] matArray2 = new float[16]; private final Vector3f tempVec3 = new Vector3f(); private final Vector3f tempVec3_2 = new Vector3f(); private final Vector4f tempVec4 = new Vector4f(); @@ -164,7 +162,7 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe *

    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{ + public static class TileInfo { int tileSize = 0; int tileWidth = 0; int tileHeight = 0; @@ -249,7 +247,7 @@ private void cleanupTileTexture(){ /** * 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. * @@ -571,7 +569,7 @@ 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){ + if(packAsTextures){ packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int); packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean); prepareLightData(1024); @@ -653,7 +651,7 @@ private void prepareLightData(int lightNum){ @Override public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { - if(bUseTexturePackMode){ + if(packAsTextures){ defines.set(packNbLightsDefineId, this.lightNum); defines.set(packTextureModeDefineId, true); } @@ -945,10 +943,10 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry 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(geometry.getUserData(LIGHT_CULL_DRAW_STAGE) != null){ + isLightCullStageDraw = geometry.getUserData(LIGHT_CULL_DRAW_STAGE); } - if(bUseTexturePackMode){ + if(packAsTextures){ if(this.lightNum != renderManager.getMaxDeferredShadingLights()){ cleanupLightData(); prepareLightData(renderManager.getMaxDeferredShadingLights()); @@ -968,9 +966,9 @@ 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); + Uniform u_tileSize = shader.getUniform(TILE_SIZE); + Uniform u_tileWidth = shader.getUniform(TILE_WIDTH); + Uniform u_tileHeight = shader.getUniform(TILE_HEIGHT); u_tileSize.setValue(VarType.Int, tileSize); u_tileWidth.setValue(VarType.Int, tileWidth); u_tileHeight.setValue(VarType.Int, tileHeight); diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java index 10107eb699..73f7d603ed 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -8,13 +8,14 @@ import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.material.RenderState; +import com.jme3.material.TechniqueDef; +import com.jme3.material.logic.DeferredSinglePassLightingLogic; import com.jme3.renderer.framegraph.AbstractModule; import com.jme3.renderer.framegraph.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.TextureTargetParam; import com.jme3.renderer.framegraph.ValueRenderParam; -import com.jme3.renderer.queue.RenderQueue; import com.jme3.shader.VarType; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture2D; @@ -41,6 +42,7 @@ public class DeferredShadingModule extends AbstractModule { protected final AssetManager assetManager; protected Material screenMat; protected Picture screenRect; + protected DeferredSinglePassLightingLogic logic; protected MatRenderParam[] matParams = new MatRenderParam[5]; protected ValueRenderParam lightList; protected ValueRenderParam executeState; @@ -70,6 +72,10 @@ public void initialize(MyFrameGraph frameGraph) { //screenMat.setTransparent(true); screenMat.setBoolean("UseLightsCullMode", false); + TechniqueDef techDef = screenMat.getMaterialDef().getTechniqueDefs(DEFERRED_PASS).get(0); + logic = new DeferredSinglePassLightingLogic(techDef, true); + techDef.setLogic(logic); + // material render parameters automatically apply their values matParams[0] = addParameter(new MatRenderParam(RT_0, screenMat, VarType.Texture2D)); matParams[1] = addParameter(new MatRenderParam(RT_1, screenMat, VarType.Texture2D)); 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 613d194673..efa93d5d92 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 @@ -667,10 +667,9 @@ private void readTechnique(Statement techStat) throws IOException{ technique.setLogic(new SinglePassLightingLogic(technique)); break; case DeferredSinglePass: - technique.setLogic(new DeferredSinglePassLightingLogic(technique)); + technique.setLogic(new DeferredSinglePassLightingLogic(technique, true)); break; case TileBasedDeferredSinglePass: - System.out.println("assign deferred lighting logic"); technique.setLogic(new TileBasedDeferredSinglePassLightingLogic(technique)); break; case StaticPass: diff --git a/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java b/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java deleted file mode 100644 index 9ace9b4e13..0000000000 --- a/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -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.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)); - } - - 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) { - 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(hitLocation); - simpleApplication.getGuiNode().attachChild(hitText); - - // hit text - BitmapText title = new BitmapText(guiFont, false); - title.setSize(guiFont.getCharSet().getRenderedSize()); - title.setText("Please press the " + keyHit + " to toggle the render path"); - title.setLocalTranslation(hitLocation); - title.getLocalTranslation().y -= 20; - 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()); - } - } -} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java index c40353608c..56831d8eb9 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java @@ -224,7 +224,6 @@ public void simpleInitApp() { rootNode.attachChild(createAxisMarker(20)); - new RenderPathHelper(this, new Vector3f(0, cam.getHeight() / 2, 0), KeyInput.KEY_K, "K"); renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java index 6e455689dd..29f043db34 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java @@ -147,8 +147,6 @@ public void simpleInitApp() { 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() { diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java index c24ebb29d5..7319da19df 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java @@ -38,8 +38,6 @@ public class TestDeferredPBRShading extends SimpleApplication { 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"); @@ -160,7 +158,7 @@ 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); + //renderManager.setRenderPath(RenderManager.RenderPath.Deferred); } }); probe.getArea().setRadius(100); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java index dff94f8c92..ff18a0145a 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java @@ -28,7 +28,7 @@ public void simpleInitApp() { // renderManager.setSinglePassLightBatchSize(30); // renderManager.setRenderPath(RenderManager.RenderPath.Forward); renderManager.setMaxDeferredShadingLights(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.setRenderPath(RenderManager.RenderPath.Deferred); renderManager.setSinglePassLightBatchSize(200); Quad quad = new Quad(15, 15); Geometry geo = new Geometry("Floor", quad); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java index 6846e3e616..0543744315 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java @@ -90,7 +90,7 @@ public void simpleInitApp() { inputManager.addMapping("toggleRenderPath", new KeyTrigger(KeyInput.KEY_SPACE)); currentRenderPath = RenderManager.RenderPath.Forward; - renderManager.setRenderPath(currentRenderPath); + //renderManager.setRenderPath(currentRenderPath); makeHudText(); flyCam.setMoveSpeed(20.0f); @@ -113,7 +113,7 @@ else if(currentRenderPath == RenderManager.RenderPath.TiledDeferred){ else{ currentRenderPath = RenderManager.RenderPath.Deferred; } - renderManager.setRenderPath(currentRenderPath); + //renderManager.setRenderPath(currentRenderPath); hitText.setText("RendererPath : "+ currentRenderPath.getInfo()); } } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java index 1cafeb1941..cef7e99f9b 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java @@ -361,7 +361,6 @@ 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() { diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java index 2603562506..be6359cc66 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java @@ -314,7 +314,7 @@ private void setUpTerrainMaterial() { matTerrain.setTexture("NormalMap_6", normalMapGravel); terrain.setMaterial(matTerrain); - new RenderPathHelper(this, new Vector3f(0, cam.getHeight() / 2, 0), KeyInput.KEY_K, "K"); + //new RenderPathHelper(this, new Vector3f(0, cam.getHeight() / 2, 0), KeyInput.KEY_K, "K"); getStateManager().attach(new DetailedProfilerState()); } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java index 68fb71f65c..0eb7876387 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java @@ -80,7 +80,7 @@ public void simpleInitApp() { // set RenderPath currentRenderPath = RenderManager.RenderPath.Forward; - renderManager.setRenderPath(currentRenderPath); + //renderManager.setRenderPath(currentRenderPath); makeHudText(); flyCam.setMoveSpeed(20.0f); @@ -98,7 +98,7 @@ else if(currentRenderPath == RenderManager.RenderPath.TiledDeferred){ else{ currentRenderPath = RenderManager.RenderPath.Deferred; } - renderManager.setRenderPath(currentRenderPath); + //renderManager.setRenderPath(currentRenderPath); hitText.setText("RendererPath : "+ currentRenderPath.getInfo()); } } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java index 6e6908fce1..dcfc1a08b1 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java @@ -138,7 +138,6 @@ public void simpleInitApp() { fpp.addFilter(slsf); viewPort.addProcessor(fpp); - new RenderPathHelper(this); } private float timeElapsed = 0.0f; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 744165ba66..e77a569da3 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -759,7 +759,7 @@ public void done(LightProbe result) { public void onAction(String name, boolean isPressed, float tpf) { if(name.equals("toggleFramegraph") && !isPressed){ bUseFramegraph = !bUseFramegraph; - renderManager.enableFramegraph(bUseFramegraph); + //renderManager.enableFramegraph(bUseFramegraph); } if(name.equals("toggleRenderPath") && !isPressed){ if(currentRenderPath == RenderManager.RenderPath.Deferred){ @@ -771,7 +771,7 @@ else if(currentRenderPath == RenderManager.RenderPath.TiledDeferred){ else{ currentRenderPath = RenderManager.RenderPath.Deferred; } - renderManager.setRenderPath(currentRenderPath); + //renderManager.setRenderPath(currentRenderPath); // getRenderManager().setForcedTechnique(null); hitText.setText("RendererPath : "+ currentRenderPath.getInfo()); } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java index 383ce8566d..a253fdac70 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java @@ -31,7 +31,7 @@ public void simpleInitApp() { // renderManager.setSinglePassLightBatchSize(30); // renderManager.setRenderPath(RenderManager.RenderPath.Forward); renderManager.setMaxDeferredShadingLights(1000); - renderManager.setRenderPath(RenderManager.RenderPath.TiledDeferred); + //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"); From a877d005d98fde2fc59ceb4f02d7bb4590771c40 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:45:47 -0400 Subject: [PATCH 043/111] remove reliance on J3mLoader and clean up code --- .../DeferredSinglePassLightingLogic.java | 6 +- ...eBasedDeferredSinglePassLightingLogic.java | 124 +++++++----------- .../jme3/material/logic/TileInfoProvider.java | 15 +++ .../jme3/material/logic/TiledRenderGrid.java | 88 +++++++++++++ .../java/com/jme3/renderer/RenderManager.java | 120 ++++------------- .../jme3/renderer/framegraph/DepthRange.java | 5 + .../renderer/framegraph/MyFrameGraph.java | 15 +++ .../renderer/framegraph/RenderContext.java | 4 + .../renderer/framegraph/ValueRenderParam.java | 19 ++- .../renderer/pass/DeferredShadingModule.java | 51 +++++-- .../pass/TileDeferredShadingModule.java | 59 +++++---- .../ShadingCommon/DeferredShading.j3md | 4 +- .../TileBasedDeferredShading.j3md | 3 +- .../jme3test/renderpath/TestShadingModel.java | 18 +-- 14 files changed, 315 insertions(+), 216 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/material/logic/TileInfoProvider.java create mode 100644 jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.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 0d42e14291..dd85e1344c 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 @@ -104,9 +104,9 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo private final int probeDefine; private final int ambientDefines; -// public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) { -// this(techniqueDef, true); -// } + public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) { + this(techniqueDef, true); + } public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef, boolean useLightTextures) { super(techniqueDef); this.useLightTextures = useLightTextures; 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 759afa301e..2ecbcd40ec 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 @@ -140,10 +140,8 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe private final 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; + private TileInfoProvider tileProvider; + private TiledRenderGrid tileInfo; // tile light ids private ArrayList> tiles; @@ -157,35 +155,12 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe private ImageRaster lightsDecodeDataUpdateIO; private int lightIndexWidth; - /** - * 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; - 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 *

    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{ + private static class LightFrustum { float left; float right; float top; @@ -199,6 +174,23 @@ public LightFrustum(float left, float right, float top, float bottom) { } } + public TileBasedDeferredSinglePassLightingLogic(TechniqueDef techniqueDef, TileInfoProvider tileProvider) { + super(techniqueDef); + this.tileProvider = tileProvider; + lightIndexWidth = (int)(Math.floor(Math.sqrt(1024))); + singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean); + if(packAsTextures){ + packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int); + packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean); + prepareLightData(1024); + } + else{ + 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); + } + /** * Clear the lightsIndex cache texture for rebuilding. */ @@ -255,25 +247,23 @@ private void cleanupTileTexture(){ * @param tileHeight Number of tiles in vertical direction * @param tileNum tileWidth * tileHeight */ - private void reset(int tileWidth, int tileHeight, int tileNum) { - if (this.tileWidth != tileWidth || this.tileHeight != tileHeight) { + private void reset(boolean gridDemensionsChanged, boolean numTilesChanged) { + if (gridDemensionsChanged) { cleanupTileTexture(); - this.tileWidth = tileWidth; - this.tileHeight = tileHeight; createLightsIndexTexture(lightIndexWidth); - lightsDecodeData = new Texture2D(tileWidth, tileHeight, Image.Format.RGBA32F); + lightsDecodeData = new Texture2D(tileInfo.getGridHeight(), tileInfo.getGridHeight(), 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); + ByteBuffer dataU = BufferUtils.createByteBuffer((int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * tileInfo.getNumTiles()); + Image convertedImageU = new Image(Image.Format.RGBA32F, tileInfo.getGridWidth(), tileInfo.getGridHeight(), dataU, null, ColorSpace.Linear); lightsDecodeData.setImage(convertedImageU); lightsDecodeData.getImage().setMipmapsGenerated(false); lightsDecodeDataUpdateIO = ImageRaster.create(lightsDecodeData.getImage()); } - if(curTileNum != tileNum){ + if (numTilesChanged) { tiles = new ArrayList<>(); - for (int i = 0; i < tileNum; i++) { + for (int i = 0, n = tileInfo.getNumTiles(); i < n; i++) { tiles.add(new ArrayList<>()); } } else for (ArrayList l : tiles) { @@ -564,23 +554,6 @@ private void tileLightDecode(int tileNum, ArrayList> tiles, i g.getMaterial().setTexture(TILE_LIGHT_DECODE, lightsDecodeData); } - - 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(packAsTextures){ - packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int); - packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean); - prepareLightData(1024); - } - else{ - 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(){ if(this.lightData1 != null){ this.lightData1.getImage().dispose(); @@ -940,7 +913,7 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light @Override public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnit) { - int nbRenderedLights = 0; + int renderedLights = 0; Renderer renderer = renderManager.getRenderer(); boolean isLightCullStageDraw = false; if(geometry.getUserData(LIGHT_CULL_DRAW_STAGE) != null){ @@ -959,20 +932,17 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry // 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){ - - // Get tileInfo from RenderManager - tileInfo = renderManager.getTileInfo(); - int tileSize = tileInfo.tileSize; - int tileWidth = tileInfo.tileWidth; - int tileHeight = tileInfo.tileHeight; - int tileNum = tileInfo.tileNum; - Uniform u_tileSize = shader.getUniform(TILE_SIZE); - Uniform u_tileWidth = shader.getUniform(TILE_WIDTH); - Uniform u_tileHeight = shader.getUniform(TILE_HEIGHT); - u_tileSize.setValue(VarType.Int, tileSize); - u_tileWidth.setValue(VarType.Int, tileWidth); - u_tileHeight.setValue(VarType.Int, tileHeight); - reset(tileWidth, tileHeight, tileNum); + + // get render grid info + TiledRenderGrid src = tileProvider.getTiledRenderGrid(); + src.verify(); + boolean gridChanged = tileInfo.gridDemensionsDiffer(src); + boolean numTilesChanged = tileInfo.numTilesDiffer(src); + tileInfo.copyFrom(tileProvider.getTiledRenderGrid()); + shader.getUniform(TILE_SIZE).setValue(VarType.Int, tileInfo.getTileSize()); + shader.getUniform(TILE_WIDTH).setValue(VarType.Int, tileInfo.getGridWidth()); + shader.getUniform(TILE_HEIGHT).setValue(VarType.Int, tileInfo.getGridHeight()); + reset(gridChanged, numTilesChanged); Camera camera = renderManager.getCurrentCamera(); viewPortWidth = camera.getWidth() * 0.5f; @@ -994,27 +964,27 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry 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); + tilesUpdate(tileInfo.getTileSize(), tileInfo.getGridWidth(), tileInfo.getGridHeight(), tileInfo.getNumTiles(), tiles, lightFrustum, i); } else{ // full tilesLight - tilesFullUpdate(tileWidth, tileHeight, tileNum, tiles, i); + tilesFullUpdate(tileInfo.getGridWidth(), tileInfo.getGridHeight(), tileInfo.getNumTiles(), tiles, i); } } // Encode light source information // 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, lastBindUnit.textureUnit); + tileLightDecode(tileInfo.getNumTiles(), tiles, tileInfo.getGridWidth(), tileInfo.getGridHeight(), shader, geometry, lights); + while (renderedLights < count) { + renderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, renderedLights, isLightCullStageDraw, lastBindUnit.textureUnit); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } } else{ // geometry.getMaterial().setInt("NBLight", 0); - nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastBindUnit.textureUnit); + renderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, renderedLights, isLightCullStageDraw, lastBindUnit.textureUnit); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } @@ -1027,8 +997,8 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } else { - while (nbRenderedLights < lights.size()) { - nbRenderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, nbRenderedLights, isLightCullStageDraw); + while (renderedLights < lights.size()) { + renderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, renderedLights, isLightCullStageDraw); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileInfoProvider.java b/jme3-core/src/main/java/com/jme3/material/logic/TileInfoProvider.java new file mode 100644 index 0000000000..ba04db5378 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/logic/TileInfoProvider.java @@ -0,0 +1,15 @@ +/* + * 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.material.logic; + +/** + * + * @author codex + */ +public interface TileInfoProvider { + + public TiledRenderGrid getTiledRenderGrid(); + +} diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java b/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java new file mode 100644 index 0000000000..35cd3a7bd1 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java @@ -0,0 +1,88 @@ +/* + * 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.material.logic; + +import com.jme3.renderer.Camera; + +/** + * + * @author codex + */ +public class TiledRenderGrid { + + private int divisions = 4; + private int forcedTileSize = 64; + private int tileSize = 0; + private int gridWidth = 0; + private int gridHeight = 0; + + public TiledRenderGrid() {} + public TiledRenderGrid(int divisions) { + this.divisions = divisions; + } + + public void update(Camera cam) { + tileSize = (forcedTileSize > 0 ? forcedTileSize : cam.getWidth()/divisions); + int x1 = (int)(cam.getViewPortLeft()*cam.getWidth()); + int y1 = (int)(cam.getViewPortBottom()*cam.getHeight()); + int x2 = (int)(cam.getViewPortRight()*cam.getWidth()); + int y2 = (int)(cam.getViewPortTop()*cam.getHeight()); + gridWidth = (x2-x1)/tileSize; + gridHeight = (y2-y1)/tileSize; + } + + public void setNumDivisions(int divisions) { + this.divisions = divisions; + } + public void setForcedTileSize(int forcedTileSize) { + this.forcedTileSize = forcedTileSize; + } + public void copyFrom(TiledRenderGrid src) { + setNumDivisions(src.divisions); + setForcedTileSize(src.forcedTileSize); + tileSize = src.tileSize; + gridWidth = src.gridWidth; + gridHeight = src.gridHeight; + } + + public int getNumDivisions() { + return divisions; + } + public int getForcedTileSize() { + return forcedTileSize; + } + public int getTileSize() { + return tileSize; + } + public int getGridWidth() { + return gridWidth; + } + public int getGridHeight() { + return gridHeight; + } + public int getNumTiles() { + return gridWidth*gridHeight; + } + + public boolean gridPropertiesDiffer(TiledRenderGrid grid) { + return grid.tileSize != tileSize || gridDemensionsDiffer(grid); + } + public boolean gridDemensionsDiffer(TiledRenderGrid grid) { + return grid.gridWidth != gridWidth || grid.gridHeight != gridHeight; + } + public boolean numTilesDiffer(TiledRenderGrid grid) { + return grid.getNumTiles() != getNumTiles(); + } + + public void verify() { + if (tileSize <= 0) { + throw new IllegalStateException("Tile size cannot be less than or equal to zero."); + } + if (gridWidth <= 0 || gridHeight <= 0) { + throw new IllegalStateException("Grid demensions cannot be negative."); + } + } + +} 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 2a1dead153..eeac296321 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -86,10 +86,6 @@ public class RenderManager { private GeometryRenderHandler renderGeometry; private MyFrameGraph myFrameGraph; private int maxDeferredLights = 1024; - private TileBasedDeferredSinglePassLightingLogic.TileInfo tileInfo; - private int forceTileSize = 64; - private int curTileSize = -1; - private int numberTileDivisions = 4; // RenderPath public enum RenderPath { @@ -150,105 +146,46 @@ public RenderManager(Renderer renderer) { this.renderer = renderer; this.forcedOverrides.add(boundDrawBufferId); } - - /** - * 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.
    - * 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) { - this.forceTileSize = forceTileSize; - } - - public int getForceTileSize() { - return forceTileSize; - } /** - * Sets the framegraph used in the rendering process. + * Sets the framegraph used for rendering if the rendered viewport + * has no framegraph assigned. * - * @param frameGraph + * @param frameGraph default framegraph, or null to not use a framegraph by default for rendering */ public void setFrameGraph(MyFrameGraph frameGraph) { this.myFrameGraph = frameGraph; } - - /** - * 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 maxDeferredLights default value 1024 - */ - public void setMaxDeferredShadingLights(int maxDeferredLights) { - this.maxDeferredLights = maxDeferredLights; - } - - public int getMaxDeferredShadingLights() { - return maxDeferredLights; - } - - /** - * 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 void setTileInfo(int tileSize, int tileWidth, int tileHeight, int tileNum){ - if(tileInfo == null){ - tileInfo = new TileBasedDeferredSinglePassLightingLogic.TileInfo(tileSize, tileWidth, tileHeight, tileNum); - } - } /** - * Calculates tiling info. - */ - public void calculateTileInfo() { - curTileSize = (forceTileSize > 0 ? forceTileSize : (getCurrentCamera().getWidth() / numberTileDivisions)); - int tileWidth = viewWidth / curTileSize; - int tileHeight = viewHeight / curTileSize; - setTileInfo(curTileSize, tileWidth, tileHeight, tileWidth * tileHeight); - } - - /** - * update tile size.
    - * @param tileSize + * Gets the framegraph used for rendering if the rendered viewport + * has no framegraph assigned. + * + * @return default framegraph, or null if framegraphs are not used by default for rendering */ - public final void updateTileSize(int tileSize){ - if(curTileSize == tileSize)return; - curTileSize = tileSize; - } - - public TileBasedDeferredSinglePassLightingLogic.TileInfo getTileInfo() { - return tileInfo; + public MyFrameGraph getFrameGraph() { + return myFrameGraph; } /** - * Set an IRenderGeometry for executing drawing call interfaces for the specified FGPass. + * Sets the GeometryRenderHandler used to render geometry. * - * @param renderGeometry + * @param renderGeometry geometry render handler, or null to not use one for rendering * @see GeometryRenderHandler */ - public final void setGeometryRenderHandler(GeometryRenderHandler renderGeometry){ + public void setGeometryRenderHandler(GeometryRenderHandler renderGeometry){ this.renderGeometry = renderGeometry; } - + + /** + * Gest the GeometryRenderHandler used to render geometry. + * + * @return geometry render handler, or null of none is used for rendering + */ public GeometryRenderHandler getGeometryRenderHandler() { return renderGeometry; } - /** * Returns the pre ViewPort with the given name. * @@ -906,7 +843,7 @@ public void preloadScene(Spatial scene) { } } } - + /** * Flattens the given scene graph into the ViewPort's RenderQueue, * checking for culling as the call goes down the graph recursively. @@ -937,11 +874,11 @@ public void preloadScene(Spatial scene) { * contain the flattened scene graph. */ public void renderScene(Spatial scene, ViewPort vp) { - //reset of the camera plane state for proper culling - //(must be 0 for the first note of the scene to be rendered) + // reset of the camera plane state for proper culling + // (must be 0 for the first note of the scene to be rendered) vp.getCamera().setPlaneState(0); - //rendering the scene - renderSubScene(scene, vp); + // queue the scene for rendering + queueSubScene(scene, vp); } /** @@ -950,13 +887,11 @@ public void renderScene(Spatial scene, ViewPort vp) { * @param scene the scene to be rendered (not null) * @param vp the ViewPort to render in (not null) */ - private void renderSubScene(Spatial scene, ViewPort vp) { - - // check culling first. + private void queueSubScene(Spatial scene, ViewPort vp) { + // check culling first if (!scene.checkCulling(vp.getCamera())) { return; } - scene.runControlRender(this, vp); if (scene instanceof Node) { // Recurse for all children @@ -967,7 +902,7 @@ private void renderSubScene(Spatial scene, ViewPort vp) { for (int i = 0; i < children.size(); i++) { // Restoring cam state before proceeding children recursively vp.getCamera().setPlaneState(camState); - renderSubScene(children.get(i), vp); + queueSubScene(children.get(i), vp); } } else if (scene instanceof Geometry) { // add to the render queue @@ -975,7 +910,6 @@ private void renderSubScene(Spatial scene, ViewPort vp) { if (gm.getMaterial() == null) { throw new IllegalStateException("No material is set for Geometry: " + gm.getName()); } - vp.getQueue().addToQueue(gm, scene.getQueueBucket()); } } @@ -1334,7 +1268,7 @@ public void renderViewPort(ViewPort vp, float tpf) { if (fg != null) { - fg.getContext().update(vp, prof, tpf); + fg.prepareRender(vp, prof, tpf); fg.preFrame(); } else if (processors != null) { 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 index b77adb5437..6ec288ea83 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java @@ -82,4 +82,9 @@ public int hashCode() { return hash; } + @Override + public String toString() { + return "DepthRange["+start+" -> "+end+"]"; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java index d6f693c82b..9761816607 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java @@ -4,7 +4,9 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.profile.AppProfiler; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; import java.util.LinkedList; /** @@ -21,6 +23,10 @@ public MyFrameGraph(RenderManager renderManager) { context = new RenderContext(renderManager); } + public void prepareRender(ViewPort vp, AppProfiler prof, float tpf) { + context.update(vp, prof, tpf); + } + public void preFrame() { for (FGModule p : passes) { p.preFrame(context); @@ -63,6 +69,15 @@ public void add(FGModule pass) { registerParameterGroup(pass); } + public T get(Class type) { + for (FGModule p : passes) { + if (type.isAssignableFrom(p.getClass())) { + return (T)p; + } + } + return null; + } + public ParameterManager getParameters() { return parameters; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java index b39a331b47..71cfc4d10d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java @@ -87,6 +87,10 @@ public void setDepthRange(DepthRange depth) { } } + public DepthRange getDepthRange() { + return depth; + } + public RenderManager getRenderManager() { return renderManager; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java index 7a135a8a5a..dbfa6154ab 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java @@ -13,13 +13,18 @@ public class ValueRenderParam implements RenderParameter { private final String name; private T value; + private T defaultValue; public ValueRenderParam(String name) { - this(name, null); + this(name, null, null); } public ValueRenderParam(String name, T value) { + this(name, value, null); + } + public ValueRenderParam(String name, T value, T defaultValue) { this.name = name; this.value = value; + this.defaultValue = defaultValue; } @Override @@ -32,7 +37,19 @@ public void accept(T value) { } @Override public T produce() { + return (value != null ? value : defaultValue); + } + + public T produceRaw() { return value; } + public void setDefaultValue(T defaultValue) { + this.defaultValue = defaultValue; + } + + public T getDefaultValue() { + return defaultValue; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java index 73f7d603ed..8c1af194b4 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java @@ -10,6 +10,9 @@ import com.jme3.material.RenderState; import com.jme3.material.TechniqueDef; import com.jme3.material.logic.DeferredSinglePassLightingLogic; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.AbstractModule; import com.jme3.renderer.framegraph.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; @@ -36,7 +39,7 @@ public class DeferredShadingModule extends AbstractModule { public final static String EXECUTE_STATE = "DeferredShadingPass.ExecuteState"; public final static String IN_FRAME_BUFFER = "DeferredShadingPass.InFrameBuffer"; public final static String DEPTH_DEBUG = "DeferredShadingPass.DepthDebug"; - protected final static String DEFERRED_PASS = "DeferredPass"; + private final static String PASS = "DeferredPass"; private static final String MATDEF = "Common/MatDefs/ShadingCommon/DeferredShading.j3md"; protected final AssetManager assetManager; @@ -65,16 +68,14 @@ public void initialize(MyFrameGraph frameGraph) { screenRect.setMaterial(screenMat); RenderState rs = screenMat.getAdditionalRenderState(); - rs.setDepthWrite(!true); + rs.setDepthWrite(true); rs.setDepthTest(true); rs.setDepthFunc(RenderState.TestFunction.Greater); //rs.setBlendMode(RenderState.BlendMode.Alpha); //screenMat.setTransparent(true); screenMat.setBoolean("UseLightsCullMode", false); - TechniqueDef techDef = screenMat.getMaterialDef().getTechniqueDefs(DEFERRED_PASS).get(0); - logic = new DeferredSinglePassLightingLogic(techDef, true); - techDef.setLogic(logic); + assignTechniqueLogic(screenMat); // material render parameters automatically apply their values matParams[0] = addParameter(new MatRenderParam(RT_0, screenMat, VarType.Texture2D)); @@ -85,7 +86,6 @@ public void initialize(MyFrameGraph frameGraph) { lightList = addParameter(new ValueRenderParam<>(LIGHT_DATA)); executeState = addParameter(new ValueRenderParam<>(EXECUTE_STATE)); gBuffer = addParameter(new ValueRenderParam<>(IN_FRAME_BUFFER)); - depthCopy = addParameter(new TextureTargetParam(DEPTH_DEBUG, null)); bindParameters(frameGraph); @@ -103,18 +103,22 @@ public void prepare(RenderContext context) { } @Override public void execute(RenderContext context) { - + context.getRenderer().copyFrameBuffer(gBuffer.produce(), context.getViewPort().getOutputFrameBuffer(), false, true); context.getRenderer().copyFrameBuffer(gBuffer.produce(), debug, false, true); + //makeRenderStateTests(context, "pre tests"); + selectTechnique(screenMat, context.getRenderManager()); context.setDepthRange(1, 1); - screenMat.selectTechnique(DEFERRED_PASS, context.getRenderManager()); + context.getRenderer().setFrameBuffer(context.getViewPort().getOutputFrameBuffer()); screenRect.updateGeometricState(); context.getRenderManager().renderGeometry(screenRect, lightList.produce()); //screenMat.render(screenRect, lightList.produce(), context.getRenderManager()); + //makeRenderStateTests(context, "post tests"); + } @Override public void reset() {} @@ -130,5 +134,36 @@ protected void bindParameters(MyFrameGraph frameGraph) { frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, gBuffer); } + protected void assignTechniqueLogic(Material material) { + for (TechniqueDef t : screenMat.getMaterialDef().getTechniqueDefs(PASS)) { + t.setLogic(new DeferredSinglePassLightingLogic(t, true)); + } + } + protected void selectTechnique(Material mat, RenderManager rm) { + mat.selectTechnique(PASS, rm); + } + + private void makeRenderStateTests(RenderContext context, String label) { + Renderer r = context.getRenderer(); + RenderManager rm = context.getRenderManager(); + ViewPort vp = context.getViewPort(); + System.out.println(label+":"); + test(r.getCurrentFrameBuffer(), "framebuffer"); + test(context.getDepthRange(), "depth"); + test(rm.getCurrentCamera(), "camera"); + test(rm.getGeometryRenderHandler(), "handler"); + test(rm.getRenderFilter(), "geometry filter"); + test(rm.getPreferredLightMode(), "preferred light mode"); + test(rm.getForcedTechnique(), "forced technique"); + test(rm.getForcedRenderState(), "forced renderstate"); + test(rm.getForcedMatParams().size(), "num forced mat params"); + test(rm.getLightFilter(), "light filter"); + test(vp.getBackgroundColor(), "viewport background"); + test(vp.getOutputFrameBuffer(), "viewport output framebuffer"); + test("color:"+vp.isClearColor()+", depth:"+vp.isClearDepth()+", stencil:"+vp.isClearStencil(), "viewport clear flags"); + } + private void test(Object object, String label) { + System.out.println(" "+label+" = "+(object == null ? "null" : object.toString().replaceAll("\n", "; "))); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java index e546138beb..0d4677e848 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java @@ -6,49 +6,62 @@ import com.jme3.asset.AssetManager; import com.jme3.material.Material; -import com.jme3.renderer.Camera; +import com.jme3.material.TechniqueDef; +import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic; +import com.jme3.material.logic.TileInfoProvider; +import com.jme3.material.logic.TiledRenderGrid; +import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.framegraph.ValueRenderParam; +import java.util.LinkedList; /** * * @author codex */ -public class TileDeferredShadingModule extends DeferredShadingModule { +public class TileDeferredShadingModule extends DeferredShadingModule implements TileInfoProvider { + public static final String TILE_INFO = "TileDeferredShading.TileInfo"; private static final String MATDEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"; - protected final static String PASS = "TileBasedDeferredPass"; + private static final String PASS = "TileBasedDeferredPass"; + + private ValueRenderParam tileInfo; + private final LinkedList logic = new LinkedList<>(); public TileDeferredShadingModule(AssetManager assetManager) { super(assetManager); } + @Override + public void initialize(MyFrameGraph frameGraph) { + super.initialize(frameGraph); + tileInfo = addParameter(new ValueRenderParam<>(TILE_INFO, null, new TiledRenderGrid())); + } + @Override + public void prepare(RenderContext context) { + super.prepare(context); + //context.getRenderManager().calculateTileInfo(); + } + @Override + public void execute(RenderContext context) { + tileInfo.produce().update(context.getRenderManager().getCurrentCamera()); + super.execute(context); + } @Override protected Material createMaterial() { return new Material(assetManager, MATDEF); } - @Override - public void execute(RenderContext context) { - - // Handle FullScreenLights - screenMat.selectTechnique(PASS, context.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, lightList.produce(), context.getRenderManager()); - screenMat.getAdditionalRenderState().setDepthTest(depthTest); - screenMat.getAdditionalRenderState().setDepthWrite(depthWrite); - - // Handle non-fullscreen lights + protected void assignTechniqueLogic(Material mat) { + for (TechniqueDef t : mat.getMaterialDef().getTechniqueDefs(PASS)) { + TileBasedDeferredSinglePassLightingLogic l = new TileBasedDeferredSinglePassLightingLogic(t, this); + logic.add(l); + t.setLogic(l); + } } - @Override - public void prepare(RenderContext context) { - super.prepare(context); - context.getRenderManager().calculateTileInfo(); + public TiledRenderGrid getTiledRenderGrid() { + return tileInfo.produce(); } } 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 265bab64b9..d89b62495a 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md @@ -20,9 +20,9 @@ MaterialDef DeferredShading { Texture2D LightPackData3 } - Technique DeferredPass{ + 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 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 98a0b58a98..84abdc4aee 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md @@ -24,7 +24,8 @@ MaterialDef DeferredShading { Texture2D TileLightIndex } - Technique TileBasedDeferredPass{ + Technique TileBasedDeferredPass { + Pipeline Deferred LightMode TileBasedDeferredSinglePass diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index 690584d41d..c204951ac7 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -2,12 +2,10 @@ import com.jme3.app.SimpleApplication; import com.jme3.asset.AssetManager; -import com.jme3.environment.EnvironmentCamera; import com.jme3.environment.EnvironmentProbeControl; import com.jme3.light.AmbientLight; import com.jme3.light.DirectionalLight; import com.jme3.material.Material; -import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; @@ -27,8 +25,8 @@ import com.jme3.scene.shape.Sphere; import com.jme3.shader.VarType; import com.jme3.shadow.DirectionalLightShadowRenderer; +import com.jme3.system.AppSettings; import com.jme3.texture.plugins.ktx.KTXLoader; -import com.jme3.ui.Picture; import com.jme3.util.SkyFactory; import com.jme3.util.TangentBinormalGenerator; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; @@ -48,6 +46,15 @@ public class TestShadingModel extends SimpleApplication { private Geometry model; private Node tex; + public static void main(String[] args) { + TestShadingModel app = new TestShadingModel(); + AppSettings settings = new AppSettings(true); + //settings.setGraphicsDebug(true); + //settings.setGraphicsTrace(true); + app.setSettings(settings); + app.start(); + } + @Override public void simpleInitApp() { @@ -157,11 +164,6 @@ public void simpleRender(RenderManager rm) { rootNode.attachChild(modelNode); } } - - public static void main(String[] args) { - TestShadingModel testShadingModel = new TestShadingModel(); - testShadingModel.start(); - } private class DepthDebugFilter extends Filter { From fcfaa2ba5fd84e04c601854a0270bae172f67717 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:51:15 -0400 Subject: [PATCH 044/111] reorganized java files --- .../java/com/jme3/renderer/RenderManager.java | 5 +++++ .../jme3/renderer/framegraph/AbstractModule.java | 1 + .../com/jme3/renderer/framegraph/FGModule.java | 2 ++ .../renderer/framegraph/FrameBufferCopyParam.java | 1 + .../renderer/framegraph/FrameBufferParam.java | 1 + .../jme3/renderer/framegraph/GraphBuilder.java | 15 --------------- .../jme3/renderer/framegraph/MyFrameGraph.java | 4 ++++ .../framegraph/RenderPipelineFactory.java | 12 ++++++------ .../{ => parameters}/MatRenderParam.java | 3 ++- .../{ => parameters}/ParameterBinding.java | 3 ++- .../{ => parameters}/ParameterManager.java | 3 ++- .../{ => parameters}/RenderParameter.java | 2 +- .../{ => parameters}/RenderParameterGroup.java | 3 ++- .../{ => parameters}/TextureTargetParam.java | 2 +- .../{ => parameters}/ValueRenderParam.java | 2 +- .../pass/BackgroundScreenTestModule.java | 2 +- .../pass/DeferredShadingModule.java | 8 ++++---- .../{ => framegraph}/pass/ForwardModule.java | 2 +- .../{ => framegraph}/pass/GBufferModule.java | 8 +++++--- .../pass/PostProcessingModule.java | 2 +- .../pass/TileDeferredShadingModule.java | 5 +++-- .../java/com/jme3/renderer/pass/GuiModule.java | 1 + .../jme3test/renderpath/TestShadingModel.java | 4 ++-- .../renderpath/TestSimpleDeferredLighting.java | 4 ++-- 24 files changed, 51 insertions(+), 44 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphBuilder.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => parameters}/MatRenderParam.java (92%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => parameters}/ParameterBinding.java (89%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => parameters}/ParameterManager.java (97%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => parameters}/RenderParameter.java (97%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => parameters}/RenderParameterGroup.java (76%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => parameters}/TextureTargetParam.java (96%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => parameters}/ValueRenderParam.java (96%) rename jme3-core/src/main/java/com/jme3/renderer/{ => framegraph}/pass/BackgroundScreenTestModule.java (97%) rename jme3-core/src/main/java/com/jme3/renderer/{ => framegraph}/pass/DeferredShadingModule.java (96%) rename jme3-core/src/main/java/com/jme3/renderer/{ => framegraph}/pass/ForwardModule.java (97%) rename jme3-core/src/main/java/com/jme3/renderer/{ => framegraph}/pass/GBufferModule.java (96%) rename jme3-core/src/main/java/com/jme3/renderer/{ => framegraph}/pass/PostProcessingModule.java (98%) rename jme3-core/src/main/java/com/jme3/renderer/{ => framegraph}/pass/TileDeferredShadingModule.java (93%) 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 eeac296321..2c3984492f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -150,6 +150,9 @@ public RenderManager(Renderer renderer) { /** * Sets the framegraph used for rendering if the rendered viewport * has no framegraph assigned. + *

    + * If this framegraph is null, and the viewport currently being rendered has + * no framegraph assigned, JME's legacy forward rendering method will be used. * * @param frameGraph default framegraph, or null to not use a framegraph by default for rendering */ @@ -169,6 +172,8 @@ public MyFrameGraph getFrameGraph() { /** * Sets the GeometryRenderHandler used to render geometry. + *

    + * default=null * * @param renderGeometry geometry render handler, or null to not use one for rendering * @see GeometryRenderHandler 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 index bd926cbcd3..84cd2713d5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.parameters.RenderParameter; import java.util.Collection; import java.util.LinkedList; 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 index 1412712e0a..75fa365650 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java @@ -4,6 +4,8 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.parameters.RenderParameterGroup; + /** * * @author codex diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java index 1444ebfd12..ed86ef05e3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.parameters.RenderParameter; import com.jme3.renderer.Renderer; import com.jme3.texture.FrameBuffer; 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 index b16f1f3399..c5aed76253 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferParam.java @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.parameters.ValueRenderParam; import com.jme3.texture.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 deleted file mode 100644 index a1d1b97468..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphBuilder.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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/framegraph/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java index 9761816607..dbd38e80ee 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java @@ -4,6 +4,10 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.parameters.RenderParameterGroup; +import com.jme3.renderer.framegraph.parameters.ParameterBinding; +import com.jme3.renderer.framegraph.parameters.ParameterManager; +import com.jme3.renderer.framegraph.parameters.RenderParameter; import com.jme3.profile.AppProfiler; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java index 886926d5c0..a889496ffc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java @@ -8,13 +8,13 @@ import com.jme3.asset.AssetManager; import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager.RenderPath; -import com.jme3.renderer.pass.BackgroundScreenTestModule; -import com.jme3.renderer.pass.DeferredShadingModule; -import com.jme3.renderer.pass.ForwardModule; -import com.jme3.renderer.pass.GBufferModule; +import com.jme3.renderer.framegraph.pass.BackgroundScreenTestModule; +import com.jme3.renderer.framegraph.pass.DeferredShadingModule; +import com.jme3.renderer.framegraph.pass.ForwardModule; +import com.jme3.renderer.framegraph.pass.GBufferModule; import com.jme3.renderer.pass.GuiModule; -import com.jme3.renderer.pass.PostProcessingModule; -import com.jme3.renderer.pass.TileDeferredShadingModule; +import com.jme3.renderer.framegraph.pass.PostProcessingModule; +import com.jme3.renderer.framegraph.pass.TileDeferredShadingModule; /** * Constructs basic framegraphs. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java similarity index 92% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java index e15f1fed66..a5f72417d7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java @@ -2,8 +2,9 @@ * 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; +package com.jme3.renderer.framegraph.parameters; +import com.jme3.renderer.framegraph.parameters.RenderParameter; import com.jme3.material.Material; import com.jme3.shader.VarType; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterBinding.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java similarity index 89% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterBinding.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java index 507662c1cc..5669aee35f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterBinding.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java @@ -2,8 +2,9 @@ * 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; +package com.jme3.renderer.framegraph.parameters; +import com.jme3.renderer.framegraph.parameters.RenderParameter; import java.util.Objects; /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterManager.java similarity index 97% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterManager.java index e9bf039db1..48618520ae 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterManager.java @@ -2,8 +2,9 @@ * 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; +package com.jme3.renderer.framegraph.parameters; +import com.jme3.renderer.framegraph.parameters.RenderParameter; import java.util.Iterator; import java.util.LinkedList; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java similarity index 97% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java index 97fad0b92e..181f47eebf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java @@ -2,7 +2,7 @@ * 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; +package com.jme3.renderer.framegraph.parameters; /** * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameterGroup.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameterGroup.java similarity index 76% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameterGroup.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameterGroup.java index 9453f2386e..315f1fa144 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameterGroup.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameterGroup.java @@ -2,8 +2,9 @@ * 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; +package com.jme3.renderer.framegraph.parameters; +import com.jme3.renderer.framegraph.parameters.RenderParameter; import java.util.Collection; /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureTargetParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java similarity index 96% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureTargetParam.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java index 494a5b7ea1..311a9a73b3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureTargetParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java @@ -2,7 +2,7 @@ * 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; +package com.jme3.renderer.framegraph.parameters; import com.jme3.texture.FrameBuffer.FrameBufferTextureTarget; import com.jme3.texture.Texture; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java similarity index 96% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java index dbfa6154ab..0321b6e224 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java @@ -2,7 +2,7 @@ * 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; +package com.jme3.renderer.framegraph.parameters; /** * diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/BackgroundScreenTestModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java similarity index 97% rename from jme3-core/src/main/java/com/jme3/renderer/pass/BackgroundScreenTestModule.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java index 7de42ac0da..6dcf1930d6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/BackgroundScreenTestModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java @@ -2,7 +2,7 @@ * 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.pass; +package com.jme3.renderer.framegraph.pass; import com.jme3.asset.AssetManager; import com.jme3.material.Material; diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java similarity index 96% rename from jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java index 8c1af194b4..8f49e6b0d2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java @@ -2,7 +2,7 @@ * 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.pass; +package com.jme3.renderer.framegraph.pass; import com.jme3.asset.AssetManager; import com.jme3.light.LightList; @@ -14,11 +14,11 @@ import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.AbstractModule; -import com.jme3.renderer.framegraph.MatRenderParam; +import com.jme3.renderer.framegraph.parameters.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.TextureTargetParam; -import com.jme3.renderer.framegraph.ValueRenderParam; +import com.jme3.renderer.framegraph.parameters.TextureTargetParam; +import com.jme3.renderer.framegraph.parameters.ValueRenderParam; import com.jme3.shader.VarType; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture2D; diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java similarity index 97% rename from jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java index 66d45d5dcc..81049a564c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java @@ -2,7 +2,7 @@ * 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.pass; +package com.jme3.renderer.framegraph.pass; import com.jme3.renderer.RenderManager; import com.jme3.renderer.framegraph.AbstractModule; diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java similarity index 96% rename from jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java index 550168a8fb..d450130891 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java @@ -2,8 +2,9 @@ * 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.pass; +package com.jme3.renderer.framegraph.pass; +import com.jme3.renderer.framegraph.pass.ForwardModule; import com.jme3.light.Light; import com.jme3.light.LightList; import com.jme3.material.Material; @@ -13,8 +14,9 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.TextureTargetParam; -import com.jme3.renderer.framegraph.ValueRenderParam; +import com.jme3.renderer.framegraph.parameters.TextureTargetParam; +import com.jme3.renderer.framegraph.parameters.ValueRenderParam; +import com.jme3.renderer.pass.GeometryRenderHandler; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java similarity index 98% rename from jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java index 04765f04ed..fef745ed4b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java @@ -2,7 +2,7 @@ * 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.pass; +package com.jme3.renderer.framegraph.pass; import com.jme3.post.SceneProcessor; import com.jme3.profile.AppProfiler; diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java similarity index 93% rename from jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java index 0d4677e848..3f8fd5dafa 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java @@ -2,8 +2,9 @@ * 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.pass; +package com.jme3.renderer.framegraph.pass; +import com.jme3.renderer.framegraph.pass.DeferredShadingModule; import com.jme3.asset.AssetManager; import com.jme3.material.Material; import com.jme3.material.TechniqueDef; @@ -12,7 +13,7 @@ import com.jme3.material.logic.TiledRenderGrid; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.ValueRenderParam; +import com.jme3.renderer.framegraph.parameters.ValueRenderParam; import java.util.LinkedList; /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java index bc154d85c2..9d6e9e0d6c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java @@ -4,6 +4,7 @@ */ package com.jme3.renderer.pass; +import com.jme3.renderer.framegraph.pass.ForwardModule; import com.jme3.renderer.Camera; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.RenderContext; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index c204951ac7..1a35b60f1a 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -13,10 +13,10 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.MatRenderParam; +import com.jme3.renderer.framegraph.parameters.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderPipelineFactory; -import com.jme3.renderer.pass.DeferredShadingModule; +import com.jme3.renderer.framegraph.pass.DeferredShadingModule; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index e77a569da3..d56e11d520 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -53,10 +53,10 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.MatRenderParam; +import com.jme3.renderer.framegraph.parameters.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderPipelineFactory; -import com.jme3.renderer.pass.GBufferModule; +import com.jme3.renderer.framegraph.pass.GBufferModule; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; From 7eab19e590e23e2f674d83a304a9adfbef026191 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:22:50 -0400 Subject: [PATCH 045/111] added support for cross-space parameter binding --- ...eBasedDeferredSinglePassLightingLogic.java | 66 +++-- .../jme3/material/logic/TiledRenderGrid.java | 13 +- .../java/com/jme3/renderer/RenderManager.java | 18 +- .../framegraph/FrameBufferCopyParam.java | 4 +- .../renderer/framegraph/MyFrameGraph.java | 105 ++++++- .../framegraph/parameters/MatRenderParam.java | 4 +- .../parameters/ParameterBinding.java | 50 +++- .../parameters/ParameterManager.java | 129 --------- .../framegraph/parameters/ParameterSpace.java | 261 ++++++++++++++++++ .../parameters/RenderParameter.java | 16 +- .../parameters/TextureTargetParam.java | 4 +- .../parameters/ValueRenderParam.java | 4 +- .../parameters/WorldRenderParam.java | 70 +++++ .../pass/DeferredShadingModule.java | 6 +- .../framegraph/pass/ForwardModule.java | 3 - .../framegraph/pass/GBufferModule.java | 2 +- .../pass/TileDeferredShadingModule.java | 20 +- 17 files changed, 562 insertions(+), 213 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterManager.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterSpace.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/WorldRenderParam.java 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 2ecbcd40ec..b07bc1cd98 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 @@ -92,6 +92,7 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe // 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 packAsTextures = true; // Use textures to store large amounts of light data at once, avoiding multiple draw calls private Texture2D lightData1; @@ -140,8 +141,10 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe private final LightFrustum _lightFrustum = new LightFrustum(0, 0, 0, 0); // tile info - private TileInfoProvider tileProvider; - private TiledRenderGrid tileInfo; + private final TiledRenderGrid tileInfo; + private final TiledRenderGrid prevTileInfo = new TiledRenderGrid(); + private int maxLights = 1024; + private boolean updateLightDataFlag = true; // tile light ids private ArrayList> tiles; @@ -174,9 +177,9 @@ public LightFrustum(float left, float right, float top, float bottom) { } } - public TileBasedDeferredSinglePassLightingLogic(TechniqueDef techniqueDef, TileInfoProvider tileProvider) { + public TileBasedDeferredSinglePassLightingLogic(TechniqueDef techniqueDef, TiledRenderGrid tileInfo) { super(techniqueDef); - this.tileProvider = tileProvider; + this.tileInfo = tileInfo; lightIndexWidth = (int)(Math.floor(Math.sqrt(1024))); singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean); if(packAsTextures){ @@ -247,8 +250,8 @@ private void cleanupTileTexture(){ * @param tileHeight Number of tiles in vertical direction * @param tileNum tileWidth * tileHeight */ - private void reset(boolean gridDemensionsChanged, boolean numTilesChanged) { - if (gridDemensionsChanged) { + private void reset() { + if (tileInfo.gridDemensionsDiffer(prevTileInfo)) { cleanupTileTexture(); createLightsIndexTexture(lightIndexWidth); lightsDecodeData = new Texture2D(tileInfo.getGridHeight(), tileInfo.getGridHeight(), Image.Format.RGBA32F); @@ -261,7 +264,7 @@ private void reset(boolean gridDemensionsChanged, boolean numTilesChanged) { lightsDecodeData.getImage().setMipmapsGenerated(false); lightsDecodeDataUpdateIO = ImageRaster.create(lightsDecodeData.getImage()); } - if (numTilesChanged) { + if (tileInfo.numTilesDiffer(prevTileInfo)) { tiles = new ArrayList<>(); for (int i = 0, n = tileInfo.getNumTiles(); i < n; i++) { tiles.add(new ArrayList<>()); @@ -920,9 +923,10 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry isLightCullStageDraw = geometry.getUserData(LIGHT_CULL_DRAW_STAGE); } if(packAsTextures){ - if(this.lightNum != renderManager.getMaxDeferredShadingLights()){ + if(updateLightDataFlag){ cleanupLightData(); - prepareLightData(renderManager.getMaxDeferredShadingLights()); + prepareLightData(maxLights); + updateLightDataFlag = false; } useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true); int count = lights.size(); @@ -931,18 +935,15 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry // 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){ + if (count > 0) { // get render grid info - TiledRenderGrid src = tileProvider.getTiledRenderGrid(); - src.verify(); - boolean gridChanged = tileInfo.gridDemensionsDiffer(src); - boolean numTilesChanged = tileInfo.numTilesDiffer(src); - tileInfo.copyFrom(tileProvider.getTiledRenderGrid()); + tileInfo.verifyUpdated(); shader.getUniform(TILE_SIZE).setValue(VarType.Int, tileInfo.getTileSize()); shader.getUniform(TILE_WIDTH).setValue(VarType.Int, tileInfo.getGridWidth()); shader.getUniform(TILE_HEIGHT).setValue(VarType.Int, tileInfo.getGridHeight()); - reset(gridChanged, numTilesChanged); + reset(); + prevTileInfo.copyFrom(tileInfo); Camera camera = renderManager.getCurrentCamera(); viewPortWidth = camera.getWidth() * 0.5f; @@ -958,38 +959,37 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry camUp.set(matArray1[4], matArray1[5], matArray1[6], 1.0f); // update tiles - LightFrustum lightFrustum = null; - for(int i = 0;i < count;i++){ + LightFrustum lightFrustum; + 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; + if (lights.get(i).getType() == Light.Type.Ambient || lights.get(i).getType() == Light.Type.Probe) { + continue; + } lightFrustum = lightClip(lights.get(i)); - if(lightFrustum != null){ + if (lightFrustum != null) { tilesUpdate(tileInfo.getTileSize(), tileInfo.getGridWidth(), tileInfo.getGridHeight(), tileInfo.getNumTiles(), tiles, lightFrustum, i); - } - else{ + } else { // full tilesLight tilesFullUpdate(tileInfo.getGridWidth(), tileInfo.getGridHeight(), tileInfo.getNumTiles(), tiles, i); } } // Encode light source information -// lightCount.setValue(VarType.Int, count); -// geometry.getMaterial().setInt("NBLight", count); + //lightCount.setValue(VarType.Int, count); + //geometry.getMaterial().setInt("NBLight", count); tileLightDecode(tileInfo.getNumTiles(), tiles, tileInfo.getGridWidth(), tileInfo.getGridHeight(), shader, geometry, lights); while (renderedLights < count) { renderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, renderedLights, isLightCullStageDraw, lastBindUnit.textureUnit); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } - } - else{ -// geometry.getMaterial().setInt("NBLight", 0); + } else { + //geometry.getMaterial().setInt("NBLight", 0); renderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, renderedLights, isLightCullStageDraw, lastBindUnit.textureUnit); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } - } - else{ + } else { // Do not use this branch, but keep it for possible future use int batchSize = renderManager.getSinglePassLightBatchSize(); if (lights.size() == 0) { @@ -1005,4 +1005,12 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry } } } + + public void setMaxLights(int maxLights) { + if (this.maxLights != maxLights) { + this.maxLights = maxLights; + updateLightDataFlag = true; + } + } + } diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java b/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java index 35cd3a7bd1..559742f09b 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java @@ -34,6 +34,7 @@ public void update(Camera cam) { } public void setNumDivisions(int divisions) { + assert divisions > 0 : "Number of divisions must be greater than zero."; this.divisions = divisions; } public void setForcedTileSize(int forcedTileSize) { @@ -76,13 +77,13 @@ public boolean numTilesDiffer(TiledRenderGrid grid) { return grid.getNumTiles() != getNumTiles(); } - public void verify() { - if (tileSize <= 0) { - throw new IllegalStateException("Tile size cannot be less than or equal to zero."); - } - if (gridWidth <= 0 || gridHeight <= 0) { - throw new IllegalStateException("Grid demensions cannot be negative."); + public void verifyUpdated() { + if (needsUpdate()) { + throw new IllegalStateException("Update is required before use."); } } + public boolean needsUpdate() { + return tileSize <= 0 || gridWidth <= 0 || gridHeight <= 0; + } } 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 2c3984492f..426106fffe 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -40,7 +40,6 @@ 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; @@ -48,6 +47,7 @@ import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.parameters.ParameterSpace; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; @@ -82,10 +82,6 @@ * @see Spatial */ public class RenderManager { - - private GeometryRenderHandler renderGeometry; - private MyFrameGraph myFrameGraph; - private int maxDeferredLights = 1024; // RenderPath public enum RenderPath { @@ -115,12 +111,15 @@ public String getInfo(){ private final ArrayList preViewPorts = new ArrayList<>(); private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); + private final ParameterSpace parameters = new ParameterSpace(); + private MyFrameGraph myFrameGraph; private Camera prevCam = null; private Material forcedMaterial = null; private String forcedTechnique = null; private RenderState forcedRenderState = null; private final SafeArrayList forcedOverrides = new SafeArrayList<>(MatParamOverride.class); + private GeometryRenderHandler renderGeometry; private int viewX; private int viewY; private int viewWidth; @@ -147,6 +146,15 @@ public RenderManager(Renderer renderer) { this.forcedOverrides.add(boundDrawBufferId); } + /** + * Gets the global parameter space for rendering. + * + * @return + */ + public ParameterSpace getParameters() { + return parameters; + } + /** * Sets the framegraph used for rendering if the rendered viewport * has no framegraph assigned. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java index ed86ef05e3..933374d5cb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java @@ -33,7 +33,7 @@ public String getParameterName() { return name; } @Override - public void accept(FrameBuffer value) { + public void set(FrameBuffer value) { if (source != value || ready) { source = value; if ((source != null || target != null) && renderer != null) { @@ -43,7 +43,7 @@ public void accept(FrameBuffer value) { } } @Override - public FrameBuffer produce() { + public FrameBuffer get() { return target; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java index dbd38e80ee..eb5a3b3c33 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java @@ -6,7 +6,7 @@ import com.jme3.renderer.framegraph.parameters.RenderParameterGroup; import com.jme3.renderer.framegraph.parameters.ParameterBinding; -import com.jme3.renderer.framegraph.parameters.ParameterManager; +import com.jme3.renderer.framegraph.parameters.ParameterSpace; import com.jme3.renderer.framegraph.parameters.RenderParameter; import com.jme3.profile.AppProfiler; import com.jme3.renderer.RenderManager; @@ -14,35 +14,62 @@ import java.util.LinkedList; /** - * + * Manages render passes, dependencies, and resources in a node-based parameter system. + * * @author codex */ public class MyFrameGraph { private final LinkedList passes = new LinkedList<>(); - private final ParameterManager parameters = new ParameterManager(); + private final ParameterSpace parameters = new ParameterSpace(); private final RenderContext context; public MyFrameGraph(RenderManager renderManager) { context = new RenderContext(renderManager); } + /** + * Prepares the context for rendering with the viewport. + * + * @param vp viewport being rendered + * @param tpf time per frame + */ + public void prepareRender(ViewPort vp, float tpf) { + prepareRender(vp, null, tpf); + } + + /** + * Prepares the context for rendering with the viewport. + * + * @param vp viewport being rendered + * @param prof app profiler, or null for no profiling + * @param tpf time per frame + */ public void prepareRender(ViewPort vp, AppProfiler prof, float tpf) { context.update(vp, prof, tpf); } + /** + * + */ public void preFrame() { for (FGModule p : passes) { p.preFrame(context); } } + /** + * + */ public void postQueue() { for (FGModule p : passes) { p.postQueue(context); } } + /** + * Executes this framegraph for rendering. + */ public void execute() { // prepare passes for execution for (FGModule p : passes) { @@ -67,12 +94,25 @@ public void execute() { } } + /** + * Adds the pass to this framegraph and registers it with the + * local parameter space. + * + * @param pass + */ public void add(FGModule pass) { pass.initialize(this); passes.add(pass); registerParameterGroup(pass); } + /** + * Gets the first pass that is of or a subclass of the given type. + * + * @param + * @param type + * @return pass of the given type, or null if none exists + */ public T get(Class type) { for (FGModule p : passes) { if (type.isAssignableFrom(p.getClass())) { @@ -82,35 +122,92 @@ public T get(Class type) { return null; } - public ParameterManager getParameters() { + /** + * Gets the local parameter space. + * + * @return + */ + public ParameterSpace getLocalParameters() { return parameters; } + /** + * Gets the world parameter space belonging to the render manager. + * + * @return + */ + public ParameterSpace getWorldParameters() { + return context.getRenderManager().getParameters(); + } + + /** + * Gets the render context. + * + * @return + */ public RenderContext getContext() { return context; } + /** + * Registers the parameter with the local parameter space. + * + * @param + * @param param + * @return the given parameter + */ public T registerParameter(T param) { parameters.register(param); return param; } + /** + * Registers the parameter group with the local parameter space. + * + * @param group + */ public void registerParameterGroup(RenderParameterGroup group) { parameters.register(group); } + /** + * Binds the given input parameter to the named target output parameter in + * the local parameter space. + * + * @param target + * @param input + * @return + */ public ParameterBinding bindToOutput(String target, RenderParameter input) { return parameters.bindToOutput(target, input); } + /** + * Binds the given output parameter to the named target input parameter in + * the local parameter space. + * + * @param target + * @param output + * @return + */ public ParameterBinding bindToInput(String target, RenderParameter output) { return parameters.bindToInput(target, output); } + /** + * Removes the parameter from the local parameter space. + * + * @param param + */ public void removeParameter(RenderParameter param) { parameters.remove(param); } + /** + * Removes the parameter group from the local parameter space. + * + * @param group + */ public void removeParameterGroup(RenderParameterGroup group) { parameters.remove(group); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java index a5f72417d7..2b8d391f47 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java @@ -37,7 +37,7 @@ public String getParameterName() { return name; } @Override - public void accept(T value) { + public void set(T value) { this.value = value; if (debug) { System.out.println("assign to material: "+this.value); @@ -45,7 +45,7 @@ public void accept(T value) { material.setParam(matName, type, this.value); } @Override - public T produce() { + public T get() { return value; } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java index 5669aee35f..57dd9927ed 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java @@ -4,9 +4,6 @@ */ package com.jme3.renderer.framegraph.parameters; -import com.jme3.renderer.framegraph.parameters.RenderParameter; -import java.util.Objects; - /** * * @author codex @@ -21,24 +18,61 @@ public ParameterBinding(RenderParameter output, RenderParameter input) { this.input = input; } + /** + * Applies the output parameter to the input parameter. + */ public void applyOutputToInput() { - input.accept(output.produce()); + input.set(output.get()); } + /** + * Returns true if the given parameter is the input parameter of this binding. + * + * @param input + * @return + */ public boolean isInput(RenderParameter input) { return this.input == input; } + /** + * Returns true if the given parameter is the output parameter of this binding. + * + * @param output + * @return + */ public boolean isOutput(RenderParameter output) { return this.output == output; } - public boolean contains(RenderParameter p) { - return input == p || output == p; + /** + * Returns true if the given parameter is a member of this binding. + * + * @param param + * @return + */ + public boolean contains(RenderParameter param) { + return input == param || output == param; + } + + /** + * Returns true if the named parameter is a member of this binding. + * + * @param name + * @return + */ + public boolean containsNamed(String name) { + return input.isPubliclyNamed(name) || output.isPubliclyNamed(name); } - public boolean isViolating(ParameterBinding pb) { - return input == pb.input; + /** + * Returns true if this binding is violating the given binding. + * + * @param binding + * @return + */ + public boolean isViolating(ParameterBinding binding) { + return input == binding.input; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterManager.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterManager.java deleted file mode 100644 index 48618520ae..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterManager.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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.parameters; - -import com.jme3.renderer.framegraph.parameters.RenderParameter; -import java.util.Iterator; -import java.util.LinkedList; - -/** - * - * @author codex - */ -public class ParameterManager { - - private final LinkedList parameters = new LinkedList<>(); - private final LinkedList bindings = new LinkedList<>(); - - public RenderParameter getParameter(String name, boolean failOnMiss) { - for (RenderParameter p : parameters) { - if (p.isPubliclyNamed(name)) { - return p; - } - } - if (failOnMiss) { - throw new NullPointerException("Input parameter \""+name+"\" does not exist or is private."); - } - return null; - } - - public T register(T param) { - parameters.add(param); - return param; - } - - public void registerAll(RenderParameter... params) { - for (RenderParameter p : params) { - register(p); - } - } - - public void register(RenderParameterGroup group) { - for (RenderParameter p : group.getRenderParameters()) { - register(p); - } - } - - public ParameterBinding bindToOutput(String target, RenderParameter input) { - return createBinding(getParameter(target, false), input); - } - - public ParameterBinding bindToInput(String target, RenderParameter output) { - return createBinding(output, getParameter(target, false)); - } - - public ParameterBinding bind(RenderParameter output, RenderParameter input) { - return createBinding(output, input); - } - - private ParameterBinding createBinding(RenderParameter output, RenderParameter input) { - if (output == null || input == null) { - return null; - } - ParameterBinding binding = new ParameterBinding(output, input); - // remove previous bindings - for (Iterator it = bindings.iterator(); it.hasNext();) { - if (it.next().isViolating(binding)) { - it.remove(); - } - } - bindings.add(binding); - return binding; - } - - public void remove(RenderParameter param) { - parameters.remove(param); - for (Iterator it = bindings.iterator(); it.hasNext();) { - if (it.next().contains(param)) { - it.remove(); - } - } - } - - public void remove(RenderParameterGroup group) { - for (RenderParameter p : group.getRenderParameters()) { - remove(p); - } - } - - public void pull(RenderParameter input) { - for (ParameterBinding b : bindings) { - if (b.isInput(input)) { - b.applyOutputToInput(); - break; - } - } - } - - public void pull(RenderParameterGroup group) { - for (RenderParameter p : group.getRenderParameters()) { - pull(p); - } - } - - public void push(RenderParameter output) { - for (ParameterBinding b : bindings) { - if (b.isOutput(output)) { - b.applyOutputToInput(); - } - } - } - - public void push(RenderParameterGroup group) { - for (RenderParameter p : group.getRenderParameters()) { - push(p); - } - } - - public void clear() { - parameters.clear(); - bindings.clear(); - } - - public LinkedList getParameterList() { - return parameters; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterSpace.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterSpace.java new file mode 100644 index 0000000000..bda8f68104 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterSpace.java @@ -0,0 +1,261 @@ +/* + * 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.parameters; + +import java.util.Iterator; +import java.util.LinkedList; + +/** + * + * @author codex + */ +public class ParameterSpace { + + private final LinkedList parameters = new LinkedList<>(); + private final LinkedList localBindings = new LinkedList<>(); + + /** + * Returns the named parameter, or null if none exists. + * + * @param name + * @param failOnMiss + * @return named parameter + * @throws NullPointerException if the named parameter does not exist and failOnMiss is true + */ + public RenderParameter getParameter(String name, boolean failOnMiss) { + for (RenderParameter p : parameters) { + if (p.isPubliclyNamed(name)) { + return p; + } + } + if (failOnMiss) { + throw new NullPointerException("Input parameter \""+name+"\" does not exist or is private."); + } + return null; + } + + /** + * Returns the named parameter of the given type, or null if none exists. + * + * @param + * @param name + * @param type + * @param failOnMiss + * @return named parameter + * @throws NullPointerException if the named parameter does not exist and failOnMiss is true + */ + public T getParameter(String name, Class type, boolean failOnMiss) { + for (RenderParameter p : parameters) { + if (p.isPubliclyNamed(name) && type.isAssignableFrom(p.getClass())) { + return (T)p; + } + } + if (failOnMiss) { + throw new NullPointerException("Input parameter \""+name+"\" does not exist, or is private, " + + "or is not of type "+type.getName()+"."); + } + return null; + } + + /** + * Registers and returns the parameter. + * + * @param + * @param param + * @return + */ + public T register(T param) { + parameters.add(param); + return param; + } + + /** + * Registers all given parameters. + * + * @param params + */ + public void registerAll(RenderParameter... params) { + for (RenderParameter p : params) { + register(p); + } + } + + /** + * Registers all parameters in the group. + * + * @param group + */ + public void register(RenderParameterGroup group) { + for (RenderParameter p : group.getRenderParameters()) { + register(p); + } + } + + /** + * Removes the parameter from this space and breaks all related bindings. + * + * @param param + */ + public void remove(RenderParameter param) { + parameters.remove(param); + for (Iterator it = localBindings.iterator(); it.hasNext();) { + if (it.next().contains(param)) { + it.remove(); + } + } + } + + /** + * Removes all parameters in the group from this space. + * + * @param group + * @see #remove(com.jme3.renderer.framegraph.parameters.RenderParameter) + */ + public void remove(RenderParameterGroup group) { + for (RenderParameter p : group.getRenderParameters()) { + remove(p); + } + } + + /** + * Binds the named parameter and the input parameter locally, with the named parameter + * as the output, and returns the resulting binding. + *

    + * The input parameter should already be registered with this space. + * + * @param target + * @param input + * @return + */ + public ParameterBinding bindToOutput(String target, RenderParameter input) { + return createBinding(getParameter(target, false), input); + } + + /** + * Binds the named parameter and the output parameter locally, with the named parameter + * as the input, and returns the resulting binding. + *

    + * The output parameter should already be registered with this space. + * + * @param target + * @param output + * @return + */ + public ParameterBinding bindToInput(String target, RenderParameter output) { + return createBinding(output, getParameter(target, false)); + } + + /** + * Binds the two parameters and returns the resulting binding. + *

    + * Both parameters should already be registered with this space. + * + * @param output + * @param input + * @return + */ + public ParameterBinding bind(RenderParameter output, RenderParameter input) { + return createBinding(output, input); + } + + /** + * Registers the binding with this space. + * + * @param binding + * @return + */ + public ParameterBinding registerBinding(ParameterBinding binding) { + breakViolatingBindings(binding); + localBindings.add(binding); + return binding; + } + + private ParameterBinding createBinding(RenderParameter output, RenderParameter input) { + if (output == null || input == null) { + return null; + } + ParameterBinding binding = new ParameterBinding(output, input); + breakViolatingBindings(binding); + localBindings.add(binding); + return binding; + } + + private void breakViolatingBindings(ParameterBinding binding) { + for (Iterator it = localBindings.iterator(); it.hasNext();) { + if (it.next().isViolating(binding)) { + it.remove(); + } + } + } + + /** + * Pulls values from parameters bound as output to the given parameter. + * + * @param input + */ + public void pull(RenderParameter input) { + for (ParameterBinding b : localBindings) { + if (b.isInput(input)) { + b.applyOutputToInput(); + break; + } + } + } + + /** + * Pulls values from parameters bound as output to parameters in the given group. + * + * @param group + */ + public void pull(RenderParameterGroup group) { + for (RenderParameter p : group.getRenderParameters()) { + pull(p); + } + } + + /** + * Pushes values to parameters bound as input to the given parameter. + * + * @param output + */ + public void push(RenderParameter output) { + for (ParameterBinding b : localBindings) { + if (b.isOutput(output)) { + b.applyOutputToInput(); + } + } + } + + /** + * Pushes values to parameters bound as input to parameters in the given group. + * + * @param group + */ + public void push(RenderParameterGroup group) { + for (RenderParameter p : group.getRenderParameters()) { + push(p); + } + } + + /** + * Clears this space of all parameters and bindings. + */ + public void clear() { + parameters.clear(); + localBindings.clear(); + } + + /** + * Returns the list of parameters. + *

    + * Do not modify the returned list. + * + * @return + */ + public LinkedList getParameterList() { + return parameters; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java index 181f47eebf..8886d6c2b9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java @@ -28,41 +28,41 @@ public interface RenderParameter { * * @param value */ - public void accept(T value); + public void set(T value); /** * Returns the value held by this parameter. * * @return */ - public T produce(); + public T get(); /** * Deletes the value held by this parameter. */ public default void erase() { - accept(null); + set(null); } /** - * Returns the next value + * Returns true if the value returned by {@link #get()} is not null. * * @return */ public default boolean validate() { - return produce() != null; + return get() != null; } /** - * Returns the value returned by {@link #produce()} if {@link #validate()} + * Returns the value returned by {@link #get()} if {@link #validate()} * returns true, otherwise returns the given value. * * @param value * @return */ - public default T produceOrElse(T value) { + public default T orElse(T value) { if (validate()) { - return produce(); + return get(); } else { return value; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java index 311a9a73b3..348997d69a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java @@ -22,7 +22,7 @@ public TextureTargetParam(String name, FrameBufferTextureTarget target) { } @Override - public Texture produce() { + public Texture get() { if (target != null) { return target.getTexture(); } else { @@ -36,7 +36,7 @@ public String getParameterName() { } @Override - public void accept(Texture value) {} + public void set(Texture value) {} @Override public void erase() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java index 0321b6e224..be7cd990f7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java @@ -32,11 +32,11 @@ public String getParameterName() { return name; } @Override - public void accept(T value) { + public void set(T value) { this.value = value; } @Override - public T produce() { + public T get() { return (value != null ? value : defaultValue); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/WorldRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/WorldRenderParam.java new file mode 100644 index 0000000000..c610658f2c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/WorldRenderParam.java @@ -0,0 +1,70 @@ +/* + * 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.parameters; + +/** + * + * @author codex + * @param + */ +public class WorldRenderParam implements RenderParameter { + + private final String name; + private ParameterSpace space; + private String target; + private boolean pull; + + public WorldRenderParam(String name, ParameterSpace space, String target) { + this(name, space, target, true); + } + public WorldRenderParam(String name, ParameterSpace space, String target, boolean pull) { + this.name = name; + this.space = space; + this.target = target; + this.pull = pull; + } + + @Override + public String getParameterName() { + return name; + } + @Override + public void set(T value) { + RenderParameter p = space.getParameter(target, false); + if (p != null) { + p.set(value); + } + } + @Override + public T get() { + RenderParameter p = space.getParameter(target, false); + if (p != null) { + return p.get(); + } else { + return null; + } + } + + public void setSpace(ParameterSpace space) { + this.space = space; + } + public void setTarget(String target) { + this.target = target; + } + public void setPull(boolean pull) { + this.pull = pull; + } + + public ParameterSpace getSpace() { + return space; + } + public String getTarget() { + return target; + } + public boolean isPull() { + return pull; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java index 8f49e6b0d2..19971dd287 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java @@ -104,17 +104,17 @@ public void prepare(RenderContext context) { @Override public void execute(RenderContext context) { - context.getRenderer().copyFrameBuffer(gBuffer.produce(), + context.getRenderer().copyFrameBuffer(gBuffer.get(), context.getViewPort().getOutputFrameBuffer(), false, true); - context.getRenderer().copyFrameBuffer(gBuffer.produce(), debug, false, true); + context.getRenderer().copyFrameBuffer(gBuffer.get(), debug, false, true); //makeRenderStateTests(context, "pre tests"); selectTechnique(screenMat, context.getRenderManager()); context.setDepthRange(1, 1); context.getRenderer().setFrameBuffer(context.getViewPort().getOutputFrameBuffer()); screenRect.updateGeometricState(); - context.getRenderManager().renderGeometry(screenRect, lightList.produce()); + context.getRenderManager().renderGeometry(screenRect, lightList.get()); //screenMat.render(screenRect, lightList.produce(), context.getRenderManager()); //makeRenderStateTests(context, "post tests"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java index 81049a564c..a8b209fc60 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java @@ -4,14 +4,11 @@ */ package com.jme3.renderer.framegraph.pass; -import com.jme3.renderer.RenderManager; import com.jme3.renderer.framegraph.AbstractModule; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.RenderQueueModule; import com.jme3.renderer.queue.RenderQueue; -import com.jme3.scene.Geometry; /** * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java index d450130891..31f03ade11 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java @@ -159,7 +159,7 @@ protected void reshape(Renderer renderer, int w, int h) { gBuffer.setDepthTarget(t4); targets[4].setTextureTarget(t4); gBuffer.setMultiTarget(true); - bufferParam.accept(gBuffer); + bufferParam.set(gBuffer); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java index 3f8fd5dafa..126f523a2e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java @@ -4,7 +4,6 @@ */ package com.jme3.renderer.framegraph.pass; -import com.jme3.renderer.framegraph.pass.DeferredShadingModule; import com.jme3.asset.AssetManager; import com.jme3.material.Material; import com.jme3.material.TechniqueDef; @@ -13,7 +12,7 @@ import com.jme3.material.logic.TiledRenderGrid; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.parameters.ValueRenderParam; +import com.jme3.renderer.framegraph.parameters.WorldRenderParam; import java.util.LinkedList; /** @@ -26,8 +25,8 @@ public class TileDeferredShadingModule extends DeferredShadingModule implements private static final String MATDEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"; private static final String PASS = "TileBasedDeferredPass"; - private ValueRenderParam tileInfo; - private final LinkedList logic = new LinkedList<>(); + private WorldRenderParam tileParam; + private TiledRenderGrid tileInfo = new TiledRenderGrid(); public TileDeferredShadingModule(AssetManager assetManager) { super(assetManager); @@ -36,7 +35,7 @@ public TileDeferredShadingModule(AssetManager assetManager) { @Override public void initialize(MyFrameGraph frameGraph) { super.initialize(frameGraph); - tileInfo = addParameter(new ValueRenderParam<>(TILE_INFO, null, new TiledRenderGrid())); + tileParam = addParameter(new WorldRenderParam<>(TILE_INFO, frameGraph.getWorldParameters(), TILE_INFO)); } @Override public void prepare(RenderContext context) { @@ -45,7 +44,11 @@ public void prepare(RenderContext context) { } @Override public void execute(RenderContext context) { - tileInfo.produce().update(context.getRenderManager().getCurrentCamera()); + TiledRenderGrid t = tileParam.get(); + if (t != null) { + tileInfo.copyFrom(t); + } + tileInfo.update(context.getRenderManager().getCurrentCamera()); super.execute(context); } @Override @@ -55,14 +58,13 @@ protected Material createMaterial() { @Override protected void assignTechniqueLogic(Material mat) { for (TechniqueDef t : mat.getMaterialDef().getTechniqueDefs(PASS)) { - TileBasedDeferredSinglePassLightingLogic l = new TileBasedDeferredSinglePassLightingLogic(t, this); - logic.add(l); + TileBasedDeferredSinglePassLightingLogic l = new TileBasedDeferredSinglePassLightingLogic(t, tileInfo); t.setLogic(l); } } @Override public TiledRenderGrid getTiledRenderGrid() { - return tileInfo.produce(); + return tileParam.orElse(tileInfo); } } From 34fee377e41fae927ba9eb2f2cd805253f9b4b4a Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:04:51 -0400 Subject: [PATCH 046/111] added optimizations --- .../renderer/framegraph/MyFrameGraph.java | 29 ++++++++++++------ .../framegraph/RenderQueueModule.java | 1 + .../framegraph/{ => pass}/AbstractModule.java | 9 +++++- .../pass/BackgroundScreenTestModule.java | 5 ++-- .../pass/DeferredShadingModule.java | 19 +++++++----- .../framegraph/{ => pass}/FGModule.java | 30 +++++++++++++++---- .../framegraph/pass/ForwardModule.java | 5 ++-- .../framegraph/pass/GBufferModule.java | 23 +++++++------- .../framegraph/pass/PostProcessingModule.java | 5 ++-- .../pass/TileDeferredShadingModule.java | 5 ++-- 10 files changed, 89 insertions(+), 42 deletions(-) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => pass}/AbstractModule.java (77%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => pass}/FGModule.java (50%) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java index eb5a3b3c33..2ec67a2a7f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.pass.FGModule; import com.jme3.renderer.framegraph.parameters.RenderParameterGroup; import com.jme3.renderer.framegraph.parameters.ParameterBinding; import com.jme3.renderer.framegraph.parameters.ParameterSpace; @@ -21,6 +22,7 @@ public class MyFrameGraph { private final LinkedList passes = new LinkedList<>(); + private final LinkedList executionQueue = new LinkedList<>(); private final ParameterSpace parameters = new ParameterSpace(); private final RenderContext context; @@ -73,25 +75,34 @@ public void postQueue() { public void execute() { // prepare passes for execution for (FGModule p : passes) { - p.prepare(context); + if (p.prepare(context)) { + executionQueue.add(p); + } } // execute - for (FGModule p : passes) { + for (FGModule p : executionQueue) { // accept parameters as arguments to the pass parameters.pull(p); // execute pass - p.execute(context); - // apply resulting output parameters to connected input parameters - parameters.push(p); - // reset depth render range - context.setDepthRange(DepthRange.IDENTITY); - // reset geometry handler - context.getRenderManager().setGeometryRenderHandler(null); + if (p.readyForExecution(context)) { + p.execute(context); + parameters.push(p); + resetRenderState(); + } } // reset passes for (FGModule p : passes) { p.reset(); } + executionQueue.clear(); + } + + /** + * Resets the render state so that one pass's render does not affect another render. + */ + protected void resetRenderState() { + context.setDepthRange(DepthRange.IDENTITY); + context.getRenderManager().setGeometryRenderHandler(null); } /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java index 9ecb7ee767..caaca217f7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.pass.AbstractModule; import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java similarity index 77% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java index 84cd2713d5..f0fabbd67e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java @@ -2,8 +2,10 @@ * 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; +package com.jme3.renderer.framegraph.pass; +import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.framegraph.pass.FGModule; import com.jme3.renderer.framegraph.parameters.RenderParameter; import java.util.Collection; import java.util.LinkedList; @@ -27,6 +29,11 @@ public void preFrame(RenderContext context) {} @Override public void postQueue(RenderContext context) {} + @Override + public boolean readyForExecution(RenderContext context) { + return true; + } + protected final T addParameter(T p) { parameters.add(p); return p; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java index 6dcf1930d6..e07593161f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java @@ -7,7 +7,6 @@ import com.jme3.asset.AssetManager; import com.jme3.material.Material; import com.jme3.material.RenderState; -import com.jme3.renderer.framegraph.AbstractModule; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.texture.Texture2D; @@ -44,7 +43,9 @@ public void initialize(MyFrameGraph frameGraph) { } @Override - public void prepare(RenderContext context) {} + public boolean prepare(RenderContext context) { + return true; + } @Override public void execute(RenderContext context) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java index 19971dd287..6b928200dc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java @@ -13,7 +13,6 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.AbstractModule; import com.jme3.renderer.framegraph.parameters.MatRenderParam; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; @@ -92,7 +91,7 @@ public void initialize(MyFrameGraph frameGraph) { } @Override - public void prepare(RenderContext context) { + public boolean prepare(RenderContext context) { if (debug == null) { debug = new FrameBuffer(context.getWidth(), context.getHeight(), 1); FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget( @@ -100,15 +99,20 @@ public void prepare(RenderContext context) { debug.setDepthTarget(t); depthCopy.setTextureTarget(t); } + return true; + } + @Override + public boolean readyForExecution(RenderContext context) { + return executeState.get(); } @Override public void execute(RenderContext context) { - + context.getRenderer().copyFrameBuffer(gBuffer.get(), context.getViewPort().getOutputFrameBuffer(), false, true); - + context.getRenderer().copyFrameBuffer(gBuffer.get(), debug, false, true); - + //makeRenderStateTests(context, "pre tests"); selectTechnique(screenMat, context.getRenderManager()); context.setDepthRange(1, 1); @@ -116,7 +120,7 @@ public void execute(RenderContext context) { screenRect.updateGeometricState(); context.getRenderManager().renderGeometry(screenRect, lightList.get()); //screenMat.render(screenRect, lightList.produce(), context.getRenderManager()); - + //makeRenderStateTests(context, "post tests"); } @@ -160,7 +164,8 @@ private void makeRenderStateTests(RenderContext context, String label) { test(rm.getLightFilter(), "light filter"); test(vp.getBackgroundColor(), "viewport background"); test(vp.getOutputFrameBuffer(), "viewport output framebuffer"); - test("color:"+vp.isClearColor()+", depth:"+vp.isClearDepth()+", stencil:"+vp.isClearStencil(), "viewport clear flags"); + test("color:"+vp.isClearColor()+", depth:"+vp.isClearDepth()+", stencil:" + +vp.isClearStencil(), "viewport clear flags"); } private void test(Object object, String label) { System.out.println(" "+label+" = "+(object == null ? "null" : object.toString().replaceAll("\n", "; "))); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java similarity index 50% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java index 75fa365650..b6f674bed7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java @@ -2,8 +2,10 @@ * 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; +package com.jme3.renderer.framegraph.pass; +import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.parameters.RenderParameterGroup; /** @@ -23,25 +25,41 @@ public interface FGModule extends RenderParameterGroup public void initialize(T frameGraph); /** - * Called before the render queue is rendered. + * Called before the render buckets are queued. * * @param context */ public void preFrame(RenderContext context); /** - * Called after the render queue is rendered. + * Called after the render buckets are queued. * * @param context */ public void postQueue(RenderContext context); /** - * Prepares the pass for execution. + * Prepares the pass for execution and determines if execution should occur. + *

    + * Execution should be vetoed on this step if possible, because the framegraph + * does not need to pull or push parameters from the parameter space for this pass + * if execution is vetoed on this step. * * @param context + * @return true if execution should occur + */ + public boolean prepare(RenderContext context); + + /** + * Returns true if this pass is ready for execution. + *

    + * If this pass is not ready for execution, the framegraph will not execute + * this pass and will not push parameters from this pass to bound parameters. + * + * @param context + * @return */ - public void prepare(RenderContext context); + public boolean readyForExecution(RenderContext context); /** * Executes this pass. @@ -51,7 +69,7 @@ public interface FGModule extends RenderParameterGroup public void execute(RenderContext context); /** - * Resets the pass after execution. + * Resets this pass after execution. */ public void reset(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java index a8b209fc60..813439f5e4 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java @@ -4,7 +4,6 @@ */ package com.jme3.renderer.framegraph.pass; -import com.jme3.renderer.framegraph.AbstractModule; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; @@ -30,7 +29,9 @@ public ForwardModule(RenderQueue.Bucket bucket, DepthRange depth) { @Override public void initialize(MyFrameGraph frameGraph) {} @Override - public void prepare(RenderContext context) {} + public boolean prepare(RenderContext context) { + return !context.getRenderQueue().isQueueEmpty(bucket); + } @Override public void execute(RenderContext context) { if (depth != null) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java index 31f03ade11..b2374fc16c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java @@ -63,11 +63,14 @@ public void initialize(MyFrameGraph frameGraph) { } @Override - public void prepare(RenderContext context) { - super.prepare(context); - if (context.isSizeChanged() || gBuffer == null) { - reshape(context.getRenderer(), context.getWidth(), context.getHeight()); + public boolean prepare(RenderContext context) { + if (super.prepare(context)) { + if (context.isSizeChanged() || gBuffer == null) { + reshape(context.getRenderer(), context.getWidth(), context.getHeight()); + } + return true; } + return false; } @Override @@ -96,17 +99,17 @@ public boolean renderGeometry(RenderManager rm, Geometry geom) { return false; } rm.renderGeometry(geom); - if(material.getActiveTechnique() != null){ - if(material.getMaterialDef().getTechniqueDefs(GBUFFER_PASS) != null){ + if (material.getActiveTechnique() != null) { + if (material.getMaterialDef().getTechniqueDefs(GBUFFER_PASS) != null) { LightList lights = geom.getFilterWorldLights(); - for(Light light : lights){ - if(!tempLights.contains(light)){ + for (Light light : lights) { + if (!tempLights.contains(light)) { tempLights.add(light); } } // Whether it has lights or not, material objects containing GBufferPass will perform // DeferredShading, and shade according to shadingModelId - //hasDraw.accept(true); + hasDraw.set(true); return true; } } @@ -118,7 +121,7 @@ public void reset() { super.reset(); tempLights.clear(); lightData.clear(); - //hasDraw.accept(false); + hasDraw.set(false); } protected void reshape(Renderer renderer, int w, int h) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java index fef745ed4b..7a1ac41d85 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java @@ -9,7 +9,6 @@ import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.AbstractModule; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; @@ -62,7 +61,9 @@ public void postQueue(RenderContext context) { } } @Override - public void prepare(RenderContext context) {} + public boolean prepare(RenderContext context) { + return true; + } @Override public void execute(RenderContext context) { context.setDepthRange(DepthRange.IDENTITY); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java index 126f523a2e..0d7284ef34 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java @@ -13,7 +13,6 @@ import com.jme3.renderer.framegraph.MyFrameGraph; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.parameters.WorldRenderParam; -import java.util.LinkedList; /** * @@ -38,9 +37,9 @@ public void initialize(MyFrameGraph frameGraph) { tileParam = addParameter(new WorldRenderParam<>(TILE_INFO, frameGraph.getWorldParameters(), TILE_INFO)); } @Override - public void prepare(RenderContext context) { - super.prepare(context); + public boolean prepare(RenderContext context) { //context.getRenderManager().calculateTileInfo(); + return super.prepare(context); } @Override public void execute(RenderContext context) { From 9ba9bb3570a9c4f49f78bf9b44404bfa460c2e6b Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 27 Apr 2024 10:12:19 -0400 Subject: [PATCH 047/111] recoding resource system --- .../DeferredSinglePassLightingLogic.java | 5 +- ...Source.java => GeometryRenderHandler.java} | 12 +- .../java/com/jme3/renderer/RenderManager.java | 32 +- .../main/java/com/jme3/renderer/ViewPort.java | 8 +- .../renderer/framegraph/AbstractFGPass.java | 142 --------- .../renderer/framegraph/AbstractFGSink.java | 82 ----- .../renderer/framegraph/AbstractFGSource.java | 51 --- .../renderer/framegraph/BindableSink.java | 84 ----- .../jme3/renderer/framegraph/FGBindable.java | 49 --- .../renderer/framegraph/FGBindingPass.java | 82 ----- .../renderer/framegraph/FGCallbackPass.java | 61 ---- .../renderer/framegraph/FGComputePass.java | 44 --- .../FGFramebufferCopyBindableSink.java | 105 ------ .../jme3/renderer/framegraph/FGGlobal.java | 62 ---- .../framegraph/FGParameterSource.java | 15 - .../com/jme3/renderer/framegraph/FGPass.java | 42 --- .../framegraph/FGRenderQueuePass.java | 109 ------- .../renderer/framegraph/FGShaderResource.java | 58 ---- .../com/jme3/renderer/framegraph/FGSink.java | 33 -- .../framegraph/FGVarBindableSink.java | 48 --- .../jme3/renderer/framegraph/FGVarSource.java | 77 ----- .../framegraph/FrameBufferCopyParam.java | 70 ---- .../jme3/renderer/framegraph/FrameGraph.java | 301 ++---------------- .../framegraph/FramebufferSource.java | 72 ----- .../renderer/framegraph/MatParamSink.java | 70 ---- .../renderer/framegraph/MyFrameGraph.java | 226 ------------- .../renderer/framegraph/RenderContext.java | 1 + .../jme3/renderer/framegraph/RenderPass.java | 40 +++ .../framegraph/RenderPipelineFactory.java | 24 +- .../renderer/framegraph/RenderResource.java | 74 +++++ .../renderer/framegraph/ResourceAction.java | 42 +++ .../jme3/renderer/framegraph/ResourceDef.java | 27 ++ .../renderer/framegraph/ResourcePool.java | 38 +++ .../renderer/framegraph/ResourceRegistry.java | 86 +++++ .../renderer/framegraph/ResourceTicket.java | 59 ++++ .../framegraph/parameters/MatRenderParam.java | 60 ---- .../parameters/ParameterBinding.java | 78 ----- .../framegraph/parameters/ParameterSpace.java | 261 --------------- .../parameters/RenderParameter.java | 90 ------ .../parameters/RenderParameterGroup.java | 18 -- .../parameters/TextureTargetParam.java | 54 ---- .../parameters/ValueRenderParam.java | 55 ---- .../parameters/WorldRenderParam.java | 70 ---- .../framegraph/pass/AbstractModule.java | 39 ++- .../pass/BackgroundScreenTestModule.java | 4 +- .../pass/DeferredShadingModule.java | 108 ++----- .../renderer/framegraph/pass/FGModule.java | 30 +- .../framegraph/pass/ForwardModule.java | 4 +- .../framegraph/pass/GBufferModule.java | 18 +- .../framegraph/pass/PostProcessingModule.java | 4 +- .../framegraph/pass/ScreenModule.java | 35 ++ .../pass/TileDeferredShadingModule.java | 109 +++++-- .../renderer/pass/DeferredLightDataProxy.java | 30 -- .../renderer/pass/DeferredLightDataSink.java | 47 --- .../pass/DeferredLightDataSource.java | 75 ----- .../renderer/pass/DeferredShadingPass.java | 131 -------- .../com/jme3/renderer/pass/ForwardPass.java | 76 ----- .../com/jme3/renderer/pass/GBufferPass.java | 198 ------------ .../renderer/pass/GeometryRenderHandler.java | 48 --- .../com/jme3/renderer/pass/GuiModule.java | 31 -- .../java/com/jme3/renderer/pass/GuiPass.java | 64 ---- .../com/jme3/renderer/pass/OpaquePass.java | 56 ---- .../jme3/renderer/pass/PostProcessorPass.java | 67 ---- .../renderer/pass/ResolveSceneColorPass.java | 95 ------ .../com/jme3/renderer/pass/ScreenPass.java | 66 ---- .../ScreenSpaceSubsurfaceScatteringPass.java | 9 - .../java/com/jme3/renderer/pass/SkyPass.java | 52 --- .../pass/TileDeferredShadingPass.java | 76 ----- .../jme3/renderer/pass/TranslucentPass.java | 49 --- .../jme3/renderer/pass/TransparentPass.java | 52 --- .../com/jme3/renderer/queue/RenderQueue.java | 3 +- .../ShadingCommon/DeferredShading.vert | 2 +- .../com/jme3/material/plugins/J3MLoader.java | 2 +- .../renderpath/TestDeferredShading.java | 2 +- .../renderpath/TestPBRTerrainRenderPath.java | 2 +- .../jme3test/renderpath/TestShadingModel.java | 4 +- .../TestSimpleDeferredLighting.java | 4 +- .../TestTileBasedDeferredShading.java | 4 +- 78 files changed, 642 insertions(+), 3971 deletions(-) rename jme3-core/src/main/java/com/jme3/renderer/{framegraph/FGSource.java => GeometryRenderHandler.java} (54%) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSource.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/BindableSink.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGParameterSource.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java delete 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/FGSink.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FramebufferSource.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java delete 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/RenderPass.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAction.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourcePool.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRegistry.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterSpace.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameterGroup.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/WorldRenderParam.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ScreenModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataProxy.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSink.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSource.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/GeometryRenderHandler.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/GuiPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/ResolveSceneColorPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/ScreenPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/ScreenSpaceSubsurfaceScatteringPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.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 dd85e1344c..79efc3ccbf 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 @@ -489,9 +489,10 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry // 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(useLightTextures){ - if (lightNum != renderManager.getMaxDeferredShadingLights()) { + int max = 1024; + if (lightNum != max) { cleanupLightData(); - prepareLightData(renderManager.getMaxDeferredShadingLights()); + prepareLightData(max); } // 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) useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientColor, probes, true); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java b/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java similarity index 54% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java rename to jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java index a8d51dc68c..40f9eeaa95 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java @@ -2,18 +2,16 @@ * 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; +package com.jme3.renderer; + +import com.jme3.scene.Geometry; /** * * @author codex */ -public interface FGSource { - - public String getName(); - - public abstract void postLinkValidate(); +public interface GeometryRenderHandler { - public abstract FGBindable yieldBindable(); + public boolean renderGeometry(RenderManager rm, Geometry geom); } 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 426106fffe..b1453fa284 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -46,13 +46,12 @@ import com.jme3.profile.AppStep; import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; -import com.jme3.renderer.framegraph.MyFrameGraph; -import com.jme3.renderer.framegraph.parameters.ParameterSpace; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourcePool; 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.pass.*; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; import com.jme3.scene.Node; @@ -111,8 +110,8 @@ public String getInfo(){ private final ArrayList preViewPorts = new ArrayList<>(); private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); - private final ParameterSpace parameters = new ParameterSpace(); - private MyFrameGraph myFrameGraph; + private final ResourcePool resPool = new ResourcePool(); + private FrameGraph frameGraph; private Camera prevCam = null; private Material forcedMaterial = null; private String forcedTechnique = null; @@ -146,15 +145,6 @@ public RenderManager(Renderer renderer) { this.forcedOverrides.add(boundDrawBufferId); } - /** - * Gets the global parameter space for rendering. - * - * @return - */ - public ParameterSpace getParameters() { - return parameters; - } - /** * Sets the framegraph used for rendering if the rendered viewport * has no framegraph assigned. @@ -164,8 +154,8 @@ public ParameterSpace getParameters() { * * @param frameGraph default framegraph, or null to not use a framegraph by default for rendering */ - public void setFrameGraph(MyFrameGraph frameGraph) { - this.myFrameGraph = frameGraph; + public void setFrameGraph(FrameGraph frameGraph) { + this.frameGraph = frameGraph; } /** @@ -174,8 +164,8 @@ public void setFrameGraph(MyFrameGraph frameGraph) { * * @return default framegraph, or null if framegraphs are not used by default for rendering */ - public MyFrameGraph getFrameGraph() { - return myFrameGraph; + public FrameGraph getFrameGraph() { + return frameGraph; } /** @@ -1274,14 +1264,14 @@ public void renderViewPort(ViewPort vp, float tpf) { processors = null; } - MyFrameGraph fg = vp.getFrameGraph(); + FrameGraph fg = vp.getFrameGraph(); if (fg == null) { - fg = myFrameGraph; + fg = frameGraph; } if (fg != null) { - fg.prepareRender(vp, prof, tpf); + fg.getContext().update(vp, prof, tpf); fg.preFrame(); } else if (processors != null) { 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 5f0ea23c69..936f4bcf2d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java +++ b/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java @@ -33,7 +33,7 @@ import com.jme3.math.ColorRGBA; import com.jme3.post.SceneProcessor; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; @@ -88,7 +88,7 @@ public class ViewPort { /** * Dedicated framegraph. */ - protected MyFrameGraph framegraph; + protected FrameGraph framegraph; /** * FrameBuffer for output. */ @@ -444,11 +444,11 @@ public boolean isEnabled() { return enabled; } - public void setFrameGraph(MyFrameGraph framegraph) { + public void setFrameGraph(FrameGraph framegraph) { this.framegraph = framegraph; } - public MyFrameGraph getFrameGraph() { + public FrameGraph getFrameGraph() { return framegraph; } 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 deleted file mode 100644 index 6cfb98c06f..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java +++ /dev/null @@ -1,142 +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 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 sinkName, String targetPass, String targetResource) { - getSink(sinkName).setTarget(targetPass, targetResource); - } - - @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 resetPass() { - if(isResetResources()){ - getSources().clear(); - getSinks().clear(); - } - } - - @Override - public void finalizePass() { - 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 deleted file mode 100644 index f3d0bd18ea..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java +++ /dev/null @@ -1,82 +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; - -/** - * - * @author JohnKkk - */ -public abstract class AbstractFGSink implements FGSink { - - private final 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 deleted file mode 100644 index d6280054a6..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSource.java +++ /dev/null @@ -1,51 +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; - -/** - * - * @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/BindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/BindableSink.java deleted file mode 100644 index a3516b7fd4..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/BindableSink.java +++ /dev/null @@ -1,84 +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; - -/** - * 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 BindableSink extends AbstractFGSink implements FGBindable { - - protected FGBindable target; - protected boolean linked = false; - - public BindableSink(String registeredName) { - super(registeredName); - } - - @Override - public void bind(RenderContext renderContext) { - if (target != null) { - target.bind(renderContext); - } - } - - @Override - 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; - } - target = 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 target; - } -} 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 deleted file mode 100644 index b11bece28c..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java +++ /dev/null @@ -1,49 +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; - -/** - * 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(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 deleted file mode 100644 index a17be1a3f2..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java +++ /dev/null @@ -1,82 +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 java.util.ArrayList; - -/** - * 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 { - - protected ArrayList binds; - - protected FGBindingPass(String name){ - this(name, new ArrayList()); - } - protected FGBindingPass(String name, ArrayList binds){ - super(name); - 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) { - BindableSink sink = new BindableSink(name); - binds.add(sink); - registerSink(sink); - } - - public void bindAll(RenderContext renderContext){ - // Bind all objects - for(FGBindable bind : binds){ - bind.bind(renderContext); - } - } - - @Override - public void prepare(RenderContext renderContext) {} - - @Override - 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 deleted file mode 100644 index afaab3f107..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java +++ /dev/null @@ -1,61 +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; - -/** - * - * @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(RenderContext 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 deleted file mode 100644 index 015017ff67..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java +++ /dev/null @@ -1,44 +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; - -/** - * - * @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/FGFramebufferCopyBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java deleted file mode 100644 index 67351928d0..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java +++ /dev/null @@ -1,105 +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.texture.FrameBuffer; - -import java.util.ArrayList; - -/** - * @author JohnKkk - * @param - */ -public class FGFramebufferCopyBindableSink extends BindableSink { - - private FramebufferCopyBindableProxy proxy; - - 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 { - 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(RenderContext renderContext) { - if(this.distFramebuffer != null || this.sourceFramebuffer != null){ - renderContext.getRenderer().copyFrameBuffer(this.sourceFramebuffer, - (this.distFramebuffer != null ? this.distFramebuffer : renderContext.getViewPort().getOutputFrameBuffer()), - bCopyColor, bCopyDepth || bCopyStencil); - } - } - } - - public final void setDistFrameBuffer(FrameBuffer distFrameBuffer){ - proxy.distFramebuffer = distFrameBuffer; - } - - @Override - public void bind(FGSource fgSource) { - FGBindable p = fgSource.yieldBindable(); - if (p == null) { - System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + fgSource.getName() + " } "); - return; - } - if(fgSource instanceof FramebufferSource){ - linked = true; - FramebufferSource framebufferSource = (FramebufferSource)fgSource; - proxy.setSourceFramebuffer(((FramebufferSource.FrameBufferSourceProxy)framebufferSource.yieldBindable()).getFrameBuffer()); - target = proxy; - } - else{ - System.err.println(getRegisteredName() + " needs a FGFramebufferSource"); - } - } - - @Override - public void postLinkValidate() { - - } -} 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 deleted file mode 100644 index d448f80370..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java +++ /dev/null @@ -1,62 +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 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 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/FGParameterSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGParameterSource.java deleted file mode 100644 index 702614ff94..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGParameterSource.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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 codex - */ -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 deleted file mode 100644 index 2347c3aa2e..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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; - -/** - * Defines a rendering pass made by the framegraph. - * - * @author codex - */ -public interface FGPass { - - public String getName(); - - public ArrayList getSinks(); - - public ArrayList getSources(); - - public boolean isResetResources(); - - public void prepare(RenderContext renderContext); - - public void execute(RenderContext renderContext); - - public FGSource getSource(String name); - - public FGSink getSink(String registeredName); - - public void setSinkLinkage(String registeredName, String targetPass, String targetResource); - - public void registerSink(AbstractFGSink sink); - - public void registerSource(FGSource source); - - 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 deleted file mode 100644 index ae61b2a9f6..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java +++ /dev/null @@ -1,109 +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.renderer.ViewPort; -import com.jme3.renderer.queue.GeometryList; -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.renderer.pass.GeometryRenderHandler; - -/** - * All passes that need to perform rendering must inherit from this class.. - * - * @author JohnKkk - */ -public abstract class FGRenderQueuePass extends FGBindingPass implements GeometryRenderHandler { - - 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 drawCommands; - protected boolean canExecute = false; - - public FGRenderQueuePass(String name) { - super(name); - } - - /** - * A RenderPass may use a specified viewport. - * - * @param forceViewPort targetViewPort - */ - public void setForceViewPort(ViewPort forceViewPort) { - this.forceViewPort = forceViewPort; - } - - /** - * 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(RenderContext renderContext) { - renderContext.getRenderManager().setGeometryRenderHandler(this); - dispatchPassSetup(renderContext.getRenderQueue()); - if(!canExecute){ - renderContext.getRenderManager().setGeometryRenderHandler(null); - return; - } - bindAll(renderContext); - - // todo:Use the default queue temporarily to avoid creating a temporary copy - //if(passMeshDrawCommandList != null && passMeshDrawCommandList.size() > 0){ - // drawcall - //} - executeDrawCommands(renderContext); - renderContext.getRenderManager().setGeometryRenderHandler(null); - } - - /** - * For the current GLRenderer, the MeshDrawCommand concept actually does not exist. - *

    - * This is prepared for future Vulkan-like renderers. - * - * @param context - */ - public abstract void executeDrawCommands(RenderContext context); - - @Override - public void resetPass() { - super.resetPass(); - 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 deleted file mode 100644 index 0c165de960..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGShaderResource.java +++ /dev/null @@ -1,58 +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; - -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/FGSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java deleted file mode 100644 index 13fcf40f89..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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 codex - */ -public interface FGSink { - - public boolean isRequired(); - - public String getRegisteredName(); - - public String getLinkPassName(); - - public String getLinkPassResName(); - - public void setTarget(String inPassName, String inPassResName); - - public void bind(FGSource fgSource); - - public void postLinkValidate(); - - public boolean isLinkValidate(); - - public default FGBindable getBind() { - return null; - } - -} 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 deleted file mode 100644 index 269635f1ef..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java +++ /dev/null @@ -1,48 +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; - -/** - * @author JohnKkk - */ -public class FGVarBindableSink extends BindableSink { - - public FGVarBindableSink(String registeredName) { - super(registeredName); - } - - @Override - 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 deleted file mode 100644 index 996fcaca3d..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java +++ /dev/null @@ -1,77 +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; - -/** - * @author JohnKkk - * @param - */ -public class FGVarSource extends AbstractFGSource { - - public static class FGVarBindableProxy implements FGBindable { - - T value; - - public FGVarBindableProxy(T value) { - this.value = value; - } - - public T getValue() { - return value; - } - - @Override - public void bind(RenderContext renderContext) {} - - } - - private final FGVarBindableProxy varBindableProxy; - - public FGVarSource(String name, T value) { - super(name); - varBindableProxy = new FGVarBindableProxy<>(value); - } - - public void setValue(T t){ - varBindableProxy.value = t; - } - - @Override - public void postLinkValidate() { - - } - - @Override - public FGBindable yieldBindable() { - return varBindableProxy; - } -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java deleted file mode 100644 index 933374d5cb..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferCopyParam.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.framegraph.parameters.RenderParameter; -import com.jme3.renderer.Renderer; -import com.jme3.texture.FrameBuffer; - -/** - * - * @author codex - */ -public class FrameBufferCopyParam implements RenderParameter { - - private final String name; - private Renderer renderer; - private FrameBuffer target, source; - private final boolean copyColor, copyDepth; - private boolean ready = true; - - public FrameBufferCopyParam(String name, Renderer renderer, FrameBuffer target, boolean copyColor, boolean copyDepth) { - this.name = name; - this.renderer = renderer; - this.target = target; - this.copyColor = copyColor; - this.copyDepth = copyDepth; - } - - @Override - public String getParameterName() { - return name; - } - @Override - public void set(FrameBuffer value) { - if (source != value || ready) { - source = value; - if ((source != null || target != null) && renderer != null) { - renderer.copyFrameBuffer(source, target, copyColor, copyDepth); - ready = false; - } - } - } - @Override - public FrameBuffer get() { - return target; - } - - public void setRenderer(Renderer renderer) { - this.renderer = renderer; - } - public void setTarget(FrameBuffer target) { - this.target = target; - } - public void setReady(boolean ready) { - this.ready = ready; - } - - public FrameBuffer getSource() { - return source; - } - public boolean isCopyColor() { - return copyColor; - } - public boolean isCopyDepth() { - return copyDepth; - } - -} 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 493bb1443a..412337ec9e 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,296 +1,45 @@ /* - * 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; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.LinkedList; /** - * 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 + * Manages render passes, dependencies, and resources in a node-based parameter system. * - * @author JohnKkk + * @author codex */ public class FrameGraph { - private static final Logger logger = Logger.getLogger(FrameGraph.class.getName()); - - private final RenderContext renderContext; - private final ArrayList passes; - private final ArrayList globalSources; - private final ArrayList globalSinks; - private boolean finalized = false; - - public FrameGraph(RenderContext renderContext) { - passes = new ArrayList<>(); - globalSinks = new ArrayList<>(); - globalSources = new ArrayList<>(); - this.renderContext = renderContext; - } - - public RenderContext getRenderContext() { - return renderContext; - } + private final LinkedList passes = new LinkedList<>(); + private final ResourceRegistry resources; - /** - * 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 s : globalSinks){ - String linkPassName = s.getLinkPassName(); - for(FGPass p : passes){ - if(p.getName().equals(linkPassName)){ - FGSource source = p.getSource(s.getLinkPassResName()); - s.bind(source); - break; - } - } - } + public FrameGraph(ResourcePool pool) { + this.resources = new ResourceRegistry(pool); } - - /** - * 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(); - - if((linkPassName == null || linkPassName.isEmpty())){ - if(sink.isRequired()){ - 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{ - 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()){ - logger.throwing(FrameGraph.class.toString(), "", new NullPointerException("Pass named [" + linkPassName + "] not found")); -// 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()){ - logger.throwing(FrameGraph.class.toString(), "", new NullPointerException("Pass named [" + linkPassName + "] not found")); -// System.err.println("Pass named [" + linkPassName + "] not found"); - return; - } - } + + public void cull() { + // count number of outputs for each pass + for (RenderPass p : passes) { + p.countReferences(); + } + // fetch unreferences resources + LinkedList cull = new LinkedList<>(); + resources.getUnreferencedResources(cull); + RenderResource res; + while ((res = cull.pollFirst()) != null) { + // dereference producer of resource + if (!res.getProducer().dereference()) { + // if producer is not referenced, dereference all input resources + res.getProducer().dereferenceInputs(resources, cull); } } } - - /** - * Execute frameGraph - *

    - * example: - * - * FrameGraph fg = new FrameGraph(); - * fg.addPass(pass1); - * fg.addPass(pass2); - * fg.finalize(); - * fg.execute(); - * - */ + public void execute() { - assert finalized; - for(FGPass p : passes){ - p.execute(renderContext); - } - 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){ - nextPass.resetPass(); - } - passes.clear(); - if(renderContext != null) { - renderContext.getRenderManager().setGeometryRenderHandler(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++){ - if(globalSources.get(i).getName().equals(source.getName())){ - index = i; - break; - } - } - if(index >= 0){ - globalSources.remove(index); - } - 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 void addPass(FGPass pass){ - assert !finalized; - // validate name uniqueness - for(FGPass nextPass : passes){ - if(nextPass.getName().equals(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().isEmpty()) { - 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; - } - } - logger.throwing(FrameGraph.class.toString(), "", new NullPointerException("Failed to find pass 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 finalizePasses(){ - assert !finalized; - for(FGPass nextPass : passes){ - nextPass.finalizePass(); - } - linkGlobalSinks(); - finalized = true; - } } 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 deleted file mode 100644 index 5ce894fc5d..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FramebufferSource.java +++ /dev/null @@ -1,72 +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.texture.FrameBuffer; - -/** - * @author JohnKkk - */ -public class FramebufferSource extends AbstractFGSource { - - private final FrameBufferSourceProxy frameBufferSourceProxy; - - public final static class FrameBufferSourceProxy implements FGBindable { - - private FrameBuffer frameBuffer; - - public FrameBufferSourceProxy(FrameBuffer frameBuffer) { - this.frameBuffer = frameBuffer; - } - - public FrameBuffer getFrameBuffer() { - return frameBuffer; - } - @Override - public void bind(RenderContext renderContext) {} - - } - public FramebufferSource(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/MatParamSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java deleted file mode 100644 index 05ccf7ddbe..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java +++ /dev/null @@ -1,70 +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 com.jme3.texture.FrameBuffer; - -public class MatParamSink extends BindableSink { - - private final Material material; - private final VarType type; - private Object value; - - public MatParamSink(String name, Material material, VarType type) { - super(name); - this.material = material; - this.type = type; - } - - @Override - 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 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/MyFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java deleted file mode 100644 index 2ec67a2a7f..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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.framegraph.pass.FGModule; -import com.jme3.renderer.framegraph.parameters.RenderParameterGroup; -import com.jme3.renderer.framegraph.parameters.ParameterBinding; -import com.jme3.renderer.framegraph.parameters.ParameterSpace; -import com.jme3.renderer.framegraph.parameters.RenderParameter; -import com.jme3.profile.AppProfiler; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.ViewPort; -import java.util.LinkedList; - -/** - * Manages render passes, dependencies, and resources in a node-based parameter system. - * - * @author codex - */ -public class MyFrameGraph { - - private final LinkedList passes = new LinkedList<>(); - private final LinkedList executionQueue = new LinkedList<>(); - private final ParameterSpace parameters = new ParameterSpace(); - private final RenderContext context; - - public MyFrameGraph(RenderManager renderManager) { - context = new RenderContext(renderManager); - } - - /** - * Prepares the context for rendering with the viewport. - * - * @param vp viewport being rendered - * @param tpf time per frame - */ - public void prepareRender(ViewPort vp, float tpf) { - prepareRender(vp, null, tpf); - } - - /** - * Prepares the context for rendering with the viewport. - * - * @param vp viewport being rendered - * @param prof app profiler, or null for no profiling - * @param tpf time per frame - */ - public void prepareRender(ViewPort vp, AppProfiler prof, float tpf) { - context.update(vp, prof, tpf); - } - - /** - * - */ - public void preFrame() { - for (FGModule p : passes) { - p.preFrame(context); - } - } - - /** - * - */ - public void postQueue() { - for (FGModule p : passes) { - p.postQueue(context); - } - } - - /** - * Executes this framegraph for rendering. - */ - public void execute() { - // prepare passes for execution - for (FGModule p : passes) { - if (p.prepare(context)) { - executionQueue.add(p); - } - } - // execute - for (FGModule p : executionQueue) { - // accept parameters as arguments to the pass - parameters.pull(p); - // execute pass - if (p.readyForExecution(context)) { - p.execute(context); - parameters.push(p); - resetRenderState(); - } - } - // reset passes - for (FGModule p : passes) { - p.reset(); - } - executionQueue.clear(); - } - - /** - * Resets the render state so that one pass's render does not affect another render. - */ - protected void resetRenderState() { - context.setDepthRange(DepthRange.IDENTITY); - context.getRenderManager().setGeometryRenderHandler(null); - } - - /** - * Adds the pass to this framegraph and registers it with the - * local parameter space. - * - * @param pass - */ - public void add(FGModule pass) { - pass.initialize(this); - passes.add(pass); - registerParameterGroup(pass); - } - - /** - * Gets the first pass that is of or a subclass of the given type. - * - * @param - * @param type - * @return pass of the given type, or null if none exists - */ - public T get(Class type) { - for (FGModule p : passes) { - if (type.isAssignableFrom(p.getClass())) { - return (T)p; - } - } - return null; - } - - /** - * Gets the local parameter space. - * - * @return - */ - public ParameterSpace getLocalParameters() { - return parameters; - } - - /** - * Gets the world parameter space belonging to the render manager. - * - * @return - */ - public ParameterSpace getWorldParameters() { - return context.getRenderManager().getParameters(); - } - - /** - * Gets the render context. - * - * @return - */ - public RenderContext getContext() { - return context; - } - - /** - * Registers the parameter with the local parameter space. - * - * @param - * @param param - * @return the given parameter - */ - public T registerParameter(T param) { - parameters.register(param); - return param; - } - - /** - * Registers the parameter group with the local parameter space. - * - * @param group - */ - public void registerParameterGroup(RenderParameterGroup group) { - parameters.register(group); - } - - /** - * Binds the given input parameter to the named target output parameter in - * the local parameter space. - * - * @param target - * @param input - * @return - */ - public ParameterBinding bindToOutput(String target, RenderParameter input) { - return parameters.bindToOutput(target, input); - } - - /** - * Binds the given output parameter to the named target input parameter in - * the local parameter space. - * - * @param target - * @param output - * @return - */ - public ParameterBinding bindToInput(String target, RenderParameter output) { - return parameters.bindToInput(target, output); - } - - /** - * Removes the parameter from the local parameter space. - * - * @param param - */ - public void removeParameter(RenderParameter param) { - parameters.remove(param); - } - - /** - * Removes the parameter group from the local parameter space. - * - * @param group - */ - public void removeParameterGroup(RenderParameterGroup group) { - parameters.remove(group); - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java index 71cfc4d10d..843e1e9353 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java @@ -70,6 +70,7 @@ public void update(ViewPort vp, AppProfiler profiler, float tpf) { } Camera cam = viewPort.getCamera(); sizeChanged = width != cam.getWidth() || height != cam.getHeight(); + //System.out.println("size changed? "+sizeChanged); width = cam.getWidth(); height = cam.getHeight(); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java new file mode 100644 index 0000000000..842a376282 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java @@ -0,0 +1,40 @@ +/* + * 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.LinkedList; +import java.util.List; + +/** + * + * @author codex + */ +public class RenderPass { + + private final LinkedList inputs = new LinkedList<>(); + private final LinkedList outputs = new LinkedList<>(); + private int refs; + + public void countReferences() { + refs = outputs.size(); + } + public boolean dereference() { + refs--; + return isReferenced(); + } + public boolean isReferenced() { + return refs > 0; + } + + public void dereferenceInputs(ResourceRegistry registry, List resList) { + for (ResourceTicket i : inputs) { + RenderResource r = registry.locateResource(i); + if (!r.dereference()) { + resList.add(r); + } + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java index a889496ffc..e48681e83e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java @@ -23,7 +23,7 @@ */ public class RenderPipelineFactory { - public static MyFrameGraph create(Application app, RenderPath path) { + public static FrameGraph create(Application app, RenderPath path) { RenderManager rm = app.getRenderManager(); switch (path) { case Forward: return createForwardPipeline(rm); @@ -34,7 +34,7 @@ public static MyFrameGraph create(Application app, RenderPath path) { } } - private static MyFrameGraph addBasicPasses(MyFrameGraph g) { + private static FrameGraph addBasicPasses(FrameGraph g) { g.add(ForwardModule.opaque()); g.add(ForwardModule.sky()); g.add(ForwardModule.transparent()); @@ -44,18 +44,18 @@ private static MyFrameGraph addBasicPasses(MyFrameGraph g) { return g; } - public static MyFrameGraph createForwardPipeline(RenderManager rm) { - return addBasicPasses(new MyFrameGraph(rm)); + public static FrameGraph createForwardPipeline(RenderManager rm) { + return addBasicPasses(new FrameGraph(rm)); } - public static MyFrameGraph createForwardPlusPipeline(RenderManager rm) { + public static FrameGraph createForwardPlusPipeline(RenderManager rm) { throw new UnsupportedOperationException("ForwardPlus render pipeline is currently unsupported."); } - public static MyFrameGraph createDeferredPipeline(AssetManager am, RenderManager rm) { - MyFrameGraph g = new MyFrameGraph(rm); + public static FrameGraph createDeferredPipeline(AssetManager am, RenderManager rm) { + FrameGraph g = new FrameGraph(rm); g.add(new GBufferModule()); - g.add(new DeferredShadingModule(am)); + //g.add(new DeferredShadingModule(am)); g.add(ForwardModule.sky()); g.add(ForwardModule.transparent()); g.add(new GuiModule()); @@ -64,15 +64,15 @@ public static MyFrameGraph createDeferredPipeline(AssetManager am, RenderManager return g; } - public static MyFrameGraph createTileDeferredPipeline(AssetManager am, RenderManager rm) { - MyFrameGraph g = new MyFrameGraph(rm); + public static FrameGraph createTileDeferredPipeline(AssetManager am, RenderManager rm) { + FrameGraph g = new FrameGraph(rm); g.add(new GBufferModule()); g.add(new TileDeferredShadingModule(am)); return addBasicPasses(g); } - public static MyFrameGraph createBackroundScreenTest(AssetManager am, RenderManager rm) { - MyFrameGraph g = new MyFrameGraph(rm); + public static FrameGraph createBackroundScreenTest(AssetManager am, RenderManager rm) { + FrameGraph g = new FrameGraph(rm); g.add(new BackgroundScreenTestModule(am)); g.add(ForwardModule.opaque()); g.add(ForwardModule.sky()); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java new file mode 100644 index 0000000000..592ebd8ff3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -0,0 +1,74 @@ +/* + * 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 class RenderResource { + + private final RenderPass producer; + private final ResourceDef def; + private final ResourceTicket ticket; + private T resource; + private int refs = 0; + private int users = 0; + + public RenderResource(RenderPass producer, ResourceDef def, ResourceTicket ticket) { + this.producer = producer; + this.def = def; + this.ticket = ticket; + } + + public void create() { + if (resource == null) { + resource = def.create(); + } + } + public void setResource(T resource) { + this.resource = resource; + } + + public void acquire() { + users++; + } + public boolean release() { + users--; + return isUsed(); + } + public boolean isUsed() { + return users > 0; + } + + public void reference() { + refs++; + } + public boolean dereference() { + refs--; + return isReferenced(); + } + public boolean isReferenced() { + return refs > 0; + } + + public RenderPass getProducer() { + return producer; + } + public ResourceDef getDefinition() { + return def; + } + public ResourceTicket getTicket() { + return ticket; + } + public T getResource() { + return resource; + } + public boolean isVirtual() { + return resource == null; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAction.java new file mode 100644 index 0000000000..0c16714bb3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAction.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; + +/** + * + * @author codex + */ +public enum ResourceAction { + + /** + * The resource will only be read from. + */ + Read(true, false), + + /** + * The resource will only be written to. + */ + Write(false, true), + + /** + * The resource will be read from and written to. + */ + ReadAndWrite(true, true); + + private final boolean read, write; + + private ResourceAction(boolean read, boolean write) { + this.read = read; + this.write = write; + } + + public boolean isRead() { + return read; + } + public boolean isWrite() { + return write; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java new file mode 100644 index 0000000000..71c5a071c8 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java @@ -0,0 +1,27 @@ +/* + * 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 class ResourceDef { + + private Class resType; + + public T create() { + return null; + } + + public T repurpose(ResourceDef def, R resource) { + if (resType.isAssignableFrom(resource.getClass())) { + return (T)resource; + } + return null; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourcePool.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourcePool.java new file mode 100644 index 0000000000..4239778737 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourcePool.java @@ -0,0 +1,38 @@ +/* + * 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.Iterator; +import java.util.LinkedList; + +/** + * + * @author codex + */ +public class ResourcePool { + + private final LinkedList resources = new LinkedList<>(); + + public void add(RenderResource res) { + if (res.isVirtual()) { + throw new IllegalArgumentException("Resource cannot be virtual."); + } + resources.add(res); + } + + public boolean acquireExisting(RenderResource resource) { + for (Iterator it = resources.iterator(); it.hasNext();) { + RenderResource r = it.next(); + T result = resource.getDefinition().repurpose(r.getDefinition(), r.getResource()); + if (result != null) { + resource.setResource(result); + it.remove(); + return true; + } + } + return false; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRegistry.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRegistry.java new file mode 100644 index 0000000000..993c879541 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRegistry.java @@ -0,0 +1,86 @@ +/* + * 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; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * + * @author codex + */ +public class ResourceRegistry { + + private final ArrayList resources = new ArrayList<>(); + private final ResourcePool pool; + + public ResourceRegistry(ResourcePool pool) { + this.pool = pool; + } + + protected RenderResource locateResource(ResourceTicket ticket) { + if (ticket.isLocateByName()) { + String name = ticket.getName(); + int i = 0; + for (RenderResource r : resources) { + if (r.getTicket().getName().equals(name)) { + // make the next location operation with this ticket faster + ticket.setIndex(i); + return r; + } + i++; + } + throw new NullPointerException("Unable to locate resource by "+ticket); + } else { + int i = ticket.getIndex(); + if (i < 0 || i >= resources.size()) { + throw new IndexOutOfBoundsException(ticket+" for size "+resources.size()); + } + RenderResource res = resources.get(i); + if (!res.getTicket().getName().equals(ticket.getName())) { + throw new NullPointerException("Unable to locate resource by "+ticket); + } + return res; + } + } + + public ResourceTicket registerFutureResource(RenderPass producer, String name, ResourceDef def) { + ResourceTicket ticket = new ResourceTicket(name, resources.size()); + RenderResource res = new RenderResource<>(producer, def, ticket); + resources.add(res); + return ticket; + } + + public void referenceResource(ResourceTicket ticket) { + locateResource(ticket).reference(); + } + + public T acquireResource(ResourceTicket ticket) { + RenderResource res = locateResource(ticket); + if (res.isVirtual() && !pool.acquireExisting(res)) { + res.create(); + } + res.acquire(); + return res.getResource(); + } + + public void releaseResource(ResourceTicket ticket) { + RenderResource res = locateResource(ticket); + if (!res.release()) { + pool.add(res); + } + } + + public void getUnreferencedResources(List resList) { + for (RenderResource r : resources) { + if (!r.isReferenced()) { + resList.add(r); + } + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java new file mode 100644 index 0000000000..b0fdeb6de9 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -0,0 +1,59 @@ +/* + * 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; + +/** + * References a {@link RenderResource} by either name or index. + *

    + * If a resource is referenced by name, the index of the resource + * will be assigned to the ticket, in order to make future references + * faster. + * + * @author codex + * @param + */ +public class ResourceTicket { + + private String name; + private int index; + + public ResourceTicket(String name) { + this(name, -1); + } + public ResourceTicket(int index) { + this(null, index); + } + public ResourceTicket(String name, int index) { + this.name = name; + this.index = index; + } + + public ResourceTicket copy() { + return new ResourceTicket(name, index); + } + + public void setName(String name) { + this.name = name; + } + public void setIndex(int index) { + this.index = index; + } + + public String getName() { + return name; + } + public int getIndex() { + return index; + } + public boolean isLocateByName() { + return index < 0 && name != null; + } + + @Override + public String toString() { + return "ResourceTicket[name="+(name != null ? "\""+name+"\"" : null)+", index="+index+"]"; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java deleted file mode 100644 index 2b8d391f47..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/MatRenderParam.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.parameters; - -import com.jme3.renderer.framegraph.parameters.RenderParameter; -import com.jme3.material.Material; -import com.jme3.shader.VarType; - -/** - * - * @author codex - * @param - */ -public class MatRenderParam implements RenderParameter { - - private final String name; - private final String matName; - private final Material material; - private final VarType type; - private boolean debug = false; - private T value; - - public MatRenderParam(String name, Material material, VarType type) { - this(name, material, name, type); - } - public MatRenderParam(String name, Material material, String matName, VarType type) { - this.name = name; - this.matName = matName; - this.material = material; - this.type = type; - } - - @Override - public String getParameterName() { - return name; - } - @Override - public void set(T value) { - this.value = value; - if (debug) { - System.out.println("assign to material: "+this.value); - } - material.setParam(matName, type, this.value); - } - @Override - public T get() { - return value; - } - @Override - public void erase() { - value = null; - } - - public void enableDebug() { - debug = true; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java deleted file mode 100644 index 57dd9927ed..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterBinding.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.parameters; - -/** - * - * @author codex - * @param - */ -public class ParameterBinding { - - private final RenderParameter output, input; - - public ParameterBinding(RenderParameter output, RenderParameter input) { - this.output = output; - this.input = input; - } - - /** - * Applies the output parameter to the input parameter. - */ - public void applyOutputToInput() { - input.set(output.get()); - } - - /** - * Returns true if the given parameter is the input parameter of this binding. - * - * @param input - * @return - */ - public boolean isInput(RenderParameter input) { - return this.input == input; - } - - /** - * Returns true if the given parameter is the output parameter of this binding. - * - * @param output - * @return - */ - public boolean isOutput(RenderParameter output) { - return this.output == output; - } - - /** - * Returns true if the given parameter is a member of this binding. - * - * @param param - * @return - */ - public boolean contains(RenderParameter param) { - return input == param || output == param; - } - - /** - * Returns true if the named parameter is a member of this binding. - * - * @param name - * @return - */ - public boolean containsNamed(String name) { - return input.isPubliclyNamed(name) || output.isPubliclyNamed(name); - } - - /** - * Returns true if this binding is violating the given binding. - * - * @param binding - * @return - */ - public boolean isViolating(ParameterBinding binding) { - return input == binding.input; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterSpace.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterSpace.java deleted file mode 100644 index bda8f68104..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ParameterSpace.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * 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.parameters; - -import java.util.Iterator; -import java.util.LinkedList; - -/** - * - * @author codex - */ -public class ParameterSpace { - - private final LinkedList parameters = new LinkedList<>(); - private final LinkedList localBindings = new LinkedList<>(); - - /** - * Returns the named parameter, or null if none exists. - * - * @param name - * @param failOnMiss - * @return named parameter - * @throws NullPointerException if the named parameter does not exist and failOnMiss is true - */ - public RenderParameter getParameter(String name, boolean failOnMiss) { - for (RenderParameter p : parameters) { - if (p.isPubliclyNamed(name)) { - return p; - } - } - if (failOnMiss) { - throw new NullPointerException("Input parameter \""+name+"\" does not exist or is private."); - } - return null; - } - - /** - * Returns the named parameter of the given type, or null if none exists. - * - * @param - * @param name - * @param type - * @param failOnMiss - * @return named parameter - * @throws NullPointerException if the named parameter does not exist and failOnMiss is true - */ - public T getParameter(String name, Class type, boolean failOnMiss) { - for (RenderParameter p : parameters) { - if (p.isPubliclyNamed(name) && type.isAssignableFrom(p.getClass())) { - return (T)p; - } - } - if (failOnMiss) { - throw new NullPointerException("Input parameter \""+name+"\" does not exist, or is private, " - + "or is not of type "+type.getName()+"."); - } - return null; - } - - /** - * Registers and returns the parameter. - * - * @param - * @param param - * @return - */ - public T register(T param) { - parameters.add(param); - return param; - } - - /** - * Registers all given parameters. - * - * @param params - */ - public void registerAll(RenderParameter... params) { - for (RenderParameter p : params) { - register(p); - } - } - - /** - * Registers all parameters in the group. - * - * @param group - */ - public void register(RenderParameterGroup group) { - for (RenderParameter p : group.getRenderParameters()) { - register(p); - } - } - - /** - * Removes the parameter from this space and breaks all related bindings. - * - * @param param - */ - public void remove(RenderParameter param) { - parameters.remove(param); - for (Iterator it = localBindings.iterator(); it.hasNext();) { - if (it.next().contains(param)) { - it.remove(); - } - } - } - - /** - * Removes all parameters in the group from this space. - * - * @param group - * @see #remove(com.jme3.renderer.framegraph.parameters.RenderParameter) - */ - public void remove(RenderParameterGroup group) { - for (RenderParameter p : group.getRenderParameters()) { - remove(p); - } - } - - /** - * Binds the named parameter and the input parameter locally, with the named parameter - * as the output, and returns the resulting binding. - *

    - * The input parameter should already be registered with this space. - * - * @param target - * @param input - * @return - */ - public ParameterBinding bindToOutput(String target, RenderParameter input) { - return createBinding(getParameter(target, false), input); - } - - /** - * Binds the named parameter and the output parameter locally, with the named parameter - * as the input, and returns the resulting binding. - *

    - * The output parameter should already be registered with this space. - * - * @param target - * @param output - * @return - */ - public ParameterBinding bindToInput(String target, RenderParameter output) { - return createBinding(output, getParameter(target, false)); - } - - /** - * Binds the two parameters and returns the resulting binding. - *

    - * Both parameters should already be registered with this space. - * - * @param output - * @param input - * @return - */ - public ParameterBinding bind(RenderParameter output, RenderParameter input) { - return createBinding(output, input); - } - - /** - * Registers the binding with this space. - * - * @param binding - * @return - */ - public ParameterBinding registerBinding(ParameterBinding binding) { - breakViolatingBindings(binding); - localBindings.add(binding); - return binding; - } - - private ParameterBinding createBinding(RenderParameter output, RenderParameter input) { - if (output == null || input == null) { - return null; - } - ParameterBinding binding = new ParameterBinding(output, input); - breakViolatingBindings(binding); - localBindings.add(binding); - return binding; - } - - private void breakViolatingBindings(ParameterBinding binding) { - for (Iterator it = localBindings.iterator(); it.hasNext();) { - if (it.next().isViolating(binding)) { - it.remove(); - } - } - } - - /** - * Pulls values from parameters bound as output to the given parameter. - * - * @param input - */ - public void pull(RenderParameter input) { - for (ParameterBinding b : localBindings) { - if (b.isInput(input)) { - b.applyOutputToInput(); - break; - } - } - } - - /** - * Pulls values from parameters bound as output to parameters in the given group. - * - * @param group - */ - public void pull(RenderParameterGroup group) { - for (RenderParameter p : group.getRenderParameters()) { - pull(p); - } - } - - /** - * Pushes values to parameters bound as input to the given parameter. - * - * @param output - */ - public void push(RenderParameter output) { - for (ParameterBinding b : localBindings) { - if (b.isOutput(output)) { - b.applyOutputToInput(); - } - } - } - - /** - * Pushes values to parameters bound as input to parameters in the given group. - * - * @param group - */ - public void push(RenderParameterGroup group) { - for (RenderParameter p : group.getRenderParameters()) { - push(p); - } - } - - /** - * Clears this space of all parameters and bindings. - */ - public void clear() { - parameters.clear(); - localBindings.clear(); - } - - /** - * Returns the list of parameters. - *

    - * Do not modify the returned list. - * - * @return - */ - public LinkedList getParameterList() { - return parameters; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java deleted file mode 100644 index 8886d6c2b9..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameter.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.parameters; - -/** - * - * @author codex - * @param - */ -public interface RenderParameter { - - /** - * When returned as the parameter name, other classes will be unable to access this parameter. - */ - public static final String PRIVATE = null; - - /** - * Returns the name this parameter is identified by. - * - * @return - */ - public String getParameterName(); - - /** - * Applies the given value to this parameter. - * - * @param value - */ - public void set(T value); - - /** - * Returns the value held by this parameter. - * - * @return - */ - public T get(); - - /** - * Deletes the value held by this parameter. - */ - public default void erase() { - set(null); - } - - /** - * Returns true if the value returned by {@link #get()} is not null. - * - * @return - */ - public default boolean validate() { - return get() != null; - } - - /** - * Returns the value returned by {@link #get()} if {@link #validate()} - * returns true, otherwise returns the given value. - * - * @param value - * @return - */ - public default T orElse(T value) { - if (validate()) { - return get(); - } else { - return value; - } - } - - /** - * Returns true if this parameter is publicly accessible. - * - * @return - */ - public default boolean isPublic() { - return getParameterName() != null; - } - - /** - * Returns true if this parameter is public and named the given name. - * - * @param name - * @return - */ - public default boolean isPubliclyNamed(String name) { - return isPublic() && getParameterName().equals(name); - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameterGroup.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameterGroup.java deleted file mode 100644 index 315f1fa144..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/RenderParameterGroup.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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.parameters; - -import com.jme3.renderer.framegraph.parameters.RenderParameter; -import java.util.Collection; - -/** - * - * @author codex - */ -public interface RenderParameterGroup { - - public Collection getRenderParameters(); - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java deleted file mode 100644 index 348997d69a..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/TextureTargetParam.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.parameters; - -import com.jme3.texture.FrameBuffer.FrameBufferTextureTarget; -import com.jme3.texture.Texture; - -/** - * - * @author codex - */ -public class TextureTargetParam implements RenderParameter { - - private final String name; - private FrameBufferTextureTarget target; - - public TextureTargetParam(String name, FrameBufferTextureTarget target) { - this.name = name; - this.target = target; - } - - @Override - public Texture get() { - if (target != null) { - return target.getTexture(); - } else { - return null; - } - } - - @Override - public String getParameterName() { - return name; - } - - @Override - public void set(Texture value) {} - - @Override - public void erase() { - target = null; - } - - public void setTextureTarget(FrameBufferTextureTarget target) { - this.target = target; - } - - public FrameBufferTextureTarget getTextureTarget() { - return target; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java deleted file mode 100644 index be7cd990f7..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/ValueRenderParam.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.parameters; - -/** - * - * @author codex - * @param - */ -public class ValueRenderParam implements RenderParameter { - - private final String name; - private T value; - private T defaultValue; - - public ValueRenderParam(String name) { - this(name, null, null); - } - public ValueRenderParam(String name, T value) { - this(name, value, null); - } - public ValueRenderParam(String name, T value, T defaultValue) { - this.name = name; - this.value = value; - this.defaultValue = defaultValue; - } - - @Override - public String getParameterName() { - return name; - } - @Override - public void set(T value) { - this.value = value; - } - @Override - public T get() { - return (value != null ? value : defaultValue); - } - - public T produceRaw() { - return value; - } - - public void setDefaultValue(T defaultValue) { - this.defaultValue = defaultValue; - } - - public T getDefaultValue() { - return defaultValue; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/WorldRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/WorldRenderParam.java deleted file mode 100644 index c610658f2c..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/parameters/WorldRenderParam.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.parameters; - -/** - * - * @author codex - * @param - */ -public class WorldRenderParam implements RenderParameter { - - private final String name; - private ParameterSpace space; - private String target; - private boolean pull; - - public WorldRenderParam(String name, ParameterSpace space, String target) { - this(name, space, target, true); - } - public WorldRenderParam(String name, ParameterSpace space, String target, boolean pull) { - this.name = name; - this.space = space; - this.target = target; - this.pull = pull; - } - - @Override - public String getParameterName() { - return name; - } - @Override - public void set(T value) { - RenderParameter p = space.getParameter(target, false); - if (p != null) { - p.set(value); - } - } - @Override - public T get() { - RenderParameter p = space.getParameter(target, false); - if (p != null) { - return p.get(); - } else { - return null; - } - } - - public void setSpace(ParameterSpace space) { - this.space = space; - } - public void setTarget(String target) { - this.target = target; - } - public void setPull(boolean pull) { - this.pull = pull; - } - - public ParameterSpace getSpace() { - return space; - } - public String getTarget() { - return target; - } - public boolean isPull() { - return pull; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java index f0fabbd67e..84ebad36a8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java @@ -5,8 +5,8 @@ package com.jme3.renderer.framegraph.pass; import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.pass.FGModule; -import com.jme3.renderer.framegraph.parameters.RenderParameter; +import com.jme3.renderer.framegraph.parameters.ParamSocket; +import com.jme3.renderer.framegraph.parameters.Referenceable; import java.util.Collection; import java.util.LinkedList; @@ -16,11 +16,18 @@ */ public abstract class AbstractModule implements FGModule { - private final LinkedList parameters = new LinkedList<>(); + private final LinkedList inSockets = new LinkedList<>(); + private final LinkedList outSockets = new LinkedList<>(); + private int refs = 0; @Override - public Collection getRenderParameters() { - return parameters; + public Collection getInputSockets() { + return inSockets; + } + + @Override + public Collection getOutputSockets() { + return outSockets; } @Override @@ -28,15 +35,25 @@ public void preFrame(RenderContext context) {} @Override public void postQueue(RenderContext context) {} - + + @Override + public int compileNumReferences() { + return (refs = outSockets.size()); + } + + @Override + public int removeReference() { + return --refs; + } + @Override - public boolean readyForExecution(RenderContext context) { - return true; + public void dereferenceUpstream(Collection derefs) { + derefs.addAll(inSockets); } - protected final T addParameter(T p) { - parameters.add(p); - return p; + @Override + public int getNumReferences() { + return refs; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java index e07593161f..b0c10a9b58 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java @@ -7,7 +7,7 @@ import com.jme3.asset.AssetManager; import com.jme3.material.Material; import com.jme3.material.RenderState; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.texture.Texture2D; import com.jme3.ui.Picture; @@ -26,7 +26,7 @@ public BackgroundScreenTestModule(AssetManager assetManager) { } @Override - public void initialize(MyFrameGraph frameGraph) { + public void initialize(FrameGraph frameGraph) { screen = new Picture("TestScreen"); screen.setWidth(1f); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java index 6b928200dc..dbcc423572 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java @@ -14,7 +14,7 @@ import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.parameters.MatRenderParam; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.parameters.TextureTargetParam; import com.jme3.renderer.framegraph.parameters.ValueRenderParam; @@ -27,7 +27,7 @@ * * @author codex */ -public class DeferredShadingModule extends AbstractModule { +public class DeferredShadingModule extends ScreenModule { public final static String RT_0 = "Context_InGBuff0"; public final static String RT_1 = "Context_InGBuff1"; @@ -42,9 +42,6 @@ public class DeferredShadingModule extends AbstractModule { private static final String MATDEF = "Common/MatDefs/ShadingCommon/DeferredShading.j3md"; protected final AssetManager assetManager; - protected Material screenMat; - protected Picture screenRect; - protected DeferredSinglePassLightingLogic logic; protected MatRenderParam[] matParams = new MatRenderParam[5]; protected ValueRenderParam lightList; protected ValueRenderParam executeState; @@ -57,37 +54,38 @@ public DeferredShadingModule(AssetManager assetManager) { } @Override - public void initialize(MyFrameGraph frameGraph) { + public void initialize(FrameGraph frameGraph) { - screenMat = createMaterial(); - screenRect = new Picture("DeferredShadingPass_Rect"); - screenRect.setWidth(1); - screenRect.setHeight(1); - screenRect.setIgnoreTransform(true); - screenRect.setMaterial(screenMat); + super.initialize(frameGraph); + Material screenMat = screenRect.getMaterial(); RenderState rs = screenMat.getAdditionalRenderState(); - rs.setDepthWrite(true); rs.setDepthTest(true); + rs.setDepthWrite(true); rs.setDepthFunc(RenderState.TestFunction.Greater); - //rs.setBlendMode(RenderState.BlendMode.Alpha); - //screenMat.setTransparent(true); screenMat.setBoolean("UseLightsCullMode", false); - assignTechniqueLogic(screenMat); + for (TechniqueDef t : screenMat.getMaterialDef().getTechniqueDefs(PASS)) { + t.setLogic(new DeferredSinglePassLightingLogic(t, true)); + } // material render parameters automatically apply their values - matParams[0] = addParameter(new MatRenderParam(RT_0, screenMat, VarType.Texture2D)); - matParams[1] = addParameter(new MatRenderParam(RT_1, screenMat, VarType.Texture2D)); - matParams[2] = addParameter(new MatRenderParam(RT_2, screenMat, VarType.Texture2D)); - matParams[3] = addParameter(new MatRenderParam(RT_3, screenMat, VarType.Texture2D)); - matParams[4] = addParameter(new MatRenderParam(RT_4, screenMat, VarType.Texture2D)); - lightList = addParameter(new ValueRenderParam<>(LIGHT_DATA)); - executeState = addParameter(new ValueRenderParam<>(EXECUTE_STATE)); - gBuffer = addParameter(new ValueRenderParam<>(IN_FRAME_BUFFER)); - depthCopy = addParameter(new TextureTargetParam(DEPTH_DEBUG, null)); + matParams[0] = addInput(new MatRenderParam(RT_0, screenMat, VarType.Texture2D)); + matParams[1] = addInput(new MatRenderParam(RT_1, screenMat, VarType.Texture2D)); + matParams[2] = addInput(new MatRenderParam(RT_2, screenMat, VarType.Texture2D)); + matParams[3] = addInput(new MatRenderParam(RT_3, screenMat, VarType.Texture2D)); + matParams[4] = addInput(new MatRenderParam(RT_4, screenMat, VarType.Texture2D)); + lightList = addInput(new ValueRenderParam<>(LIGHT_DATA)); + executeState = addInput(new ValueRenderParam<>(EXECUTE_STATE)); + gBuffer = addInput(new ValueRenderParam<>(IN_FRAME_BUFFER)); + depthCopy = addOutput(new TextureTargetParam(DEPTH_DEBUG, null)); - bindParameters(frameGraph); + for (int i = 0; i < matParams.length; i++) { + frameGraph.bindToOutput(GBufferModule.RENDER_TARGETS[i], matParams[i]); + } + frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); + frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); + frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, gBuffer); } @Override @@ -102,73 +100,25 @@ public boolean prepare(RenderContext context) { return true; } @Override - public boolean readyForExecution(RenderContext context) { - return executeState.get(); - } - @Override public void execute(RenderContext context) { - + context.getRenderer().copyFrameBuffer(gBuffer.get(), context.getViewPort().getOutputFrameBuffer(), false, true); context.getRenderer().copyFrameBuffer(gBuffer.get(), debug, false, true); - - //makeRenderStateTests(context, "pre tests"); - selectTechnique(screenMat, context.getRenderManager()); + + screenRect.getMaterial().selectTechnique(PASS, context.getRenderManager()); context.setDepthRange(1, 1); context.getRenderer().setFrameBuffer(context.getViewPort().getOutputFrameBuffer()); screenRect.updateGeometricState(); context.getRenderManager().renderGeometry(screenRect, lightList.get()); - //screenMat.render(screenRect, lightList.produce(), context.getRenderManager()); - - //makeRenderStateTests(context, "post tests"); } @Override public void reset() {} - - protected Material createMaterial() { + @Override + protected Material createScreenMaterial() { return new Material(assetManager, MATDEF); } - protected void bindParameters(MyFrameGraph frameGraph) { - for (int i = 0; i < matParams.length; i++) { - frameGraph.bindToOutput(GBufferModule.RENDER_TARGETS[i], matParams[i]); - } - frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); - frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); - frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, gBuffer); - } - protected void assignTechniqueLogic(Material material) { - for (TechniqueDef t : screenMat.getMaterialDef().getTechniqueDefs(PASS)) { - t.setLogic(new DeferredSinglePassLightingLogic(t, true)); - } - } - protected void selectTechnique(Material mat, RenderManager rm) { - mat.selectTechnique(PASS, rm); - } - - private void makeRenderStateTests(RenderContext context, String label) { - Renderer r = context.getRenderer(); - RenderManager rm = context.getRenderManager(); - ViewPort vp = context.getViewPort(); - System.out.println(label+":"); - test(r.getCurrentFrameBuffer(), "framebuffer"); - test(context.getDepthRange(), "depth"); - test(rm.getCurrentCamera(), "camera"); - test(rm.getGeometryRenderHandler(), "handler"); - test(rm.getRenderFilter(), "geometry filter"); - test(rm.getPreferredLightMode(), "preferred light mode"); - test(rm.getForcedTechnique(), "forced technique"); - test(rm.getForcedRenderState(), "forced renderstate"); - test(rm.getForcedMatParams().size(), "num forced mat params"); - test(rm.getLightFilter(), "light filter"); - test(vp.getBackgroundColor(), "viewport background"); - test(vp.getOutputFrameBuffer(), "viewport output framebuffer"); - test("color:"+vp.isClearColor()+", depth:"+vp.isClearDepth()+", stencil:" - +vp.isClearStencil(), "viewport clear flags"); - } - private void test(Object object, String label) { - System.out.println(" "+label+" = "+(object == null ? "null" : object.toString().replaceAll("\n", "; "))); - } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java index b6f674bed7..b6ec8b3614 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java @@ -4,16 +4,16 @@ */ package com.jme3.renderer.framegraph.pass; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.parameters.RenderParameterGroup; +import com.jme3.renderer.framegraph.parameters.SocketGroup; /** * * @author codex * @param */ -public interface FGModule extends RenderParameterGroup { +public interface FGModule extends SocketGroup { /** * Initializes the pass to the framegraph. @@ -26,6 +26,8 @@ public interface FGModule extends RenderParameterGroup /** * Called before the render buckets are queued. + *

    + * This method is called before parameters are pulled. * * @param context */ @@ -33,6 +35,8 @@ public interface FGModule extends RenderParameterGroup /** * Called after the render buckets are queued. + *

    + * This method is called before parameters are pulled. * * @param context */ @@ -41,26 +45,16 @@ public interface FGModule extends RenderParameterGroup /** * Prepares the pass for execution and determines if execution should occur. *

    - * Execution should be vetoed on this step if possible, because the framegraph - * does not need to pull or push parameters from the parameter space for this pass - * if execution is vetoed on this step. + * If execution is vetoed on this step, parameter pulling, execution, parameter + * pushing, and render state reset will not occur. + *

    + * This method is called before parameters are pulled. * * @param context * @return true if execution should occur */ public boolean prepare(RenderContext context); - /** - * Returns true if this pass is ready for execution. - *

    - * If this pass is not ready for execution, the framegraph will not execute - * this pass and will not push parameters from this pass to bound parameters. - * - * @param context - * @return - */ - public boolean readyForExecution(RenderContext context); - /** * Executes this pass. * @@ -69,7 +63,7 @@ public interface FGModule extends RenderParameterGroup public void execute(RenderContext context); /** - * Resets this pass after execution. + * Resets this pass after all passes have been executed. */ public void reset(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java index 813439f5e4..6f7301c395 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java @@ -5,7 +5,7 @@ package com.jme3.renderer.framegraph.pass; import com.jme3.renderer.framegraph.DepthRange; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.queue.RenderQueue; @@ -27,7 +27,7 @@ public ForwardModule(RenderQueue.Bucket bucket, DepthRange depth) { } @Override - public void initialize(MyFrameGraph frameGraph) {} + public void initialize(FrameGraph frameGraph) {} @Override public boolean prepare(RenderContext context) { return !context.getRenderQueue().isQueueEmpty(bucket); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java index b2374fc16c..c6dbce0bd9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java @@ -4,19 +4,18 @@ */ package com.jme3.renderer.framegraph.pass; -import com.jme3.renderer.framegraph.pass.ForwardModule; import com.jme3.light.Light; import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; +import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.renderer.framegraph.parameters.TextureTargetParam; import com.jme3.renderer.framegraph.parameters.ValueRenderParam; -import com.jme3.renderer.pass.GeometryRenderHandler; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; @@ -52,7 +51,7 @@ public GBufferModule() { } @Override - public void initialize(MyFrameGraph frameGraph) { + public void initialize(FrameGraph frameGraph) { super.initialize(frameGraph); for (int i = 0; i < targets.length; i++) { targets[i] = addParameter(new TextureTargetParam(RENDER_TARGETS[i], null)); @@ -64,13 +63,10 @@ public void initialize(MyFrameGraph frameGraph) { @Override public boolean prepare(RenderContext context) { - if (super.prepare(context)) { - if (context.isSizeChanged() || gBuffer == null) { - reshape(context.getRenderer(), context.getWidth(), context.getHeight()); - } - return true; + if (context.isSizeChanged() || gBuffer == null) { + reshape(context.getRenderer(), context.getWidth(), context.getHeight()); } - return false; + return super.prepare(context); } @Override @@ -126,6 +122,8 @@ public void reset() { protected void reshape(Renderer renderer, int w, int h) { if (gBuffer != null) { + //w = gBuffer.getWidth(); + //h = gBuffer.getHeight(); gBuffer.dispose(); gBuffer.deleteObject(renderer); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java index 7a1ac41d85..516286196e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java @@ -10,7 +10,7 @@ import com.jme3.profile.VpStep; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.DepthRange; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderContext; import com.jme3.util.SafeArrayList; @@ -21,7 +21,7 @@ public class PostProcessingModule extends AbstractModule { @Override - public void initialize(MyFrameGraph frameGraph) {} + public void initialize(FrameGraph frameGraph) {} @Override public void preFrame(RenderContext context) { ViewPort vp = context.getViewPort(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ScreenModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ScreenModule.java new file mode 100644 index 0000000000..6f00a90613 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ScreenModule.java @@ -0,0 +1,35 @@ +/* + * 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.pass; + +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.ui.Picture; + +/** + * + * @author codex + */ +public abstract class ScreenModule extends AbstractModule { + + protected Picture screenRect; + + @Override + public void initialize(FrameGraph frameGraph) { + screenRect = new Picture("ScreenRect"); + screenRect.setWidth(1); + screenRect.setHeight(1); + screenRect.setIgnoreTransform(true); + Material mat = createScreenMaterial(); + screenRect.setMaterial(mat); + RenderState rs = mat.getAdditionalRenderState(); + rs.setDepthWrite(false); + rs.setDepthTest(false); + } + + protected abstract Material createScreenMaterial(); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java index 0d7284ef34..eab576f9a9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java @@ -5,65 +5,128 @@ package com.jme3.renderer.framegraph.pass; import com.jme3.asset.AssetManager; +import com.jme3.light.LightList; import com.jme3.material.Material; +import com.jme3.material.RenderState; import com.jme3.material.TechniqueDef; import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic; -import com.jme3.material.logic.TileInfoProvider; import com.jme3.material.logic.TiledRenderGrid; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderContext; +import com.jme3.renderer.framegraph.parameters.MatRenderParam; +import com.jme3.renderer.framegraph.parameters.TextureTargetParam; +import com.jme3.renderer.framegraph.parameters.ValueRenderParam; import com.jme3.renderer.framegraph.parameters.WorldRenderParam; +import com.jme3.shader.VarType; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture2D; /** * * @author codex */ -public class TileDeferredShadingModule extends DeferredShadingModule implements TileInfoProvider { +public class TileDeferredShadingModule extends ScreenModule { - public static final String TILE_INFO = "TileDeferredShading.TileInfo"; + public final static String RT_0 = "Context_InGBuff0"; + public final static String RT_1 = "Context_InGBuff1"; + public final static String RT_2 = "Context_InGBuff2"; + public final static String RT_3 = "Context_InGBuff3"; + public final static String RT_4 = "Context_InGBuff4"; + public final static String LIGHT_DATA = "TileDeferredShadingPass.LightData"; + public final static String EXECUTE_STATE = "TileDeferredShadingPass.ExecuteState"; + public final static String IN_FRAME_BUFFER = "TileDeferredShadingPass.InFrameBuffer"; + public final static String TILE_INFO = "TileDeferredShadingPass.TileInfo"; + public final static String DEPTH_DEBUG = "TileDeferredShadingPass.DepthDebug"; + private final static String PASS = "TileBasedDeferredPass"; private static final String MATDEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"; - private static final String PASS = "TileBasedDeferredPass"; + protected final AssetManager assetManager; + private final TiledRenderGrid tileInfo = new TiledRenderGrid(); + protected MatRenderParam[] matParams = new MatRenderParam[5]; + protected ValueRenderParam lightList; + protected ValueRenderParam executeState; + protected ValueRenderParam gBuffer; private WorldRenderParam tileParam; - private TiledRenderGrid tileInfo = new TiledRenderGrid(); + private FrameBuffer debug; + private TextureTargetParam depthCopy; public TileDeferredShadingModule(AssetManager assetManager) { - super(assetManager); + this.assetManager = assetManager; } @Override - public void initialize(MyFrameGraph frameGraph) { + public void initialize(FrameGraph frameGraph) { + super.initialize(frameGraph); + + Material screenMat = screenRect.getMaterial(); + RenderState rs = screenMat.getAdditionalRenderState(); + rs.setDepthTest(true); + rs.setDepthWrite(true); + rs.setDepthFunc(RenderState.TestFunction.Greater); + screenMat.setBoolean("UseLightsCullMode", false); + + for (TechniqueDef t : screenMat.getMaterialDef().getTechniqueDefs(PASS)) { + t.setLogic(new TileBasedDeferredSinglePassLightingLogic(t, tileInfo)); + } + + // material render parameters automatically apply their values + matParams[0] = addParameter(new MatRenderParam(RT_0, screenMat, VarType.Texture2D)); + matParams[1] = addParameter(new MatRenderParam(RT_1, screenMat, VarType.Texture2D)); + matParams[2] = addParameter(new MatRenderParam(RT_2, screenMat, VarType.Texture2D)); + matParams[3] = addParameter(new MatRenderParam(RT_3, screenMat, VarType.Texture2D)); + matParams[4] = addParameter(new MatRenderParam(RT_4, screenMat, VarType.Texture2D)); + lightList = addParameter(new ValueRenderParam<>(LIGHT_DATA)); + executeState = addParameter(new ValueRenderParam<>(EXECUTE_STATE)); + gBuffer = addParameter(new ValueRenderParam<>(IN_FRAME_BUFFER)); tileParam = addParameter(new WorldRenderParam<>(TILE_INFO, frameGraph.getWorldParameters(), TILE_INFO)); + depthCopy = addParameter(new TextureTargetParam(DEPTH_DEBUG, null)); + + for (int i = 0; i < matParams.length; i++) { + frameGraph.bindToOutput(GBufferModule.RENDER_TARGETS[i], matParams[i]); + } + frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); + frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); + frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, gBuffer); + } @Override public boolean prepare(RenderContext context) { - //context.getRenderManager().calculateTileInfo(); - return super.prepare(context); + if (debug == null) { + debug = new FrameBuffer(context.getWidth(), context.getHeight(), 1); + FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget( + new Texture2D(context.getWidth(), context.getHeight(), GBufferModule.DEPTH_FORMAT)); + debug.setDepthTarget(t); + depthCopy.setTextureTarget(t); + } + return true; } @Override public void execute(RenderContext context) { + TiledRenderGrid t = tileParam.get(); if (t != null) { tileInfo.copyFrom(t); } tileInfo.update(context.getRenderManager().getCurrentCamera()); - super.execute(context); - } - @Override - protected Material createMaterial() { - return new Material(assetManager, MATDEF); + + context.getRenderer().copyFrameBuffer(gBuffer.get(), + context.getViewPort().getOutputFrameBuffer(), false, true); + + context.getRenderer().copyFrameBuffer(gBuffer.get(), debug, false, true); + + screenRect.getMaterial().selectTechnique(PASS, context.getRenderManager()); + context.setDepthRange(1, 1); + context.getRenderer().setFrameBuffer(context.getViewPort().getOutputFrameBuffer()); + screenRect.updateGeometricState(); + context.getRenderManager().renderGeometry(screenRect, lightList.get()); + } @Override - protected void assignTechniqueLogic(Material mat) { - for (TechniqueDef t : mat.getMaterialDef().getTechniqueDefs(PASS)) { - TileBasedDeferredSinglePassLightingLogic l = new TileBasedDeferredSinglePassLightingLogic(t, tileInfo); - t.setLogic(l); - } - } + public void reset() {} @Override - public TiledRenderGrid getTiledRenderGrid() { - return tileParam.orElse(tileInfo); + protected Material createScreenMaterial() { + return new Material(assetManager, MATDEF); } } 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 deleted file mode 100644 index b01d431e4d..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataProxy.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.pass; - -import com.jme3.light.LightList; -import com.jme3.renderer.framegraph.FGBindable; -import com.jme3.renderer.framegraph.RenderContext; - -/** - * - * @author codex - */ -public class DeferredLightDataProxy implements FGBindable { - - private final LightList lightData; - - public DeferredLightDataProxy(LightList lightData) { - this.lightData = lightData; - } - - public LightList getLightData() { - return lightData; - } - - @Override - public void bind(RenderContext renderContext) {} - -} 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 deleted file mode 100644 index 2fd3e395fc..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSink.java +++ /dev/null @@ -1,47 +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.pass; - -import com.jme3.renderer.framegraph.BindableSink; - -public class DeferredLightDataSink extends BindableSink { - - public DeferredLightDataSink(String registeredName) { - super(registeredName); - } - - @Override - public void postLinkValidate() { - bLinkValidate = target != null; - } - -} 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 deleted file mode 100644 index 83f0754a9b..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSource.java +++ /dev/null @@ -1,75 +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.pass; - -import com.jme3.light.LightList; -import com.jme3.renderer.framegraph.FGBindable; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.AbstractFGSource; - -public class DeferredLightDataSource extends AbstractFGSource { - - 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 implements FGBindable { - - private LightList lightData; - - public DeferredLightDataProxy(LightList lightData) { - this.lightData = lightData; - } - - public LightList getLightData() { - return lightData; - } - - @Override - public void bind(RenderContext renderContext) {} - - } - -} 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 deleted file mode 100644 index 6733182fe6..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingPass.java +++ /dev/null @@ -1,131 +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.pass; - -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(RenderContext renderContext) { - super.prepare(renderContext); - ViewPort vp = renderContext.getViewPort(); - 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 - registerBindableSink(new MatParamSink(S_RT_0, screenMat, VarType.Texture2D)); - registerBindableSink(new MatParamSink(S_RT_1, screenMat, VarType.Texture2D)); - registerBindableSink(new MatParamSink(S_RT_2, screenMat, VarType.Texture2D)); - registerBindableSink(new MatParamSink(S_RT_3, screenMat, VarType.Texture2D)); - registerBindableSink(new MatParamSink(S_RT_4, screenMat, VarType.Texture2D)); - registerBindableSink(new DeferredLightDataSink(S_LIGHT_DATA)); - registerBindableSink(new FGVarBindableSink(S_EXECUTE_STATE)); - registerBindableSink(new FGFramebufferCopyBindableSink(FGGlobal.S_DEFAULT_FB, null, false, true, true)); - } - - @Override - public void executeDrawCommands(RenderContext renderContext) { - 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(); - 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.getRenderManager()); - 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 renderGeometry(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/pass/ForwardPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java deleted file mode 100644 index 46fdd30a3c..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java +++ /dev/null @@ -1,76 +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.pass; - -import com.jme3.renderer.Camera; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.RenderContext; -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 executeDrawCommands(RenderContext renderContext) { - if (!canExecute) { - return; - } - Camera cam; - if(forceViewPort != null){ - cam = forceViewPort.getCamera(); - } else { - cam = renderContext.getViewPort().getCamera(); - } - RenderManager rm = renderContext.getRenderManager(); - renderContext.getRenderQueue().renderQueue(this.bucket, rm, cam, true); - } - - @Override - public void dispatchPassSetup(RenderQueue renderQueue) { - canExecute = !renderQueue.isQueueEmpty(this.bucket); - } - - @Override - public boolean renderGeometry(RenderManager rm, Geometry geom) { - rm.renderGeometry(geom); - return true; - } -} 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 deleted file mode 100644 index 2ea04db9ad..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java +++ /dev/null @@ -1,198 +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.pass; - -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.FramebufferSource; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.FGShaderResource; -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 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 = false; - private FGVarSource bHasDrawVarSource; - private FrameBuffer gBuffer; - private final Texture2D[] gBufferData = new Texture2D[5]; - private final ColorRGBA gBufferMask = new ColorRGBA(0, 0, 0, 0); - private int frameBufferWidth, frameBufferHeight; - - public GBufferPass() { - super("GBufferPass"); - } - - @Override - public void executeDrawCommands(RenderContext renderContext) { - if(canExecute){ - bHasDraw = false; - tempLights.clear(); - lightData.clear(); - ViewPort vp; - if (forceViewPort != null) { - vp = forceViewPort; - } else { - vp = renderContext.getViewPort(); - } - 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.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.executeDrawCommands(renderContext); - renderContext.getRenderManager().setForcedTechnique(techOrig); - vp.setOutputFrameBuffer(opfb); - renderContext.getRenderer().setBackgroundColor(opClearColor); - renderContext.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer()); - bHasDrawVarSource.setValue(bHasDraw); - if (bHasDraw) { - for(Light light : tempLights){ - lightData.add(light); - } - //renderContext.renderManager.getRenderer().copyFrameBuffer(gBuffer, vp.getOutputFrameBuffer(), false, true); - } - } - } - - @Override - public void resetPass() { - super.resetPass(); - 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; - frameBufferHeight = h; - recreate = true; - } - } else { - recreate = true; - frameBufferWidth = w; - frameBufferHeight = h; - } - - if (recreate) { - // To ensure accurate results, 32bit is used here for generalization. - 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); - //gBuffer.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(Image.Format.RGBA8)); - 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 DeferredLightDataSource(LIGHT_DATA, lightData)); - bHasDrawVarSource = new FGVarSource<>(EXECUTE_STATE, bHasDraw); - registerSource(bHasDrawVarSource); - registerSource(new FramebufferSource(G_FRAME_BUFFER, gBuffer)); - } - } - - @Override - public boolean renderGeometry(RenderManager rm, Geometry geom) { - Material material = geom.getMaterial(); - if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null)return false; - rm.renderGeometry(geom); - if(material.getActiveTechnique() != null){ - if(material.getMaterialDef().getTechniqueDefs(GBUFFER_PASS) != null){ - LightList lights = geom.getFilterWorldLights(); - for(Light light : lights){ - if(!tempLights.contains(light)){ - tempLights.add(light); - } - } - // Whether it has lights or not, material objects containing GBufferPass will perform DeferredShading, and shade according to shadingModelId - bHasDraw = true; - return true; - } - } - return false; - } - - @Override - public void prepare(RenderContext renderContext) { - super.prepare(renderContext); - ViewPort vp; - if(forceViewPort != null){ - vp = forceViewPort; - } else { - vp = renderContext.getViewPort(); - } - reshape(renderContext.getRenderer(), vp, vp.getCamera().getWidth(), vp.getCamera().getHeight()); - } -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GeometryRenderHandler.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GeometryRenderHandler.java deleted file mode 100644 index 1425bef605..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GeometryRenderHandler.java +++ /dev/null @@ -1,48 +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.pass; - -import com.jme3.renderer.RenderManager; -import com.jme3.scene.Geometry; - -/** - * @author JohnKkk - */ -public interface GeometryRenderHandler { - /** - * 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 renderGeometry(RenderManager rm, Geometry geom); -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java deleted file mode 100644 index 9d6e9e0d6c..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.pass; - -import com.jme3.renderer.framegraph.pass.ForwardModule; -import com.jme3.renderer.Camera; -import com.jme3.renderer.framegraph.DepthRange; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.queue.RenderQueue; - -/** - * - * @author codex - */ -public class GuiModule extends ForwardModule { - - public GuiModule() { - super(RenderQueue.Bucket.Gui, DepthRange.IDENTITY); - } - - @Override - public void execute(RenderContext context) { - Camera cam = context.getViewPort().getCamera(); - context.getRenderManager().setCamera(cam, true); - super.execute(context); - context.getRenderManager().setCamera(cam, false); - } - -} 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 deleted file mode 100644 index e50d378b59..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiPass.java +++ /dev/null @@ -1,64 +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.pass; - -import com.jme3.renderer.Camera; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.queue.RenderQueue; - -/** - * @author JohnKkk - */ -public class GuiPass extends ForwardPass{ - @Override - public void executeDrawCommands(RenderContext context) { - Camera cam = null; - if(forceViewPort != null){ - cam = forceViewPort.getCamera(); - } - else{ - cam = context.getViewPort().getCamera(); - } - if(canExecute){ - context.setDepthRange(0, 0); - context.getRenderManager().setCamera(cam, true); - } - super.executeDrawCommands(context); - if(canExecute){ - context.getRenderManager().setCamera(cam, false); - } - } - - public GuiPass() { - super("GUIPass", RenderQueue.Bucket.Gui); - } -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java deleted file mode 100644 index f31888aaaf..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java +++ /dev/null @@ -1,56 +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.pass; - -import com.jme3.renderer.framegraph.RenderContext; -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 executeDrawCommands(RenderContext renderContext) { - if(canExecute){ - renderContext.setDepthRange(0, 1); - } - super.executeDrawCommands(renderContext); - } - - public OpaquePass() { - super("ForwardOpaquePass", RenderQueue.Bucket.Opaque); - } -} 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 deleted file mode 100644 index 4746fe82e3..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java +++ /dev/null @@ -1,67 +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.pass; - -import com.jme3.post.SceneProcessor; -import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.AbstractFGPass; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.util.SafeArrayList; - -/** - * @author JohnKkk - */ -public class PostProcessorPass extends AbstractFGPass { - - public PostProcessorPass(String name) { - super(name); - } - - @Override - public void execute(RenderContext renderContext) { - renderContext.setDepthRange(0, 1); - ViewPort vp = renderContext.getViewPort(); - 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); - } - } - - @Override - public void prepare(RenderContext renderContext) {} - -} 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 deleted file mode 100644 index 94ea513465..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/ResolveSceneColorPass.java +++ /dev/null @@ -1,95 +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.pass; - -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 executeDrawCommands(RenderContext renderContext) { - 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.getRenderManager()); - screenMat.getAdditionalRenderState().setDepthWrite(depthWrite); - screenMat.getAdditionalRenderState().setDepthTest(depthTest); - } - public void updateExposure(float exposure){ - screenMat.setFloat("Exposure", exposure); - } - - @Override - public boolean renderGeometry(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 - registerBindableSink(new MatParamSink(S_SCENE_COLOR_RT, screenMat, VarType.Texture2D)); - registerBindableSink(new FGFramebufferCopyBindableSink(FGGlobal.S_DEFAULT_FB, null, false, true, true)); - } -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenPass.java deleted file mode 100644 index d6c4745d53..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenPass.java +++ /dev/null @@ -1,66 +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.pass; - -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/pass/ScreenSpaceSubsurfaceScatteringPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenSpaceSubsurfaceScatteringPass.java deleted file mode 100644 index 99583579bd..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenSpaceSubsurfaceScatteringPass.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.jme3.renderer.pass; - -/** - * Subsurface Scattering. - * http://www.iryoku.com/screen-space-subsurface-scattering - * @author JohnKkk - */ -public class ScreenSpaceSubsurfaceScatteringPass extends OpaquePass{ -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java deleted file mode 100644 index 79a11ebbdc..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java +++ /dev/null @@ -1,52 +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.pass; - -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.queue.RenderQueue; - -/** - * @author JohnKkk - */ -public class SkyPass extends ForwardPass{ - public SkyPass() { - super("Sky", RenderQueue.Bucket.Sky); - } - - @Override - public void executeDrawCommands(RenderContext context) { - if(canExecute){ - context.setDepthRange(1, 1); - } - super.executeDrawCommands(context); - } -} 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 deleted file mode 100644 index 1f18888c68..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingPass.java +++ /dev/null @@ -1,76 +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.pass; - -import com.jme3.light.LightList; -import com.jme3.material.Material; -import com.jme3.material.MaterialDef; -import com.jme3.renderer.framegraph.RenderContext; - -public class TileDeferredShadingPass extends DeferredShadingPass{ - - private static final String MATDEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"; - protected final static String PASS = "TileBasedDeferredPass"; - - public TileDeferredShadingPass() { - super("TileDeferredShadingPass"); - } - - @Override - protected Material getMaterial() { - MaterialDef def = (MaterialDef) assetManager.loadAsset(MATDEF); - screenMat = new Material(def); - return screenMat; - } - - @Override - public void executeDrawCommands(RenderContext renderContext) { - DeferredLightDataSink deferredLightDataSink = (DeferredLightDataSink) getSink(S_LIGHT_DATA); - DeferredLightDataSource.DeferredLightDataProxy deferredLightDataProxy = (DeferredLightDataSource.DeferredLightDataProxy) deferredLightDataSink.getBind(); - LightList lights = deferredLightDataProxy.getLightData(); - - // Handle FullScreenLights - 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.getRenderManager()); - screenMat.getAdditionalRenderState().setDepthTest(depthTest); - screenMat.getAdditionalRenderState().setDepthWrite(depthWrite); - - // Handle non-fullscreen lights - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java deleted file mode 100644 index 8f9d19c245..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java +++ /dev/null @@ -1,49 +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.pass; - -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.queue.RenderQueue; - -public class TranslucentPass extends ForwardPass{ - @Override - public void executeDrawCommands(RenderContext renderContext) { - if(canExecute){ - renderContext.setDepthRange(0, 1); - } - super.executeDrawCommands(renderContext); - } - - public TranslucentPass() { - super("TranslucentPass", RenderQueue.Bucket.Translucent); - } -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java deleted file mode 100644 index 117b65335f..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java +++ /dev/null @@ -1,52 +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.pass; - -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.queue.RenderQueue; - -/** - * @author JohnKkk - */ -public class TransparentPass extends ForwardPass{ - @Override - public void executeDrawCommands(RenderContext renderContext) { - if(canExecute){ - renderContext.setDepthRange(0, 1); - } - super.executeDrawCommands(renderContext); - } - - public TransparentPass() { - super("TransparentPass", RenderQueue.Bucket.Transparent); - } -} 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 be0c5300f2..07c70e483a 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 @@ -33,12 +33,11 @@ import com.jme3.post.SceneProcessor; import com.jme3.renderer.Camera; +import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.RenderManager; import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; -import java.util.Iterator; import java.util.LinkedList; -import com.jme3.renderer.pass.GeometryRenderHandler; /** * RenderQueue is used to queue up and sort diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert index cfb28fcf4a..d0122dc266 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert @@ -20,4 +20,4 @@ void main(){ viewProjectionMatrixInverse = GetViewProjectionMatrixInverse(); -} \ 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 efa93d5d92..6c30e710f7 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 @@ -670,7 +670,7 @@ private void readTechnique(Statement techStat) throws IOException{ technique.setLogic(new DeferredSinglePassLightingLogic(technique, true)); break; case TileBasedDeferredSinglePass: - technique.setLogic(new TileBasedDeferredSinglePassLightingLogic(technique)); + technique.setLogic(new TileBasedDeferredSinglePassLightingLogic(technique, null)); break; case StaticPass: technique.setLogic(new StaticPassLightingLogic(technique)); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java index ff18a0145a..a87cc65396 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java @@ -27,7 +27,7 @@ public void simpleInitApp() { // renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); // renderManager.setSinglePassLightBatchSize(30); // renderManager.setRenderPath(RenderManager.RenderPath.Forward); - renderManager.setMaxDeferredShadingLights(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.setMaxDeferredShadingLights(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); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java index be6359cc66..d2f2cd73e4 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java @@ -198,7 +198,7 @@ else if(name.equals("addPointLight") && !pressed){ @Override public void simpleInitApp() { // For this scene, use a tileSize=64 configuration (at 1600*900 resolution) - renderManager.setForceTileSize(64);// 1600 * 900 resolution config + //renderManager.setForceTileSize(64);// 1600 * 900 resolution config setupKeys(); setUpTerrain(); setUpTerrainMaterial(); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index 1a35b60f1a..e221135663 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -14,7 +14,7 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.parameters.MatRenderParam; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderPipelineFactory; import com.jme3.renderer.framegraph.pass.DeferredShadingModule; import com.jme3.renderer.queue.RenderQueue; @@ -58,7 +58,7 @@ public static void main(String[] args) { @Override public void simpleInitApp() { - MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); + FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); //MyFrameGraph graph = RenderPipelineFactory.createBackroundScreenTest(assetManager, renderManager); renderManager.setFrameGraph(graph); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index d56e11d520..41ed76856b 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -54,7 +54,7 @@ import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.RenderManager; import com.jme3.renderer.framegraph.parameters.MatRenderParam; -import com.jme3.renderer.framegraph.MyFrameGraph; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderPipelineFactory; import com.jme3.renderer.framegraph.pass.GBufferModule; import com.jme3.renderer.queue.RenderQueue; @@ -655,7 +655,7 @@ private void testScene11(){ @Override public void simpleInitApp() { - MyFrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); + FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); renderManager.setFrameGraph(graph); Geometry debugView = new Geometry("debug", new Quad(200, 200)); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java index a253fdac70..f51ead680b 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java @@ -26,11 +26,11 @@ public class TestTileBasedDeferredShading extends SimpleApplication { @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.setForceTileSize(128);// 1600 * 900 resolution config // renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); // renderManager.setSinglePassLightBatchSize(30); // renderManager.setRenderPath(RenderManager.RenderPath.Forward); - renderManager.setMaxDeferredShadingLights(1000); + //renderManager.setMaxDeferredShadingLights(1000); //renderManager.setRenderPath(RenderManager.RenderPath.TiledDeferred); Quad quad = new Quad(15, 15); Geometry geo = new Geometry("Floor", quad); From c02d491eb4bcdcdb30cbd6563a5e203e8eab4589 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 29 Apr 2024 17:10:30 -0400 Subject: [PATCH 048/111] redesigned resource system --- .../java/com/jme3/renderer/RenderManager.java | 14 ++- .../jme3/renderer/framegraph/CameraSize.java | 45 +++++++ .../jme3/renderer/framegraph/FrameGraph.java | 19 ++- .../jme3/renderer/framegraph/GBufferPass.java | 29 +++++ .../renderer/framegraph/RenderContext.java | 32 +---- .../jme3/renderer/framegraph/RenderPass.java | 16 ++- .../renderer/framegraph/RenderResource.java | 39 +++--- .../renderer/framegraph/ResourceAction.java | 42 ------- ...sourcePool.java => ResourceAllocator.java} | 26 ++-- .../jme3/renderer/framegraph/ResourceDef.java | 84 +++++++++++-- .../renderer/framegraph/ResourceList.java | 119 ++++++++++++++++++ .../renderer/framegraph/ResourceRegistry.java | 86 ------------- .../renderer/framegraph/ResourceTicket.java | 66 +++++++--- .../renderer/framegraph/TextureDef2D.java | 38 ++++++ 14 files changed, 422 insertions(+), 233 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/CameraSize.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAction.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ResourcePool.java => ResourceAllocator.java} (50%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRegistry.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.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 b1453fa284..28844605b1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -47,7 +47,7 @@ import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.ResourcePool; +import com.jme3.renderer.framegraph.ResourceAllocator; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; @@ -110,7 +110,7 @@ public String getInfo(){ private final ArrayList preViewPorts = new ArrayList<>(); private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); - private final ResourcePool resPool = new ResourcePool(); + private final ResourceAllocator resPool = new ResourceAllocator(); private FrameGraph frameGraph; private Camera prevCam = null; private Material forcedMaterial = null; @@ -133,7 +133,6 @@ public String getInfo(){ private MatParamOverride boundDrawBufferId = new MatParamOverride(VarType.Int, "BoundDrawBuffer", 0); private Predicate renderFilter; - /** * Creates a high-level rendering interface over the * low-level rendering interface. @@ -167,6 +166,15 @@ public void setFrameGraph(FrameGraph frameGraph) { public FrameGraph getFrameGraph() { return frameGraph; } + + /** + * Gets the global resource pool used to store potential render resources. + * + * @return + */ + public ResourceAllocator getResourcePool() { + return resPool; + } /** * Sets the GeometryRenderHandler used to render geometry. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/CameraSize.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/CameraSize.java new file mode 100644 index 0000000000..fa2eb83db6 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/CameraSize.java @@ -0,0 +1,45 @@ +/* + * 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.Camera; + +/** + * + * @author codex + */ +public class CameraSize { + + private int width, height; + + public CameraSize() {} + + public boolean needsUpdate(Camera cam) { + return width != cam.getWidth() || height != cam.getHeight(); + } + public boolean needsUpdate(CameraSize camSize) { + return width != camSize.width || height != camSize.height; + } + public boolean update(Camera cam) { + boolean changed = needsUpdate(cam); + width = cam.getWidth(); + height = cam.getHeight(); + return changed; + } + public boolean update(CameraSize camSize) { + boolean changed = needsUpdate(camSize); + width = camSize.width; + height = camSize.height; + return changed; + } + + public int getWidth() { + return width; + } + public int getHeight() { + return height; + } + +} 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 412337ec9e..7a964455b0 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 @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.RenderManager; import java.util.LinkedList; /** @@ -14,10 +15,12 @@ public class FrameGraph { private final LinkedList passes = new LinkedList<>(); - private final ResourceRegistry resources; + private final ResourceList resources; + private final RenderContext context; - public FrameGraph(ResourcePool pool) { - this.resources = new ResourceRegistry(pool); + public FrameGraph(RenderManager renderManager) { + this.resources = new ResourceList(renderManager.getResourcePool(), 30); + this.context = new RenderContext(renderManager); } public void cull() { @@ -27,7 +30,7 @@ public void cull() { } // fetch unreferences resources LinkedList cull = new LinkedList<>(); - resources.getUnreferencedResources(cull); + resources.getUnreferenced(cull); RenderResource res; while ((res = cull.pollFirst()) != null) { // dereference producer of resource @@ -39,7 +42,13 @@ public void cull() { } public void execute() { - + // create resources... + // execute + for (RenderPass p : passes) { + if (p.isReferenced()) { + p.execute(context); + } + } } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java new file mode 100644 index 0000000000..9616368aaa --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java @@ -0,0 +1,29 @@ +/* + * 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.Image; +import com.jme3.texture.Texture2D; + +/** + * + * @author codex + */ +public class GBufferPass extends RenderPass { + + private ResourceTicket depthTicket = new ResourceTicket("SceneDepth"); + private ResourceTicket texTicket1 = ResourceTicket.createUnlinked("GBufferTex1"); + + @Override + public void createResources(RenderContext context, ResourceList resources) { + resources.register(this, new TextureDef2D(1024, 1024, Image.Format.RGBA8), texTicket1); + resources.reference(depthTicket); + } + @Override + public void execute(RenderContext context) { + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java index 843e1e9353..0282807ba6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java @@ -48,14 +48,12 @@ public class RenderContext { private ViewPort viewPort; private AppProfiler profiler; private final DepthRange depth = new DepthRange(); + private final CameraSize camSize = new CameraSize(); private float tpf; - private int width, height; - private boolean sizeChanged = false; public RenderContext(RenderManager renderManager, ViewPort viewPort) { this.renderManager = renderManager; this.viewPort = viewPort; - width = height = -1; } public RenderContext(RenderManager renderManager) { this(renderManager, null); @@ -68,11 +66,7 @@ public void update(ViewPort vp, AppProfiler profiler, float tpf) { if (viewPort == null) { throw new NullPointerException("ViewPort cannot be null."); } - Camera cam = viewPort.getCamera(); - sizeChanged = width != cam.getWidth() || height != cam.getHeight(); - //System.out.println("size changed? "+sizeChanged); - width = cam.getWidth(); - height = cam.getHeight(); + camSize.update(viewPort.getCamera()); } public void setDepthRange(float start, float end) { @@ -81,7 +75,6 @@ public void setDepthRange(float start, float end) { renderManager.getRenderer().setDepthRange(depth); } } - public void setDepthRange(DepthRange depth) { if (!this.depth.equals(depth)) { renderManager.getRenderer().setDepthRange(this.depth.set(depth)); @@ -91,27 +84,24 @@ public void setDepthRange(DepthRange depth) { public DepthRange getDepthRange() { return depth; } - public RenderManager getRenderManager() { return renderManager; } - public ViewPort getViewPort() { return viewPort; } - public AppProfiler getProfiler() { return profiler; } - + public CameraSize getCameraSize() { + return camSize; + } public float getTpf() { return tpf; } - public Renderer getRenderer() { return renderManager.getRenderer(); } - public RenderQueue getRenderQueue() { if (viewPort != null) { return viewPort.getQueue(); @@ -124,16 +114,4 @@ public boolean isProfilerAvailable() { return profiler != null; } - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public boolean isSizeChanged() { - return sizeChanged; - } - } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java index 842a376282..eb9d955892 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java @@ -11,11 +11,14 @@ * * @author codex */ -public class RenderPass { +public abstract class RenderPass { private final LinkedList inputs = new LinkedList<>(); private final LinkedList outputs = new LinkedList<>(); - private int refs; + private int refs = 0; + + public abstract void createResources(RenderContext context, ResourceList resources); + public abstract void execute(RenderContext context); public void countReferences() { refs = outputs.size(); @@ -28,13 +31,8 @@ public boolean isReferenced() { return refs > 0; } - public void dereferenceInputs(ResourceRegistry registry, List resList) { - for (ResourceTicket i : inputs) { - RenderResource r = registry.locateResource(i); - if (!r.dereference()) { - resList.add(r); - } - } + public void dereferenceInputs(ResourceList resources, List resList) { + resources.dereferenceListed(inputs, resList); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 592ebd8ff3..1aa29000ef 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -13,46 +13,30 @@ public class RenderResource { private final RenderPass producer; private final ResourceDef def; - private final ResourceTicket ticket; + private int index; private T resource; private int refs = 0; - private int users = 0; - public RenderResource(RenderPass producer, ResourceDef def, ResourceTicket ticket) { + public RenderResource(RenderPass producer, ResourceDef def) { this.producer = producer; this.def = def; - this.ticket = ticket; } public void create() { - if (resource == null) { - resource = def.create(); - } + resource = def.create(); } public void setResource(T resource) { this.resource = resource; } - - public void acquire() { - users++; - } - public boolean release() { - users--; - return isUsed(); - } - public boolean isUsed() { - return users > 0; + public void setIndex(int index) { + this.index = index; } public void reference() { refs++; } - public boolean dereference() { + public void release() { refs--; - return isReferenced(); - } - public boolean isReferenced() { - return refs > 0; } public RenderPass getProducer() { @@ -61,14 +45,21 @@ public RenderPass getProducer() { public ResourceDef getDefinition() { return def; } - public ResourceTicket getTicket() { - return ticket; + public int getIndex() { + return index; } public T getResource() { return resource; } + public boolean isVirtual() { return resource == null; } + public boolean isReferenced() { + return refs > 0; + } + public boolean isUsed() { + return refs >= 0; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAction.java deleted file mode 100644 index 0c16714bb3..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAction.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 enum ResourceAction { - - /** - * The resource will only be read from. - */ - Read(true, false), - - /** - * The resource will only be written to. - */ - Write(false, true), - - /** - * The resource will be read from and written to. - */ - ReadAndWrite(true, true); - - private final boolean read, write; - - private ResourceAction(boolean read, boolean write) { - this.read = read; - this.write = write; - } - - public boolean isRead() { - return read; - } - public boolean isWrite() { - return write; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourcePool.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAllocator.java similarity index 50% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourcePool.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAllocator.java index 4239778737..5d8f696291 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourcePool.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAllocator.java @@ -11,7 +11,7 @@ * * @author codex */ -public class ResourcePool { +public class ResourceAllocator { private final LinkedList resources = new LinkedList<>(); @@ -22,14 +22,24 @@ public void add(RenderResource res) { resources.add(res); } - public boolean acquireExisting(RenderResource resource) { + /** + * Reallocates a resource from the pool to the given resource, if the + * resource definition accepts. + * + * @param + * @param resource + * @return true if a resource was reallocated to the given resource + */ + public boolean reallocateTo(RenderResource resource) { for (Iterator it = resources.iterator(); it.hasNext();) { - RenderResource r = it.next(); - T result = resource.getDefinition().repurpose(r.getDefinition(), r.getResource()); - if (result != null) { - resource.setResource(result); - it.remove(); - return true; + RenderResource res = it.next(); + if (resource.getDefinition().isOfResourceType(res.getResource().getClass())) { + T r = (T)res.getResource(); + if (resource.getDefinition().acceptReallocationOf(r)) { + resource.setResource(r); + it.remove(); + return true; + } } } return false; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java index 71c5a071c8..40f746a374 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java @@ -9,19 +9,85 @@ * @author codex * @param */ -public class ResourceDef { +public abstract class ResourceDef { - private Class resType; + private final Class resType; + + public ResourceDef(Class resType) { + this.resType = resType; + } + + /** + * Creates and returns a new resource. + * + * @return + */ + public abstract T create(); + + /** + * Returns true if this definition accepts the reallocation of the given + * resource to the {@link RenderResource} this is assigned to. + * + * @param resource + * @return + */ + public abstract boolean acceptReallocationOf(T resource); + + /** + * Returns true if this definition's resource type + * {@link Class#isAssignableFrom(java.lang.Class) is assignable from} the + * given class. + * + * @param type + * @return + */ + public boolean isOfResourceType(Class type) { + return resType.isAssignableFrom(type); + } + + /** + * Returns true if the {@link RenderResource} this is assigned to can accept + * reallocated resources. + * + * @return + */ + public boolean isAcceptsReallocated() { + return true; + } + + /** + * If true, the existing resource contained in the {@link RenderResource} + * this is assigned to will be reallocated to another RenderResource, if possible. + *

    + * Reallocation only occurs after all users have released the RenderResource. + * + * @return + */ + public boolean isReallocatable() { + return true; + } - public T create() { - return null; + /** + * If true, the existing resource contained in the {@link RenderResource} + * this is assigned to be destroyed during rendering cleanup. + * + * @return + */ + public boolean isTransient() { + return false; } - public T repurpose(ResourceDef def, R resource) { - if (resType.isAssignableFrom(resource.getClass())) { - return (T)resource; - } - return null; + /** + * Returns true if the {@link RenderResource} this is assigned to should be + * discarded when it becomes unused. + *

    + * This overrides {@link #isReallocatable()} and {@link #isTransient()}, as the + * resource will not survive to do either. + * + * @return + */ + public boolean isDiscardIfUnused() { + return false; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java new file mode 100644 index 0000000000..4264951444 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -0,0 +1,119 @@ +/* + * 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; +import java.util.LinkedList; +import java.util.List; + +/** + * + * @author codex + */ +public class ResourceList { + + private static final int INITIAL_SIZE = 20; + + private final ResourceAllocator allocator; + private ArrayList resources = new ArrayList<>(INITIAL_SIZE); + private int nextSlot = 0; + + public ResourceList(ResourceAllocator allocator) { + this.allocator = allocator; + } + + protected RenderResource locate(ResourceTicket ticket) { + final int i = ticket.getIndex(); + if (i >= 0 && i < resources.size()) { + RenderResource res = resources.get(i); + if (res != null) { + return res; + } + throw new NullPointerException(ticket+" points to null resource."); + } + throw new IndexOutOfBoundsException(ticket+" is out of bounds for size "+resources.size()); + } + protected int add(RenderResource res) { + assert res != null; + if (nextSlot >= resources.size()) { + // add resource to end of list + resources.add(res); + nextSlot++; + return resources.size()-1; + } else { + // insert resource into available slot + int i = nextSlot; + resources.set(i, res); + // find next available slot + while (++nextSlot < resources.size()) { + RenderResource r = resources.get(nextSlot); + if (r == null) { + break; + } + } + return i; + } + } + protected RenderResource remove(int index) { + nextSlot = Math.min(nextSlot, index); + return resources.set(index, null); + } + + public ResourceTicket register(RenderPass producer, ResourceDef def) { + return new ResourceTicket<>(add(new RenderResource<>(producer, def))); + } + public void reference(ResourceTicket ticket) { + locate(ticket).reference(); + } + public T acquire(ResourceTicket ticket) { + RenderResource res = locate(ticket); + if (res.isVirtual() && (!res.getDefinition().isAcceptsReallocated() || allocator.reallocateTo(res))) { + res.create(); + } + return res.getResource(); + } + public void release(ResourceTicket ticket) { + RenderResource res = locate(ticket); + res.release(); + if (!res.isUsed()) { + remove(ticket.getIndex()); + } + if (res.getDefinition().isReallocatable()) { + allocator.add(res); + } + } + + public void getUnreferenced(List resList) { + for (int i = 0; i < resources.size(); i++) { + RenderResource r = resources.get(i); + if (r != null && !r.isReferenced()) { + resList.add(r); + } + } + } + public void dereferenceListed(List tickets, List resList) { + for (ResourceTicket t : tickets) { + RenderResource r = locate(t); + r.release(); + if (!r.isReferenced()) { + resList.add(r); + } + } + } + public void discardUnreferenced() { + for (int i = 0; i < resources.size(); i++) { + RenderResource r = resources.get(i); + if (!r.isReferenced()) { + remove(i); + } + } + } + public void clear() { + int size = resources.size(); + resources = new ArrayList<>(size); + nextSlot = 0; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRegistry.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRegistry.java deleted file mode 100644 index 993c879541..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRegistry.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -/** - * - * @author codex - */ -public class ResourceRegistry { - - private final ArrayList resources = new ArrayList<>(); - private final ResourcePool pool; - - public ResourceRegistry(ResourcePool pool) { - this.pool = pool; - } - - protected RenderResource locateResource(ResourceTicket ticket) { - if (ticket.isLocateByName()) { - String name = ticket.getName(); - int i = 0; - for (RenderResource r : resources) { - if (r.getTicket().getName().equals(name)) { - // make the next location operation with this ticket faster - ticket.setIndex(i); - return r; - } - i++; - } - throw new NullPointerException("Unable to locate resource by "+ticket); - } else { - int i = ticket.getIndex(); - if (i < 0 || i >= resources.size()) { - throw new IndexOutOfBoundsException(ticket+" for size "+resources.size()); - } - RenderResource res = resources.get(i); - if (!res.getTicket().getName().equals(ticket.getName())) { - throw new NullPointerException("Unable to locate resource by "+ticket); - } - return res; - } - } - - public ResourceTicket registerFutureResource(RenderPass producer, String name, ResourceDef def) { - ResourceTicket ticket = new ResourceTicket(name, resources.size()); - RenderResource res = new RenderResource<>(producer, def, ticket); - resources.add(res); - return ticket; - } - - public void referenceResource(ResourceTicket ticket) { - locateResource(ticket).reference(); - } - - public T acquireResource(ResourceTicket ticket) { - RenderResource res = locateResource(ticket); - if (res.isVirtual() && !pool.acquireExisting(res)) { - res.create(); - } - res.acquire(); - return res.getResource(); - } - - public void releaseResource(ResourceTicket ticket) { - RenderResource res = locateResource(ticket); - if (!res.release()) { - pool.add(res); - } - } - - public void getUnreferencedResources(List resList) { - for (RenderResource r : resources) { - if (!r.isReferenced()) { - resList.add(r); - } - } - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index b0fdeb6de9..545d503187 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -16,44 +16,70 @@ */ public class ResourceTicket { - private String name; private int index; - public ResourceTicket(String name) { - this(name, -1); + public ResourceTicket() { + this(-1); } public ResourceTicket(int index) { - this(null, index); - } - public ResourceTicket(String name, int index) { - this.name = name; this.index = index; } - public ResourceTicket copy() { - return new ResourceTicket(name, index); - } - - public void setName(String name) { - this.name = name; + /** + * Copies this ticket's info to the target. + *

    + * If the target is null, a new instance will be created and + * written to. + * + * @param target copy target (can be null) + * @return target + */ + public ResourceTicket copyTo(ResourceTicket target) { + if (target == null) { + target = new ResourceTicket(); + } + target.index = index; + return target; } + + /** + * Sets the resource index. + * + * @param index + */ public void setIndex(int index) { this.index = index; } - public String getName() { - return name; - } + /** + * Gets the resource index. + * + * @return + */ public int getIndex() { return index; } - public boolean isLocateByName() { - return index < 0 && name != null; - } @Override public String toString() { - return "ResourceTicket[name="+(name != null ? "\""+name+"\"" : null)+", index="+index+"]"; + return "ResourceTicket["+index+"]"; + } + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + this.index; + return hash; + } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final ResourceTicket other = (ResourceTicket) obj; + return this.index == other.index; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java new file mode 100644 index 0000000000..b1a5b6f001 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java @@ -0,0 +1,38 @@ +/* + * 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.Image; +import com.jme3.texture.Texture2D; + +/** + * + * @author codex + */ +public class TextureDef2D extends ResourceDef { + + private final int width; + private final int height; + private final Image.Format format; + + public TextureDef2D(int width, int height, Image.Format format) { + super(Texture2D.class); + this.width = width; + this.height = height; + this.format = format; + } + + @Override + public Texture2D create() { + return new Texture2D(width, height, format); + } + + @Override + public boolean acceptReallocationOf(Texture2D resource) { + Image img = resource.getImage(); + return img.getWidth() == width && img.getHeight() == height && img.getFormat() == format; + } + +} From 66810b74f20fd374262318cca97b994c53eecde6 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 3 May 2024 07:29:11 -0400 Subject: [PATCH 049/111] framegraph operational --- .../java/com/jme3/renderer/RenderManager.java | 24 +- .../jme3/renderer/framegraph/BucketPass.java | 123 ++++++++++ .../renderer/framegraph/DeferredPass.java | 57 +++++ .../renderer/framegraph/FGRenderContext.java | 210 ++++++++++++++++++ .../framegraph/ForwardGraphConstructor.java | 56 +++++ .../jme3/renderer/framegraph/FrameGraph.java | 92 ++++++-- .../jme3/renderer/framegraph/GBufferPass.java | 88 +++++++- .../renderer/framegraph/GraphConstructor.java | 17 ++ .../renderer/framegraph/RenderContext.java | 117 ---------- .../jme3/renderer/framegraph/RenderPass.java | 109 ++++++++- .../renderer/framegraph/RenderResource.java | 49 +++- .../framegraph/ResourceAllocator.java | 48 ---- .../jme3/renderer/framegraph/ResourceDef.java | 75 +------ .../renderer/framegraph/ResourceList.java | 181 ++++++++++++--- .../renderer/framegraph/ResourceProducer.java | 21 ++ .../renderer/framegraph/ResourceRecycler.java | 69 ++++++ .../renderer/framegraph/ResourceTicket.java | 74 ++++-- .../jme3/renderer/framegraph/ResultPass.java | 54 +++++ .../renderer/framegraph/TestConstructor.java | 37 +++ .../renderer/framegraph/TextureDef2D.java | 51 ++++- .../jme3/renderer/framegraph/ValueDef.java | 49 ++++ .../ShadingCommon/DeferredShading.vert | 23 +- .../Common/MatDefs/ShadingCommon/Screen.vert | 12 + .../ShadingCommon/TextureTransfer.frag | 35 +++ .../ShadingCommon/TextureTransfer.j3md | 31 +++ .../jme3test/renderpath/TestShadingModel.java | 29 ++- 26 files changed, 1372 insertions(+), 359 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.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/ForwardGraphConstructor.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphConstructor.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAllocator.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResultPass.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueDef.java create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md 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 28844605b1..da954502e3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -47,7 +47,7 @@ import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.ResourceAllocator; +import com.jme3.renderer.framegraph.ResourceRecycler; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; @@ -110,7 +110,7 @@ public String getInfo(){ private final ArrayList preViewPorts = new ArrayList<>(); private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); - private final ResourceAllocator resPool = new ResourceAllocator(); + private final ResourceRecycler recycler = new ResourceRecycler(); private FrameGraph frameGraph; private Camera prevCam = null; private Material forcedMaterial = null; @@ -172,8 +172,8 @@ public FrameGraph getFrameGraph() { * * @return */ - public ResourceAllocator getResourcePool() { - return resPool; + public ResourceRecycler getResourceRecycler() { + return recycler; } /** @@ -500,6 +500,15 @@ public void notifyRescale(float x, float y) { public void setForcedMaterial(Material mat) { forcedMaterial = mat; } + + /** + * Gets the forced material. + * + * @return + */ + public Material getForcedMaterial() { + return forcedMaterial; + } /** * Returns the forced render state previously set with @@ -1280,7 +1289,7 @@ public void renderViewPort(ViewPort vp, float tpf) { if (fg != null) { fg.getContext().update(vp, prof, tpf); - fg.preFrame(); + //fg.preFrame(); } else if (processors != null) { if (prof != null) { @@ -1318,7 +1327,7 @@ public void renderViewPort(ViewPort vp, float tpf) { if (fg != null) { - fg.postQueue(); + //fg.postQueue(); } else if (processors != null) { if (prof != null) { @@ -1422,6 +1431,9 @@ public void render(float tpf, boolean mainFrameBufferActive) { renderViewPort(vp, tpf); } } + + recycler.flush(); + } /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java new file mode 100644 index 0000000000..c21653c918 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java @@ -0,0 +1,123 @@ +/* + * 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.RenderState; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.GeometryRenderHandler; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.scene.Geometry; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture2D; + +/** + * + * @author codex + */ +public class BucketPass extends RenderPass implements GeometryRenderHandler { + + private Bucket bucket; + private DepthRange depth; + private int samples = 1; + private boolean flush = true; + private ResourceTicket inColor, inDepth, outColor, outDepth; + private Texture2D fTex; + + public BucketPass(Bucket bucket) { + this(bucket, DepthRange.IDENTITY); + } + public BucketPass(Bucket bucket, DepthRange depth) { + this.bucket = bucket; + this.depth = depth; + if (this.bucket == Bucket.Inherit) { + throw new IllegalArgumentException("Rendered bucket cannot be Inherit."); + } + } + + @Override + protected void initialize(FrameGraph frameGraph) { + fTex = (Texture2D)frameGraph.getAssetManager().loadTexture("Common/Textures/MissingTexture.png"); + } + @Override + protected void prepare(FGRenderContext context) { + int w = context.getWidth(); + int h = context.getHeight(); + outColor = register(new TextureDef2D(w, h, samples, Image.Format.RGBA8), outColor); + outDepth = register(new TextureDef2D(w, h, samples, Image.Format.Depth), outDepth); + referenceOptional(inColor, inDepth); + } + @Override + protected void execute(FGRenderContext context) { + frameBuffer.addColorTarget(context.createTextureTarget(resources.acquire(outColor))); + frameBuffer.setDepthTarget(context.createTextureTarget(resources.acquire(outDepth))); + context.setFrameBuffer(frameBuffer, true, true, true); + context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); + //context.getRenderManager().setGeometryRenderHandler(this); + context.transferTextures(resources.acquire(inColor, null), resources.acquire(inDepth, null)); + context.getRenderer().setDepthRange(depth); + if (bucket == Bucket.Gui) { + context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); + } + //context.getRenderer().setDepthRange(0, 0); + context.renderViewPortQueue(bucket, flush); + if (bucket == Bucket.Gui) { + context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); + } + //context.transferTextures(fTex, null, false); + frameBuffer.clearColorTargets(); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + protected FrameBuffer createFrameBuffer(FGRenderContext context) { + return new FrameBuffer(context.getWidth(), context.getHeight(), samples); + //return null; + } + @Override + public boolean isReferenced() { + return super.isReferenced(); + //return true; + } + @Override + public boolean renderGeometry(RenderManager rm, Geometry geom) { + rm.renderGeometry(geom); + System.out.println("RENDER GEOMETRY: "+geom); + return true; + } + + public void setDepthRange(DepthRange depth) { + this.depth = depth; + } + public void setInColor(ResourceTicket inColor) { + this.inColor = inColor; + } + public void setInDepth(ResourceTicket inDepth) { + this.inDepth = inDepth; + } + public void setInput(BucketPass pass) { + inColor = pass.outColor.copyIndexTo(null); + inDepth = pass.outDepth.copyIndexTo(null); + } + + public DepthRange getDepthRange() { + return depth; + } + public ResourceTicket getOutColor() { + return outColor; + } + public ResourceTicket getOutDepth() { + return outDepth; + } + + @Override + public String toString() { + return "BucketPass["+bucket+"]"; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java new file mode 100644 index 0000000000..7862f052ee --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java @@ -0,0 +1,57 @@ +/* + * 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.light.LightList; +import com.jme3.material.Material; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture2D; + +/** + * + * @author codex + */ +public class DeferredPass extends RenderPass { + + private ResourceTicket depth, diffuse, specular, emissive, normal, result; + private ResourceTicket lights; + private Material material; + private final CameraSize camSize = new CameraSize(); + + @Override + protected void initialize(FrameGraph frameGraph) { + material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); + } + @Override + protected void prepare(FGRenderContext context) { + int w = context.getWidth(); + int h = context.getHeight(); + result = register( new TextureDef2D(w, h, Image.Format.RGBA8), result); + reference(depth, diffuse, specular, emissive, normal, lights); + } + @Override + protected void execute(FGRenderContext context) { + material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); + material.setTexture("Context_InGBuff1", resources.acquire(specular)); + material.setTexture("Context_InGBuff2", resources.acquire(emissive)); + material.setTexture("Context_InGBuff3", resources.acquire(normal)); + material.setTexture("Context_InGBuff4", resources.acquire(depth)); + resources.acquireColorTargets(frameBuffer, result); + material.selectTechnique("DeferredPass", context.getRenderManager()); + context.setFrameBuffer(frameBuffer, true, true, true); + context.renderFullscreen(material); + frameBuffer.clearColorTargets(); + } + @Override + public void reset(FGRenderContext context) {} + @Override + public void cleanup(FrameGraph frameGraph) {} + @Override + protected FrameBuffer createFrameBuffer(FGRenderContext context) { + return new FrameBuffer(context.getWidth(), context.getHeight(), 1); + } + +} 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..50ef948040 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java @@ -0,0 +1,210 @@ +/* + * 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.asset.AssetManager; +import com.jme3.material.Material; +import com.jme3.material.RenderState; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.profile.AppProfiler; +import com.jme3.renderer.GeometryRenderHandler; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import com.jme3.util.BufferUtils; +import java.util.function.Predicate; + +/** + * 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 { + + private final RenderManager renderManager; + private ViewPort viewPort; + private AppProfiler profiler; + private final CameraSize camSize = new CameraSize(); + private float tpf; + private Geometry screen; + private final Material transferMat; + + private String forcedTechnique; + private Material forcedMat; + private FrameBuffer frameBuffer; + private GeometryRenderHandler geomRender; + private Predicate geomFilter; + private RenderState renderState; + + public FGRenderContext(AssetManager assetManager, RenderManager renderManager) { + this.renderManager = renderManager; + transferMat = new Material(assetManager, "Common/MatDefs/ShadingCommon/TextureTransfer.j3md"); + //transferMat.getAdditionalRenderState().setDepthFunc(RenderState.TestFunction.Less); + } + + public void update(ViewPort vp, AppProfiler profiler, float tpf) { + this.viewPort = vp; + this.profiler = profiler; + this.tpf = tpf; + if (viewPort == null) { + throw new NullPointerException("ViewPort cannot be null."); + } + camSize.update(viewPort.getCamera()); + } + + /** + * Saves the current render settings. + */ + public void pushRenderSettings() { + forcedTechnique = renderManager.getForcedTechnique(); + forcedMat = renderManager.getForcedMaterial(); + frameBuffer = renderManager.getRenderer().getCurrentFrameBuffer(); + geomRender = renderManager.getGeometryRenderHandler(); + geomFilter = renderManager.getRenderFilter(); + renderState = renderManager.getForcedRenderState(); + } + /** + * Applies saved render settings. + */ + public void popRenderSettings() { + renderManager.setForcedTechnique(forcedTechnique); + renderManager.setForcedMaterial(forcedMat); + renderManager.getRenderer().setFrameBuffer(frameBuffer); + renderManager.setGeometryRenderHandler(geomRender); + renderManager.setRenderFilter(geomFilter); + renderManager.setForcedRenderState(renderState); + renderManager.getRenderer().setDepthRange(0, 1); + if (viewPort.isClearColor()) { + renderManager.getRenderer().setBackgroundColor(viewPort.getBackgroundColor()); + } + } + + public void renderViewPortQueue(RenderQueue.Bucket bucket, boolean clear) { + viewPort.getQueue().renderQueue(bucket, renderManager, viewPort.getCamera(), clear); + } + public void renderFullscreen(Material mat) { + if (screen == null) { + Mesh mesh = new Mesh(); + mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer( + 0, 0, 0, + 1, 0, 0, + 0, 1, 0, + 1, 1, 0 + )); + mesh.setBuffer(VertexBuffer.Type.Index, 3, BufferUtils.createIntBuffer( + 0, 1, 2, + 1, 3, 2 + )); + mesh.updateBound(); + mesh.updateCounts(); + mesh.setStatic(); + screen = new Geometry("Screen", mesh); + } + screen.setMaterial(mat); + screen.updateGeometricState(); + renderManager.renderGeometry(screen); + } + public void transferTextures(Texture2D color, Texture2D depth) { + transferTextures(color, depth, BlendMode.Off); + } + public void transferTextures(Texture2D color, Texture2D depth, BlendMode blend) { + boolean writeDepth = depth != null; + if (color != null || writeDepth) { + transferMat.setTexture("ColorMap", color); + transferMat.setTexture("DepthMap", depth); + transferMat.getAdditionalRenderState().setDepthTest(writeDepth); + transferMat.getAdditionalRenderState().setDepthWrite(writeDepth); + //transferMat.getAdditionalRenderState().setBlendMode(BlendMode.Off); + System.out.println("blend="+blend); + transferMat.getAdditionalRenderState().setBlendMode(blend); + //transferMat.setTransparent(blend == BlendMode.Alpha + // || blend == BlendMode.AlphaAdditive || blend == BlendMode.AlphaSumA); + //System.out.println("blendmode="+transferMat.getAdditionalRenderState().getBlendMode()); + //System.out.println("alpha="+transferMat.isTransparent()); + renderFullscreen(transferMat); + } + } + public FrameBuffer.FrameBufferTextureTarget createTextureTarget(Texture tex) { + return FrameBuffer.FrameBufferTarget.newTarget(tex); + } + + public void setFrameBuffer(FrameBuffer fbo) { + renderManager.getRenderer().setFrameBuffer(fbo); + } + public void setFrameBuffer(FrameBuffer fbo, boolean clearColor, boolean clearDepth, boolean clearStencil) { + setFrameBuffer(fbo); + renderManager.getRenderer().clearBuffers(clearColor, clearDepth, clearStencil); + } + + public RenderManager getRenderManager() { + return renderManager; + } + public ViewPort getViewPort() { + return viewPort; + } + public AppProfiler getProfiler() { + return profiler; + } + public CameraSize getCameraSize() { + return camSize; + } + public Renderer getRenderer() { + return renderManager.getRenderer(); + } + public RenderQueue getRenderQueue() { + if (viewPort != null) { + return viewPort.getQueue(); + } else { + return null; + } + } + public float getTpf() { + return tpf; + } + public int getWidth() { + return camSize.getWidth(); + } + public int getHeight() { + return camSize.getHeight(); + } + + public boolean isProfilerAvailable() { + return profiler != null; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java new file mode 100644 index 0000000000..b54b2004b1 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java @@ -0,0 +1,56 @@ +/* + * 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.queue.RenderQueue.Bucket; + +/** + * + * @author codex + */ +public class ForwardGraphConstructor implements GraphConstructor { + + private BucketPass opaque, sky, transparent, gui, translucent; + private ResultPass result; + + @Override + public void addPasses(FrameGraph frameGraph) { + opaque = frameGraph.add(new BucketPass(Bucket.Opaque)); + sky = frameGraph.add(new BucketPass(Bucket.Sky, DepthRange.REAR)); + transparent = frameGraph.add(new BucketPass(Bucket.Transparent)); + gui = frameGraph.add(new BucketPass(Bucket.Gui, DepthRange.FRONT)); + translucent = frameGraph.add(new BucketPass(Bucket.Translucent)); + result = frameGraph.add(new ResultPass()); + } + @Override + public void preparePasses(FGRenderContext context) { + + System.out.println(" prepare opaque"); + opaque.prepareRender(context); + + System.out.println(" prepare sky"); + sky.setInput(opaque); + sky.prepareRender(context); + + System.out.println(" prepare transparent"); + transparent.setInput(sky); + transparent.prepareRender(context); + + System.out.println(" prepare gui"); + gui.setInput(transparent); + gui.prepareRender(context); + + System.out.println(" prepare translucent"); + translucent.setInput(gui); + translucent.prepareRender(context); + + System.out.println(" prepare result"); + BucketPass out = sky; + result.setInColor(out.getOutColor()); + result.setInDepth(out.getOutDepth()); + result.prepareRender(context); + } + +} 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 7a964455b0..6cfd1eb956 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 @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.asset.AssetManager; import com.jme3.renderer.RenderManager; import java.util.LinkedList; @@ -14,41 +15,90 @@ */ public class FrameGraph { - private final LinkedList passes = new LinkedList<>(); + private final AssetManager assetManager; private final ResourceList resources; - private final RenderContext context; + private final FGRenderContext context; + private final LinkedList passes = new LinkedList<>(); + private GraphConstructor constructor; + private boolean debug = false; - public FrameGraph(RenderManager renderManager) { - this.resources = new ResourceList(renderManager.getResourcePool(), 30); - this.context = new RenderContext(renderManager); + public FrameGraph(AssetManager assetManager, RenderManager renderManager) { + this.assetManager = assetManager; + this.resources = new ResourceList(renderManager.getResourceRecycler()); + this.context = new FGRenderContext(this.assetManager, renderManager); } - public void cull() { - // count number of outputs for each pass + public void execute() { + System.out.println("render viewport: "+context.getViewPort().getName()); + // prepare passes + if (constructor != null) { + constructor.preparePasses(context); + } else for (RenderPass p : passes) { + p.prepareRender(context); + } for (RenderPass p : passes) { p.countReferences(); } - // fetch unreferences resources - LinkedList cull = new LinkedList<>(); - resources.getUnreferenced(cull); - RenderResource res; - while ((res = cull.pollFirst()) != null) { - // dereference producer of resource - if (!res.getProducer().dereference()) { - // if producer is not referenced, dereference all input resources - res.getProducer().dereferenceInputs(resources, cull); + // cull resources + resources.cullUnreferenced(); + // execute passes + context.pushRenderSettings(); + for (RenderPass p : passes) { + if (p.isReferenced()) { + System.out.println(" execute pass: "+p); + p.executeRender(context); } } + // reset passes + for (RenderPass p : passes) { + p.resetRender(context); + } + // cleanup resources + resources.clear(); } - public void execute() { - // create resources... - // execute + public void setConstructor(GraphConstructor constructor) { + if (this.constructor != null || constructor == null) { + throw new IllegalStateException(); + } + this.constructor = constructor; + this.constructor.addPasses(this); + } + public T add(T pass) { + passes.addLast(pass); + pass.initializePass(this); + return pass; + } + public T get(Class type) { for (RenderPass p : passes) { - if (p.isReferenced()) { - p.execute(context); + if (type.isAssignableFrom(p.getClass())) { + return (T)p; } } + return null; + } + + public void setDebug(boolean debug) { + this.debug = debug; + } + + public AssetManager getAssetManager() { + return assetManager; + } + public ResourceList getResources() { + return resources; + } + public ResourceRecycler getRecycler() { + return context.getRenderManager().getResourceRecycler(); + } + public FGRenderContext getContext() { + return context; + } + public RenderManager getRenderManager() { + return context.getRenderManager(); + } + public boolean isDebug() { + return debug; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java index 9616368aaa..e4bc65f021 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java @@ -4,26 +4,98 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.GeometryRenderHandler; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; +import java.util.LinkedList; /** * * @author codex */ -public class GBufferPass extends RenderPass { +public class GBufferPass extends RenderPass implements GeometryRenderHandler { - private ResourceTicket depthTicket = new ResourceTicket("SceneDepth"); - private ResourceTicket texTicket1 = ResourceTicket.createUnlinked("GBufferTex1"); + private final static String GBUFFER_PASS = "GBufferPass"; + private ResourceTicket depth, diffuse, specular, emissive, normal; + private ResourceTicket lights; + private final LinkedList accumulatedLights = new LinkedList<>(); + private final ColorRGBA mask = new ColorRGBA(); + + @Override + protected void initialize(FrameGraph frameGraph) {} + @Override + protected void prepare(FGRenderContext context) { + int w = context.getWidth(); + int h = context.getHeight(); + depth = register(new TextureDef2D(w, h, Image.Format.Depth), depth).setName("depth"); + diffuse = register(new TextureDef2D(w, h, Image.Format.RGBA16F), diffuse).setName("diffuse"); + specular = register(new TextureDef2D(w, h, Image.Format.RGBA16F), specular).setName("specular"); + emissive = register(new TextureDef2D(w, h, Image.Format.RGBA16F), emissive).setName("emissive"); + normal = register(new TextureDef2D(w, h, Image.Format.RGBA32F), normal).setName("normal"); + lights = register(ValueDef.create(n -> new LightList(null)), lights).setName("lights"); + } + @Override + protected void execute(FGRenderContext context) { + // acquire and attach texture targets + frameBuffer.setDepthTarget(context.createTextureTarget(resources.acquire(depth))); + resources.acquireColorTargets(frameBuffer, diffuse, specular, emissive, normal); + LightList lightList = resources.acquire(lights); + // render to gBuffer + context.setFrameBuffer(frameBuffer, true, true, true); + context.getRenderer().setBackgroundColor(mask.set(context.getViewPort().getBackgroundColor()).setAlpha(0)); + context.getRenderManager().setForcedTechnique(GBUFFER_PASS); + context.getRenderManager().setGeometryRenderHandler(this); + context.renderViewPortQueue(RenderQueue.Bucket.Opaque, true); + // add accumulated lights + while (!accumulatedLights.isEmpty()) { + lightList.add(accumulatedLights.pollFirst()); + } + frameBuffer.clearColorTargets(); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} @Override - public void createResources(RenderContext context, ResourceList resources) { - resources.register(this, new TextureDef2D(1024, 1024, Image.Format.RGBA8), texTicket1); - resources.reference(depthTicket); + protected FrameBuffer createFrameBuffer(FGRenderContext context) { + FrameBuffer buffer = new FrameBuffer(context.getWidth(), context.getHeight(), 1); + buffer.setMultiTarget(true); + return buffer; } @Override - public void execute(RenderContext context) { - + public boolean renderGeometry(RenderManager rm, Geometry geom) { + Material material = geom.getMaterial(); + if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null) { + return false; + } + rm.renderGeometry(geom); + if (material.getActiveTechnique() != null) { + if (material.getMaterialDef().getTechniqueDefs(GBUFFER_PASS) != null) { + LightList lts = geom.getFilterWorldLights(); + for (Light l : lts) { + // todo: checking for containment is very slow + if (!accumulatedLights.contains(l)) { + accumulatedLights.add(l); + } + } + return true; + } + } + return false; + } + + public void setDepth(ResourceTicket depth) { + this.depth = depth.copyIndexTo(this.depth); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphConstructor.java new file mode 100644 index 0000000000..850ef4d632 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphConstructor.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 codex + */ +public interface GraphConstructor { + + public void addPasses(FrameGraph frameGraph); + + public void preparePasses(FGRenderContext context); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java deleted file mode 100644 index 0282807ba6..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderContext.java +++ /dev/null @@ -1,117 +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.profile.AppProfiler; -import com.jme3.renderer.Camera; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.Renderer; -import com.jme3.renderer.ViewPort; -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 RenderContext { - - private final RenderManager renderManager; - private ViewPort viewPort; - private AppProfiler profiler; - private final DepthRange depth = new DepthRange(); - private final CameraSize camSize = new CameraSize(); - private float tpf; - - public RenderContext(RenderManager renderManager, ViewPort viewPort) { - this.renderManager = renderManager; - this.viewPort = viewPort; - } - public RenderContext(RenderManager renderManager) { - this(renderManager, null); - } - - public void update(ViewPort vp, AppProfiler profiler, float tpf) { - this.viewPort = vp; - this.profiler = profiler; - this.tpf = tpf; - if (viewPort == null) { - throw new NullPointerException("ViewPort cannot be null."); - } - camSize.update(viewPort.getCamera()); - } - - public void setDepthRange(float start, float end) { - if (!depth.equals(start, end)) { - depth.set(start, end); - renderManager.getRenderer().setDepthRange(depth); - } - } - public void setDepthRange(DepthRange depth) { - if (!this.depth.equals(depth)) { - renderManager.getRenderer().setDepthRange(this.depth.set(depth)); - } - } - - public DepthRange getDepthRange() { - return depth; - } - public RenderManager getRenderManager() { - return renderManager; - } - public ViewPort getViewPort() { - return viewPort; - } - public AppProfiler getProfiler() { - return profiler; - } - public CameraSize getCameraSize() { - return camSize; - } - public float getTpf() { - return tpf; - } - public Renderer getRenderer() { - return renderManager.getRenderer(); - } - public RenderQueue getRenderQueue() { - if (viewPort != null) { - return viewPort.getQueue(); - } else { - return null; - } - } - - public boolean isProfilerAvailable() { - return profiler != null; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java index eb9d955892..5d7b68c7f7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java @@ -4,35 +4,130 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.texture.FrameBuffer; +import java.util.Arrays; import java.util.LinkedList; -import java.util.List; /** * * @author codex */ -public abstract class RenderPass { +public abstract class RenderPass implements ResourceProducer { + protected ResourceList resources; private final LinkedList inputs = new LinkedList<>(); private final LinkedList outputs = new LinkedList<>(); + private final CameraSize camSize = new CameraSize(); private int refs = 0; + protected FrameBuffer frameBuffer; - public abstract void createResources(RenderContext context, ResourceList resources); - public abstract void execute(RenderContext context); + public void initializePass(FrameGraph frameGraph) { + this.resources = frameGraph.getResources(); + initialize(frameGraph); + } + public void prepareRender(FGRenderContext context) { + prepare(context); + } + public void executeRender(FGRenderContext context) { + if (camSize.update(context.getCameraSize()) || frameBuffer == null) { + if (frameBuffer != null) { + destroyFrameBuffer(context, frameBuffer); + } + frameBuffer = createFrameBuffer(context); + } + execute(context); + context.popRenderSettings(); + releaseAll(); + } + public void resetRender(FGRenderContext context) { + reset(context); + inputs.clear(); + outputs.clear(); + } + public void cleanupPass(FrameGraph frameGraph) { + cleanup(frameGraph); + } + + protected abstract void initialize(FrameGraph frameGraph); + protected abstract void prepare(FGRenderContext context); + protected abstract void execute(FGRenderContext context); + protected abstract void reset(FGRenderContext context); + protected abstract void cleanup(FrameGraph frameGraph); + + protected FrameBuffer createFrameBuffer(FGRenderContext context) { + return null; + } + protected void destroyFrameBuffer(FGRenderContext context, FrameBuffer fbo) { + fbo.dispose(); + //fbo.deleteObject(context.getRenderer()); + } + + protected ResourceTicket register(ResourceDef def, ResourceTicket ticket) { + ticket = resources.register(this, def, ticket); + addOutput(ticket); + return ticket; + } + protected void reference(ResourceTicket ticket) { + resources.reference(ticket); + addInput(ticket); + } + protected void reference(ResourceTicket... tickets) { + resources.reference(tickets); + addInputs(tickets); + } + protected boolean referenceOptional(ResourceTicket ticket) { + if (resources.referenceOptional(ticket)) { + addInput(ticket); + return true; + } + return false; + } + protected void referenceOptional(ResourceTicket... tickets) { + for (ResourceTicket t : tickets) { + referenceOptional(t); + } + } + private void releaseAll() { + for (ResourceTicket t : inputs) { + resources.release(t); + } + for (ResourceTicket t : outputs) { + resources.release(t); + } + } + + protected ResourceTicket addInput(ResourceTicket input) { + inputs.add(input); + return input; + } + protected void addInputs(ResourceTicket... inputs) { + this.inputs.addAll(Arrays.asList(inputs)); + } + protected ResourceTicket addOutput(ResourceTicket output) { + outputs.add(output); + return output; + } public void countReferences() { refs = outputs.size(); } + + @Override public boolean dereference() { refs--; return isReferenced(); } + @Override public boolean isReferenced() { return refs > 0; } - - public void dereferenceInputs(ResourceList resources, List resList) { - resources.dereferenceListed(inputs, resList); + @Override + public LinkedList getInputTickets() { + return inputs; + } + @Override + public LinkedList getOutputTickets() { + return outputs; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 1aa29000ef..d9ae99ca86 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -11,26 +11,23 @@ */ public class RenderResource { - private final RenderPass producer; + private final ResourceProducer producer; private final ResourceDef def; - private int index; + private final ResourceTicket ticket; private T resource; private int refs = 0; + private int timeout = 0; + private boolean watched = false; - public RenderResource(RenderPass producer, ResourceDef def) { + public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { this.producer = producer; this.def = def; + this.ticket = ticket; } public void create() { resource = def.create(); } - public void setResource(T resource) { - this.resource = resource; - } - public void setIndex(int index) { - this.index = index; - } public void reference() { refs++; @@ -38,19 +35,38 @@ public void reference() { public void release() { refs--; } + public boolean tickTimeout() { + return timeout-- > 0; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + public void setResource(T resource) { + this.resource = resource; + } + public void setWatched(boolean watched) { + this.watched = watched; + } - public RenderPass getProducer() { + public ResourceProducer getProducer() { return producer; } public ResourceDef getDefinition() { return def; } - public int getIndex() { - return index; + public ResourceTicket getTicket() { + return ticket; } public T getResource() { return resource; } + public int getIndex() { + return ticket.getIndex(); + } + public int getNumReferences() { + return refs; + } public boolean isVirtual() { return resource == null; @@ -61,5 +77,14 @@ public boolean isReferenced() { public boolean isUsed() { return refs >= 0; } + public boolean isWatched() { + return watched; + } + + @Override + public String toString() { + return "RenderResource[index="+ticket.getIndex()+", resource=" + +(resource != null ? resource.getClass().getName() : "null")+"]"; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAllocator.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAllocator.java deleted file mode 100644 index 5d8f696291..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceAllocator.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.Iterator; -import java.util.LinkedList; - -/** - * - * @author codex - */ -public class ResourceAllocator { - - private final LinkedList resources = new LinkedList<>(); - - public void add(RenderResource res) { - if (res.isVirtual()) { - throw new IllegalArgumentException("Resource cannot be virtual."); - } - resources.add(res); - } - - /** - * Reallocates a resource from the pool to the given resource, if the - * resource definition accepts. - * - * @param - * @param resource - * @return true if a resource was reallocated to the given resource - */ - public boolean reallocateTo(RenderResource resource) { - for (Iterator it = resources.iterator(); it.hasNext();) { - RenderResource res = it.next(); - if (resource.getDefinition().isOfResourceType(res.getResource().getClass())) { - T r = (T)res.getResource(); - if (resource.getDefinition().acceptReallocationOf(r)) { - resource.setResource(r); - it.remove(); - return true; - } - } - } - return false; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java index 40f746a374..bcf7767e6a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java @@ -12,82 +12,31 @@ public abstract class ResourceDef { private final Class resType; + private int timeout = -1; public ResourceDef(Class resType) { this.resType = resType; } - /** - * Creates and returns a new resource. - * - * @return - */ public abstract T create(); + public abstract boolean applyRecycled(T resource); + public void destroy(T resource) {} - /** - * Returns true if this definition accepts the reallocation of the given - * resource to the {@link RenderResource} this is assigned to. - * - * @param resource - * @return - */ - public abstract boolean acceptReallocationOf(T resource); + public void setRecycleTimeout(int timeout) { + this.timeout = timeout; + } - /** - * Returns true if this definition's resource type - * {@link Class#isAssignableFrom(java.lang.Class) is assignable from} the - * given class. - * - * @param type - * @return - */ public boolean isOfResourceType(Class type) { - return resType.isAssignableFrom(type); + return resType != null && resType.isAssignableFrom(type); } - - /** - * Returns true if the {@link RenderResource} this is assigned to can accept - * reallocated resources. - * - * @return - */ - public boolean isAcceptsReallocated() { - return true; + public boolean isAcceptsRecycled() { + return resType != null; } - - /** - * If true, the existing resource contained in the {@link RenderResource} - * this is assigned to will be reallocated to another RenderResource, if possible. - *

    - * Reallocation only occurs after all users have released the RenderResource. - * - * @return - */ - public boolean isReallocatable() { + public boolean isRecycleable() { return true; } - - /** - * If true, the existing resource contained in the {@link RenderResource} - * this is assigned to be destroyed during rendering cleanup. - * - * @return - */ - public boolean isTransient() { - return false; - } - - /** - * Returns true if the {@link RenderResource} this is assigned to should be - * discarded when it becomes unused. - *

    - * This overrides {@link #isReallocatable()} and {@link #isTransient()}, as the - * resource will not survive to do either. - * - * @return - */ - public boolean isDiscardIfUnused() { - return false; + public int getRecycleTimeout() { + return timeout; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 4264951444..db3afa4a94 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -4,6 +4,8 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -16,15 +18,18 @@ public class ResourceList { private static final int INITIAL_SIZE = 20; - private final ResourceAllocator allocator; + private ResourceRecycler recycler; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); private int nextSlot = 0; - public ResourceList(ResourceAllocator allocator) { - this.allocator = allocator; + public ResourceList(ResourceRecycler recycler) { + this.recycler = recycler; } protected RenderResource locate(ResourceTicket ticket) { + if (ticket == null) { + throw new NullPointerException("Ticket cannot be null."); + } final int i = ticket.getIndex(); if (i >= 0 && i < resources.size()) { RenderResource res = resources.get(i); @@ -57,61 +62,185 @@ protected int add(RenderResource res) { } } protected RenderResource remove(int index) { + RenderResource prev = resources.set(index, null); + if (prev != null && prev.isReferenced()) { + throw new IllegalStateException("Cannot remove "+prev+" because it is referenced."); + } nextSlot = Math.min(nextSlot, index); - return resources.set(index, null); + return prev; } - public ResourceTicket register(RenderPass producer, ResourceDef def) { - return new ResourceTicket<>(add(new RenderResource<>(producer, def))); + public ResourceTicket register(ResourceProducer producer, ResourceDef def) { + return register(producer, def, null); } + public ResourceTicket register(ResourceProducer producer, ResourceDef def, ResourceTicket store) { + ResourceTicket t = new ResourceTicket<>(); + t.setIndex(add(new RenderResource<>(producer, def, t))); + store = t.copyIndexTo(store); + System.out.println(" "+producer+": register "+t); + return store; + } + public void reference(ResourceTicket ticket) { locate(ticket).reference(); + System.out.println(" "+locate(ticket).getProducer()+": reference "+ticket); + } + public boolean referenceOptional(ResourceTicket ticket) { + if (ticket != null) { + reference(ticket); + return true; + } + System.out.println(" optional reference failed"); + return false; + } + public void reference(ResourceTicket... tickets) { + for (ResourceTicket t : tickets) { + reference(t); + } + } + public void referenceOptional(ResourceTicket... tickets) { + for (ResourceTicket t : tickets) { + referenceOptional(t); + } + } + + public > R getDef(Class type, ResourceTicket ticket) { + ResourceDef def = locate(ticket).getDefinition(); + if (type.isAssignableFrom(def.getClass())) { + return (R)def; + } + return null; } + public T acquire(ResourceTicket ticket) { RenderResource res = locate(ticket); - if (res.isVirtual() && (!res.getDefinition().isAcceptsReallocated() || allocator.reallocateTo(res))) { + if (!res.isUsed()) { + throw new IllegalStateException(res+" was unexpectedly acquired."); + } + System.out.println(" acquire resource from "+ticket); + if (!res.isVirtual()) { + System.out.println(" resource already created"); + } + if (res.isVirtual() && !recycler.recycle(res)) { + System.out.println(" create from scratch for "+res); res.create(); } return res.getResource(); } - public void release(ResourceTicket ticket) { - RenderResource res = locate(ticket); - res.release(); - if (!res.isUsed()) { - remove(ticket.getIndex()); + public T acquire(ResourceTicket ticket, T value) { + if (ticket != null) { + return acquire(ticket); + } else { + return value; } - if (res.getDefinition().isReallocatable()) { - allocator.add(res); + } + public void acquireColorTargets(FrameBuffer fbo, ResourceTicket... tickets) { + for (ResourceTicket t : tickets) { + fbo.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(acquire(t))); } } - public void getUnreferenced(List resList) { - for (int i = 0; i < resources.size(); i++) { - RenderResource r = resources.get(i); - if (r != null && !r.isReferenced()) { - resList.add(r); + public void release(ResourceTicket ticket) { + if (ticket != null) { + RenderResource res = locate(ticket); + res.release(); + if (!res.isUsed()) { + System.out.println(" resource is not used: "+res); + remove(ticket.getIndex()); + if (res.getDefinition().isRecycleable()) { + recycler.add(res); + } } } } - public void dereferenceListed(List tickets, List resList) { + public boolean releaseOptional(ResourceTicket ticket) { + if (ticket != null) { + release(ticket); + return true; + } + return false; + } + public void release(ResourceTicket... tickets) { + for (ResourceTicket t : tickets) { + release(t); + } + } + public void releaseOptional(ResourceTicket... tickets) { + for (ResourceTicket t : tickets) { + releaseOptional(t); + } + } + + public void watch(ResourceTicket ticket) { + locate(ticket).setWatched(true); + } + public boolean watchOptional(ResourceTicket ticket) { + if (ticket != null) { + watch(ticket); + return true; + } + return false; + } + public void watch(ResourceTicket... tickets) { + for (ResourceTicket t : tickets) { + watch(t); + } + } + public void watchOptional(ResourceTicket... tickets) { + for (ResourceTicket t : tickets) { + watchOptional(t); + } + } + + public void dereferenceListed(List tickets, List target) { for (ResourceTicket t : tickets) { RenderResource r = locate(t); r.release(); if (!r.isReferenced()) { - resList.add(r); + target.add(r); } } } - public void discardUnreferenced() { - for (int i = 0; i < resources.size(); i++) { - RenderResource r = resources.get(i); - if (!r.isReferenced()) { - remove(i); + public void cullUnreferenced() { + LinkedList cull = new LinkedList<>(); + for (RenderResource r : resources) { + if (r != null && !r.isReferenced()) { + cull.add(r); + } + } + RenderResource resource; + while ((resource = cull.pollFirst()) != null) { + // dereference producer of resource + if (!resource.getProducer().dereference()) { + // if producer is not referenced, dereference all input resources + for (ResourceTicket t : resource.getProducer().getInputTickets()) { + RenderResource r = locate(t); + r.release(); + if (!r.isReferenced()) { + cull.addLast(r); + } + } + // remove all output resources + for (ResourceTicket t : resource.getProducer().getOutputTickets()) { + remove(t.getIndex()); + } } } } + public void clear() { + int n = 0; int size = resources.size(); + for (RenderResource r : resources) { + if (r != null) { + n++; + if (r.isUsed()) { + System.out.println("Warning: "+r+" still retains "+(r.getNumReferences()+1)+" references"); + } + } + } + System.out.println("peak concurrent resources: "+size); + System.out.println("unculled resources: "+n); resources = new ArrayList<>(size); nextSlot = 0; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java new file mode 100644 index 0000000000..4baa372f07 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java @@ -0,0 +1,21 @@ +/* + * 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.Collection; + +/** + * + * @author codex + */ +public interface ResourceProducer { + + public boolean dereference(); + public boolean isReferenced(); + + public Collection getInputTickets(); + public Collection getOutputTickets(); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java new file mode 100644 index 0000000000..ca0e159e22 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java @@ -0,0 +1,69 @@ +/* + * 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.Iterator; +import java.util.LinkedList; + +/** + * + * @author codex + */ +public class ResourceRecycler { + + private final LinkedList resources = new LinkedList<>(); + private int timeout = 1; + + public void add(RenderResource res) { + if (res.isVirtual()) { + throw new IllegalArgumentException("Resource cannot be virtual."); + } + if (res.getDefinition().getRecycleTimeout() >= 0) { + res.setTimeout(res.getDefinition().getRecycleTimeout()); + } else { + res.setTimeout(timeout); + } + //res.getDefinition().destroy(res.getResource()); + resources.add(res); + } + + public boolean recycle(RenderResource resource) { + ResourceDef def = resource.getDefinition(); + if (!def.isAcceptsRecycled()) { + return false; + } + System.out.println(" try "+resources.size()+" available resources to recycle"); + for (Iterator it = resources.iterator(); it.hasNext();) { + RenderResource res = it.next(); + if (def.isOfResourceType(res.getResource().getClass())) { + T r = (T)res.getResource(); + if (def.applyRecycled(r)) { + System.out.println(" recycle for "+resource); + resource.setResource(r); + it.remove(); + return true; + } + } + } + return false; + } + + public void flush() { + // Note: flushing resources on the same frame they were created causes the + // screen to render black. Guess: destroying output texture early causes + // the input to become null? + int n = 0; + for (Iterator it = resources.iterator(); it.hasNext();) { + RenderResource r = it.next(); + if (!r.tickTimeout()) { + n++; + r.getDefinition().destroy(r.getResource()); + it.remove(); + } + } + System.out.println("resources flushed: "+n); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index 545d503187..c767578854 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -16,12 +16,24 @@ */ public class ResourceTicket { + private static long nextId = 0; + + private final long id; + private String name; private int index; public ResourceTicket() { - this(-1); + this(null, -1); + } + public ResourceTicket(String name) { + this(name, -1); } public ResourceTicket(int index) { + this(null, index); + } + public ResourceTicket(String name, int index) { + this.id = nextId++; + this.name = name; this.index = index; } @@ -34,7 +46,7 @@ public ResourceTicket(int index) { * @param target copy target (can be null) * @return target */ - public ResourceTicket copyTo(ResourceTicket target) { + public ResourceTicket copyIndexTo(ResourceTicket target) { if (target == null) { target = new ResourceTicket(); } @@ -43,12 +55,45 @@ public ResourceTicket copyTo(ResourceTicket target) { } /** - * Sets the resource index. + * Sets the name of this ticket. + *

    + * Names are used to locate a particular ticket among a group. + * + * @param name + * @return this ticket instance + */ + public ResourceTicket setName(String name) { + this.name = name; + return this; + } + + /** + * Sets the index. * - * @param index + * @param index + * @return this instance */ - public void setIndex(int index) { + protected ResourceTicket setIndex(int index) { this.index = index; + return this; + } + + /** + * Gets the id unique to this ticket. + * + * @return + */ + public long getId() { + return id; + } + + /** + * Gets the name of this ticket. + * + * @return + */ + public String getName() { + return name; } /** @@ -62,24 +107,7 @@ public int getIndex() { @Override public String toString() { - return "ResourceTicket["+index+"]"; - } - @Override - public int hashCode() { - int hash = 7; - hash = 97 * hash + this.index; - return hash; - } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - final ResourceTicket other = (ResourceTicket) obj; - return this.index == other.index; + return "Ticket[id="+id+", name="+name+", index="+index+"]"; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResultPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResultPass.java new file mode 100644 index 0000000000..ad7c1b508a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResultPass.java @@ -0,0 +1,54 @@ +/* + * 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.RenderState; +import com.jme3.texture.Texture2D; + +/** + * + * @author codex + */ +public class ResultPass extends RenderPass { + + private ResourceTicket inColor, inDepth; + private Texture2D forcedTex; + + @Override + public void initialize(FrameGraph frameGraph) { + forcedTex = (Texture2D)frameGraph.getAssetManager().loadTexture("Common/Textures/MissingTexture.png"); + } + @Override + public void prepare(FGRenderContext context) { + referenceOptional(inColor, inDepth); + } + @Override + public void execute(FGRenderContext context) { + Texture2D color = resources.acquire(inColor, null); + Texture2D depth = resources.acquire(inDepth, null); + context.transferTextures(color, depth, RenderState.BlendMode.Alpha); + } + @Override + public void reset(FGRenderContext context) {} + @Override + public void cleanup(FrameGraph frameGraph) {} + @Override + public boolean isReferenced() { + return true; + } + + public void setInColor(ResourceTicket inColor) { + this.inColor = inColor; + } + public void setInDepth(ResourceTicket inDepth) { + this.inDepth = inDepth; + } + + @Override + public String toString() { + return "ResultPass[]"; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java new file mode 100644 index 0000000000..b01d08b010 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java @@ -0,0 +1,37 @@ +/* + * 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.queue.RenderQueue.Bucket; + +/** + * + * @author codex + */ +public class TestConstructor implements GraphConstructor { + + private BucketPass opaque, sky; + private ResultPass result; + + @Override + public void addPasses(FrameGraph frameGraph) { + opaque = frameGraph.add(new BucketPass(Bucket.Opaque)); + sky = frameGraph.add(new BucketPass(Bucket.Sky, DepthRange.REAR)); + result = frameGraph.add(new ResultPass()); + } + @Override + public void preparePasses(FGRenderContext context) { + //opaque.setInput(sky); + opaque.prepareRender(context); + sky.setInput(opaque); + sky.prepareRender(context); + //result.setInColor(opaque.getOutColor()); + //result.setInDepth(opaque.getOutDepth()); + result.setInColor(sky.getOutColor()); + result.setInDepth(sky.getOutDepth()); + result.prepareRender(context); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java index b1a5b6f001..48a95b9b44 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java @@ -13,26 +13,63 @@ */ public class TextureDef2D extends ResourceDef { - private final int width; - private final int height; - private final Image.Format format; + private int width, height, samples; + private Image.Format format; public TextureDef2D(int width, int height, Image.Format format) { + this(width, height, 1, format); + } + public TextureDef2D(int width, int height, int samples, Image.Format format) { super(Texture2D.class); this.width = width; this.height = height; + this.samples = samples; this.format = format; } @Override public Texture2D create() { - return new Texture2D(width, height, format); + if (samples != 1) { + return new Texture2D(width, height, samples, format); + } else { + return new Texture2D(width, height, format); + } } - @Override - public boolean acceptReallocationOf(Texture2D resource) { + public boolean applyRecycled(Texture2D resource) { Image img = resource.getImage(); - return img.getWidth() == width && img.getHeight() == height && img.getFormat() == format; + return img.getWidth() == width && img.getHeight() == height + && img.getFormat() == format && img.getMultiSamples() == samples; + } + @Override + public void destroy(Texture2D tex) { + tex.getImage().dispose(); + } + + public void setWidth(int width) { + this.width = width; + } + public void setHeight(int height) { + this.height = height; + } + public void setSamples(int samples) { + this.samples = samples; + } + public void setFormat(Image.Format format) { + this.format = format; + } + + public int getWidth() { + return width; + } + public int getHeight() { + return height; + } + public int getSamples() { + return samples; + } + public Image.Format getFormat() { + return format; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueDef.java new file mode 100644 index 0000000000..8acf33bf1c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueDef.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; + +import java.util.function.Function; + +/** + * + * @author codex + * @param + */ +public abstract class ValueDef extends ResourceDef { + + public ValueDef() { + super(null); + } + + @Override + public boolean applyRecycled(T resource) { + return false; + } + + @Override + public boolean isRecycleable() { + return false; + } + + public static ValueDef create(Function func) { + return new ValueDefImpl(func); + } + + private static class ValueDefImpl extends ValueDef { + + private final Function func; + + public ValueDefImpl(Function func) { + this.func = func; + } + + @Override + public T create() { + return func.apply(null); + } + + } + +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert index d0122dc266..0115cf495e 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert @@ -1,23 +1,24 @@ + #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 +#ifdef USE_LIGHTS_CULL_MODE + varying vec2 texCoord; +#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 + + #ifndef USE_LIGHTS_CULL_MODE + texCoord = inPosition.xy; + gl_Position = vec4(sign(inPosition.xy - vec2(0.5)), 0.0, 1.0); + #else + gl_Position = TransformWorldViewProjection(vec4(inPosition, 1.0)); + #endif viewProjectionMatrixInverse = GetViewProjectionMatrixInverse(); } + diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert new file mode 100644 index 0000000000..c010f034f3 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert @@ -0,0 +1,12 @@ + +#import "Common/ShaderLib/GLSLCompat.glsllib" + +attribute vec3 inPosition; + +varying vec2 texCoord; + +void main() { + texCoord = inPosition.xy; + gl_Position = vec4(sign(inPosition.xy - vec2(0.5)), 0.0, 1.0); +} + diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag new file mode 100644 index 0000000000..e44f5bbaff --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag @@ -0,0 +1,35 @@ + +#import "Common/ShaderLib/GLSLCompat.glsllib" + +#ifdef WRITE_COLOR + uniform sampler2D m_ColorMap; +#endif +#ifdef WRITE_DEPTH + uniform sampler2D m_DepthMap; +#endif +#ifdef WRITE_ALPHA + uniform float m_Alpha; +#endif + +varying vec2 texCoord; + +void main() { + + #ifdef WRITE_COLOR + gl_FragColor = texture2D(m_ColorMap, texCoord); + #else + gl_FragColor = vec4(0.0); + #endif + + #ifdef WRITE_DEPTH + gl_FragDepth = texture2D(m_DepthMap, texCoord).r; + #else + gl_FragDepth = 1.0; + #endif + + #ifdef WRITE_ALPHA + gl_FragColor.a = m_Alpha; + #endif + +} + diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md new file mode 100644 index 0000000000..2a70289dc2 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md @@ -0,0 +1,31 @@ +MaterialDef TextureTransfer { + + MaterialParameters { + Texture2D ColorMap + Texture2D DepthMap + Float Alpha + } + + Technique { + + Pipeline Deferred + + VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/Screen.vert + FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/TextureTransfer.frag + + WorldParameters { + CameraPosition + ViewProjectionMatrixInverse + WorldViewProjectionMatrix + ViewProjectionMatrix + ResolutionInverse + } + + Defines { + WRITE_COLOR : ColorMap + WRITE_DEPTH : DepthMap + WRITE_ALPHA : Alpha + } + } + +} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index e221135663..13f176edc9 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -13,17 +13,15 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.parameters.MatRenderParam; +import com.jme3.renderer.framegraph.ForwardGraphConstructor; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.RenderPipelineFactory; -import com.jme3.renderer.framegraph.pass.DeferredShadingModule; +import com.jme3.renderer.framegraph.TestConstructor; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; -import com.jme3.shader.VarType; import com.jme3.shadow.DirectionalLightShadowRenderer; import com.jme3.system.AppSettings; import com.jme3.texture.plugins.ktx.KTXLoader; @@ -58,9 +56,14 @@ public static void main(String[] args) { @Override public void simpleInitApp() { - FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); + //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); + FrameGraph graph = new FrameGraph(assetManager, renderManager); + graph.setConstructor(new ForwardGraphConstructor()); + //graph.setConstructor(new TestConstructor()); //MyFrameGraph graph = RenderPipelineFactory.createBackroundScreenTest(assetManager, renderManager); - renderManager.setFrameGraph(graph); + viewPort.setFrameGraph(graph); + //guiViewPort.setFrameGraph(graph); + //renderManager.setFrameGraph(graph); viewPort.setBackgroundColor(ColorRGBA.Green.mult(0.2f)); //viewPort.setBackgroundColor(ColorRGBA.White); @@ -71,9 +74,9 @@ public void simpleInitApp() { //debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); //debugMat.setTransparent(true); debugView.setMaterial(debugMat); - MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); + //MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); //texParam.enableDebug(); - graph.bindToOutput(DeferredShadingModule.DEPTH_DEBUG, texParam); + //graph.bindToOutput(DeferredShadingModule.DEPTH_DEBUG, texParam); //guiNode.attachChild(debugView); // UNLIT @@ -89,7 +92,7 @@ public void simpleInitApp() { unlitSphere.setLocalTranslation(-5, 0, 0); unlitSphere.setLocalRotation(new Quaternion(new float[]{(float) Math.toRadians(-90), 0, 0})); unlitSphere.setMaterial(unlitMat); - unlitSphere.setQueueBucket(RenderQueue.Bucket.Transparent); + unlitSphere.setQueueBucket(RenderQueue.Bucket.Opaque); rootNode.attachChild(unlitSphere); // LEGACY_LIGHTING @@ -149,6 +152,12 @@ public void simpleInitApp() { //new RenderPathHelper(this); flyCam.setMoveSpeed(10.0f); } + + @Override + public void simpleUpdate(float tpf) { + cam.lookAt(new Vector3f(), Vector3f.UNIT_Y); + System.out.println("------------------- FRAME"); + } @Override public void simpleRender(RenderManager rm) { @@ -157,7 +166,7 @@ public void simpleRender(RenderManager rm) { if (frame == 2) { - rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); + //rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); } if (frame > 10 && modelNode.getParent() == null) { From 08f60d8ac0bc0155ea6727ade50a29678f96194f Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 4 May 2024 16:06:34 -0400 Subject: [PATCH 050/111] framegraph complete --- .../java/com/jme3/renderer/RenderManager.java | 51 +++------- .../jme3/renderer/framegraph/BucketPass.java | 38 ++----- .../framegraph/DeferredGraphConstructor.java | 57 +++++++++++ .../renderer/framegraph/DeferredPass.java | 55 +++++++++-- .../renderer/framegraph/FGRenderContext.java | 59 +++-------- .../framegraph/ForwardGraphConstructor.java | 34 ++----- .../renderer/framegraph/FrameBufferDef.java | 57 +++++++++++ .../jme3/renderer/framegraph/FrameGraph.java | 6 +- .../renderer/framegraph/FullScreenQuad.java | 67 +++++++++++++ .../jme3/renderer/framegraph/GBufferPass.java | 19 +++- .../renderer/framegraph/OutputBucketPass.java | 51 ++++++++++ .../{ResultPass.java => OutputPass.java} | 34 +++---- .../framegraph/PostProcessingPass.java | 51 ++++++++++ .../jme3/renderer/framegraph/RenderPass.java | 25 ++--- .../renderer/framegraph/RenderResource.java | 6 +- .../renderer/framegraph/ResourceList.java | 61 ++++++------ .../renderer/framegraph/ResourceRecycler.java | 27 ++--- .../renderer/framegraph/TestConstructor.java | 4 +- .../renderer/framegraph/TileDeferredPass.java | 99 +++++++++++++++++++ .../ShadingCommon/DeferredShading.frag | 6 +- .../ShadingCommon/DeferredShading.vert | 2 +- .../ShadingCommon/TextureTransfer.frag | 14 ++- .../ShadingCommon/TextureTransfer.j3md | 4 +- .../TileBasedDeferredShading.frag | 6 +- .../TileBasedDeferredShading.j3md | 3 +- .../Common/ShaderLib/Deferred.glsllib | 25 ++--- ...thPointDirectionalAndSpotLightShadows.java | 9 +- .../jme3test/renderpath/TestShadingModel.java | 7 +- 28 files changed, 609 insertions(+), 268 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferDef.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputBucketPass.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ResultPass.java => OutputPass.java} (50%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/PostProcessingPass.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/TileDeferredPass.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 da954502e3..8a29212e3e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -143,39 +143,19 @@ public RenderManager(Renderer renderer) { this.renderer = renderer; this.forcedOverrides.add(boundDrawBufferId); } - - /** - * Sets the framegraph used for rendering if the rendered viewport - * has no framegraph assigned. - *

    - * If this framegraph is null, and the viewport currently being rendered has - * no framegraph assigned, JME's legacy forward rendering method will be used. - * - * @param frameGraph default framegraph, or null to not use a framegraph by default for rendering - */ - public void setFrameGraph(FrameGraph frameGraph) { - this.frameGraph = frameGraph; - } - - /** - * Gets the framegraph used for rendering if the rendered viewport - * has no framegraph assigned. - * - * @return default framegraph, or null if framegraphs are not used by default for rendering - */ + public FrameGraph getFrameGraph() { return frameGraph; } - - /** - * Gets the global resource pool used to store potential render resources. - * - * @return - */ - public ResourceRecycler getResourceRecycler() { - return recycler; + + public void setFrameGraph(FrameGraph frameGraph) { + this.frameGraph = frameGraph; } + public ResourceRecycler getRecycler() { + return recycler; + } + /** * Sets the GeometryRenderHandler used to render geometry. *

    @@ -1285,13 +1265,11 @@ public void renderViewPort(ViewPort vp, float tpf) { if (fg == null) { fg = frameGraph; } - if (fg != null) { - fg.getContext().update(vp, prof, tpf); - //fg.preFrame(); - - } else if (processors != null) { + } + + if (processors != null) { if (prof != null) { prof.vpStep(VpStep.PreFrame, vp, null); } @@ -1325,11 +1303,7 @@ public void renderViewPort(ViewPort vp, float tpf) { renderScene(scenes.get(i), vp); } - if (fg != null) { - - //fg.postQueue(); - - } else if (processors != null) { + if (processors != null) { if (prof != null) { prof.vpStep(VpStep.PostQueue, vp, null); } @@ -1432,6 +1406,7 @@ public void render(float tpf, boolean mainFrameBufferActive) { } } + // flush unrecycled resources recycler.flush(); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java index c21653c918..cc1e85a6d4 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java @@ -4,12 +4,8 @@ */ package com.jme3.renderer.framegraph; -import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; -import com.jme3.renderer.GeometryRenderHandler; -import com.jme3.renderer.RenderManager; import com.jme3.renderer.queue.RenderQueue.Bucket; -import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; @@ -18,13 +14,14 @@ * * @author codex */ -public class BucketPass extends RenderPass implements GeometryRenderHandler { +public class BucketPass extends RenderPass { private Bucket bucket; private DepthRange depth; private int samples = 1; private boolean flush = true; private ResourceTicket inColor, inDepth, outColor, outDepth; + private ResourceTicket frameBuffer; private Texture2D fTex; public BucketPass(Bucket bucket) { @@ -48,48 +45,33 @@ protected void prepare(FGRenderContext context) { int h = context.getHeight(); outColor = register(new TextureDef2D(w, h, samples, Image.Format.RGBA8), outColor); outDepth = register(new TextureDef2D(w, h, samples, Image.Format.Depth), outDepth); + frameBuffer = register(new FrameBufferDef(w, h, samples), frameBuffer); referenceOptional(inColor, inDepth); } @Override protected void execute(FGRenderContext context) { - frameBuffer.addColorTarget(context.createTextureTarget(resources.acquire(outColor))); - frameBuffer.setDepthTarget(context.createTextureTarget(resources.acquire(outDepth))); - context.setFrameBuffer(frameBuffer, true, true, true); + FrameBuffer fb = resources.acquire(frameBuffer); + fb.clearColorTargets(); + // no need to clear the depth target, since we are assigning one below + fb.addColorTarget(context.createTextureTarget(resources.acquire(outColor))); + fb.setDepthTarget(context.createTextureTarget(resources.acquire(outDepth))); + context.setFrameBuffer(fb, true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); - //context.getRenderManager().setGeometryRenderHandler(this); context.transferTextures(resources.acquire(inColor, null), resources.acquire(inDepth, null)); context.getRenderer().setDepthRange(depth); if (bucket == Bucket.Gui) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); } - //context.getRenderer().setDepthRange(0, 0); context.renderViewPortQueue(bucket, flush); if (bucket == Bucket.Gui) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); } - //context.transferTextures(fTex, null, false); - frameBuffer.clearColorTargets(); + fb.clearColorTargets(); } @Override protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} - @Override - protected FrameBuffer createFrameBuffer(FGRenderContext context) { - return new FrameBuffer(context.getWidth(), context.getHeight(), samples); - //return null; - } - @Override - public boolean isReferenced() { - return super.isReferenced(); - //return true; - } - @Override - public boolean renderGeometry(RenderManager rm, Geometry geom) { - rm.renderGeometry(geom); - System.out.println("RENDER GEOMETRY: "+geom); - return true; - } public void setDepthRange(DepthRange depth) { this.depth = depth; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java new file mode 100644 index 0000000000..0d2cdf76a1 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java @@ -0,0 +1,57 @@ +/* + * 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.queue.RenderQueue.Bucket; + +/** + * + * @author codex + */ +public class DeferredGraphConstructor implements GraphConstructor { + + private GBufferPass gbuf; + private TileDeferredPass deferred; + private OutputPass defOut; + private OutputBucketPass sky, transparent, gui, translucent; + private PostProcessingPass post; + + @Override + public void addPasses(FrameGraph frameGraph) { + gbuf = frameGraph.add(new GBufferPass()); + deferred = frameGraph.add(new TileDeferredPass()); + defOut = frameGraph.add(new OutputPass()); + sky = frameGraph.add(new OutputBucketPass(Bucket.Sky, DepthRange.REAR)); + transparent = frameGraph.add(new OutputBucketPass(Bucket.Transparent)); + gui = frameGraph.add(new OutputBucketPass(Bucket.Gui, DepthRange.FRONT)); + post = frameGraph.add(new PostProcessingPass()); + translucent = frameGraph.add(new OutputBucketPass(Bucket.Translucent)); + } + @Override + public void preparePasses(FGRenderContext context) { + + gbuf.prepareRender(context); + + deferred.setDepth(gbuf.getDepth()); + deferred.setDiffuse(gbuf.getDiffuse()); + deferred.setEmissive(gbuf.getEmissive()); + deferred.setNormal(gbuf.getNormal()); + deferred.setLights(gbuf.getLights()); + deferred.setSpecular(gbuf.getSpecular()); + deferred.prepareRender(context); + + defOut.setInColor(deferred.getOutColor()); + defOut.setInDepth(gbuf.getDepth()); + defOut.prepareRender(context); + + sky.prepareRender(context); + transparent.prepareRender(context); + gui.prepareRender(context); + post.prepareRender(context); + translucent.prepareRender(context); + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java index 7862f052ee..32f30a5b1f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java @@ -6,6 +6,8 @@ import com.jme3.light.LightList; import com.jme3.material.Material; +import com.jme3.material.TechniqueDef; +import com.jme3.material.logic.DeferredSinglePassLightingLogic; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; @@ -16,42 +18,75 @@ */ public class DeferredPass extends RenderPass { - private ResourceTicket depth, diffuse, specular, emissive, normal, result; + private ResourceTicket depth, diffuse, specular, emissive, normal, outColor; private ResourceTicket lights; + private ResourceTicket frameBuffer; private Material material; private final CameraSize camSize = new CameraSize(); @Override protected void initialize(FrameGraph frameGraph) { material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); + for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { + t.setLogic(new DeferredSinglePassLightingLogic(t)); + } } @Override protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - result = register( new TextureDef2D(w, h, Image.Format.RGBA8), result); - reference(depth, diffuse, specular, emissive, normal, lights); + outColor = register(new TextureDef2D(w, h, Image.Format.RGBA8), outColor); + frameBuffer = register(new FrameBufferDef(w, h, 1), frameBuffer); + reference(depth, diffuse, specular, emissive, normal); + referenceOptional(lights); } @Override protected void execute(FGRenderContext context) { + FrameBuffer fb = resources.acquire(frameBuffer); + fb.clearColorTargets(); + fb.setDepthTarget((FrameBuffer.FrameBufferTextureTarget)null); + resources.acquireColorTargets(fb, outColor); + context.setFrameBuffer(fb, true, true, true); material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); material.setTexture("Context_InGBuff1", resources.acquire(specular)); material.setTexture("Context_InGBuff2", resources.acquire(emissive)); material.setTexture("Context_InGBuff3", resources.acquire(normal)); material.setTexture("Context_InGBuff4", resources.acquire(depth)); - resources.acquireColorTargets(frameBuffer, result); material.selectTechnique("DeferredPass", context.getRenderManager()); - context.setFrameBuffer(frameBuffer, true, true, true); - context.renderFullscreen(material); - frameBuffer.clearColorTargets(); + LightList lightList = resources.acquire(lights, null); + if (lightList != null) { + context.getScreen().render(context.getRenderManager(), material, lightList); + } else { + context.renderFullscreen(material); + } + fb.clearColorTargets(); } @Override public void reset(FGRenderContext context) {} @Override public void cleanup(FrameGraph frameGraph) {} - @Override - protected FrameBuffer createFrameBuffer(FGRenderContext context) { - return new FrameBuffer(context.getWidth(), context.getHeight(), 1); + + public void setDepth(ResourceTicket depth) { + this.depth = depth; + } + public void setDiffuse(ResourceTicket diffuse) { + this.diffuse = diffuse; + } + public void setSpecular(ResourceTicket specular) { + this.specular = specular; + } + public void setEmissive(ResourceTicket emissive) { + this.emissive = emissive; + } + public void setNormal(ResourceTicket normal) { + this.normal = normal; + } + public void setLights(ResourceTicket lights) { + this.lights = lights; + } + + public ResourceTicket getOutColor() { + return outColor; } } 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 50ef948040..c8136a4d56 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 @@ -56,13 +56,13 @@ */ public class FGRenderContext { + private final FrameGraph frameGraph; private final RenderManager renderManager; private ViewPort viewPort; private AppProfiler profiler; private final CameraSize camSize = new CameraSize(); private float tpf; - private Geometry screen; - private final Material transferMat; + private final FullScreenQuad screen; private String forcedTechnique; private Material forcedMat; @@ -71,10 +71,10 @@ public class FGRenderContext { private Predicate geomFilter; private RenderState renderState; - public FGRenderContext(AssetManager assetManager, RenderManager renderManager) { + public FGRenderContext(FrameGraph frameGraph, RenderManager renderManager) { + this.frameGraph = frameGraph; this.renderManager = renderManager; - transferMat = new Material(assetManager, "Common/MatDefs/ShadingCommon/TextureTransfer.j3md"); - //transferMat.getAdditionalRenderState().setDepthFunc(RenderState.TestFunction.Less); + this.screen = new FullScreenQuad(this.frameGraph.getAssetManager()); } public void update(ViewPort vp, AppProfiler profiler, float tpf) { @@ -118,49 +118,10 @@ public void renderViewPortQueue(RenderQueue.Bucket bucket, boolean clear) { viewPort.getQueue().renderQueue(bucket, renderManager, viewPort.getCamera(), clear); } public void renderFullscreen(Material mat) { - if (screen == null) { - Mesh mesh = new Mesh(); - mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer( - 0, 0, 0, - 1, 0, 0, - 0, 1, 0, - 1, 1, 0 - )); - mesh.setBuffer(VertexBuffer.Type.Index, 3, BufferUtils.createIntBuffer( - 0, 1, 2, - 1, 3, 2 - )); - mesh.updateBound(); - mesh.updateCounts(); - mesh.setStatic(); - screen = new Geometry("Screen", mesh); - } - screen.setMaterial(mat); - screen.updateGeometricState(); - renderManager.renderGeometry(screen); + screen.render(renderManager, mat); } public void transferTextures(Texture2D color, Texture2D depth) { - transferTextures(color, depth, BlendMode.Off); - } - public void transferTextures(Texture2D color, Texture2D depth, BlendMode blend) { - boolean writeDepth = depth != null; - if (color != null || writeDepth) { - transferMat.setTexture("ColorMap", color); - transferMat.setTexture("DepthMap", depth); - transferMat.getAdditionalRenderState().setDepthTest(writeDepth); - transferMat.getAdditionalRenderState().setDepthWrite(writeDepth); - //transferMat.getAdditionalRenderState().setBlendMode(BlendMode.Off); - System.out.println("blend="+blend); - transferMat.getAdditionalRenderState().setBlendMode(blend); - //transferMat.setTransparent(blend == BlendMode.Alpha - // || blend == BlendMode.AlphaAdditive || blend == BlendMode.AlphaSumA); - //System.out.println("blendmode="+transferMat.getAdditionalRenderState().getBlendMode()); - //System.out.println("alpha="+transferMat.isTransparent()); - renderFullscreen(transferMat); - } - } - public FrameBuffer.FrameBufferTextureTarget createTextureTarget(Texture tex) { - return FrameBuffer.FrameBufferTarget.newTarget(tex); + screen.render(renderManager, color, depth); } public void setFrameBuffer(FrameBuffer fbo) { @@ -170,6 +131,9 @@ public void setFrameBuffer(FrameBuffer fbo, boolean clearColor, boolean clearDep setFrameBuffer(fbo); renderManager.getRenderer().clearBuffers(clearColor, clearDepth, clearStencil); } + public FrameBuffer.FrameBufferTextureTarget createTextureTarget(Texture tex) { + return FrameBuffer.FrameBufferTarget.newTarget(tex); + } public RenderManager getRenderManager() { return renderManager; @@ -193,6 +157,9 @@ public RenderQueue getRenderQueue() { return null; } } + public FullScreenQuad getScreen() { + return screen; + } public float getTpf() { return tpf; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java index b54b2004b1..132a2e6c9d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java @@ -11,46 +11,26 @@ * @author codex */ public class ForwardGraphConstructor implements GraphConstructor { - - private BucketPass opaque, sky, transparent, gui, translucent; - private ResultPass result; + + private OutputBucketPass opaque, sky, transparent, gui, translucent; @Override public void addPasses(FrameGraph frameGraph) { - opaque = frameGraph.add(new BucketPass(Bucket.Opaque)); - sky = frameGraph.add(new BucketPass(Bucket.Sky, DepthRange.REAR)); - transparent = frameGraph.add(new BucketPass(Bucket.Transparent)); - gui = frameGraph.add(new BucketPass(Bucket.Gui, DepthRange.FRONT)); - translucent = frameGraph.add(new BucketPass(Bucket.Translucent)); - result = frameGraph.add(new ResultPass()); + opaque = frameGraph.add(new OutputBucketPass(Bucket.Opaque)); + sky = frameGraph.add(new OutputBucketPass(Bucket.Sky, DepthRange.REAR)); + transparent = frameGraph.add(new OutputBucketPass(Bucket.Transparent)); + gui = frameGraph.add(new OutputBucketPass(Bucket.Gui, DepthRange.FRONT)); + translucent = frameGraph.add(new OutputBucketPass(Bucket.Translucent)); } @Override public void preparePasses(FGRenderContext context) { - System.out.println(" prepare opaque"); opaque.prepareRender(context); - - System.out.println(" prepare sky"); - sky.setInput(opaque); sky.prepareRender(context); - - System.out.println(" prepare transparent"); - transparent.setInput(sky); transparent.prepareRender(context); - - System.out.println(" prepare gui"); - gui.setInput(transparent); gui.prepareRender(context); - - System.out.println(" prepare translucent"); - translucent.setInput(gui); translucent.prepareRender(context); - System.out.println(" prepare result"); - BucketPass out = sky; - result.setInColor(out.getOutColor()); - result.setInDepth(out.getOutDepth()); - result.prepareRender(context); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferDef.java new file mode 100644 index 0000000000..53c3a41f5e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferDef.java @@ -0,0 +1,57 @@ +/* + * 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 FrameBufferDef extends ResourceDef { + + private int width, height, samples; + + public FrameBufferDef(int width, int height, int samples) { + super(FrameBuffer.class); + this.width = width; + this.height = height; + this.samples = samples; + } + + @Override + public FrameBuffer create() { + return new FrameBuffer(width, height, samples); + } + @Override + public boolean applyRecycled(FrameBuffer r) { + return r.getWidth() == width && r.getHeight() == height && r.getSamples() == samples; + } + @Override + public void destroy(FrameBuffer r) { + r.dispose(); + } + + public void setWidth(int width) { + this.width = width; + } + public void setHeight(int height) { + this.height = height; + } + public void setSamples(int samples) { + this.samples = samples; + } + + public int getWidth() { + return width; + } + public int getHeight() { + return height; + } + public int getSamples() { + return samples; + } + +} 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 6cfd1eb956..d157c53e62 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 @@ -24,8 +24,8 @@ public class FrameGraph { public FrameGraph(AssetManager assetManager, RenderManager renderManager) { this.assetManager = assetManager; - this.resources = new ResourceList(renderManager.getResourceRecycler()); - this.context = new FGRenderContext(this.assetManager, renderManager); + this.resources = new ResourceList(renderManager.getRecycler()); + this.context = new FGRenderContext(this, renderManager); } public void execute() { @@ -89,7 +89,7 @@ public ResourceList getResources() { return resources; } public ResourceRecycler getRecycler() { - return context.getRenderManager().getResourceRecycler(); + return context.getRenderManager().getRecycler(); } public FGRenderContext getContext() { return context; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java new file mode 100644 index 0000000000..4aebbf4168 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java @@ -0,0 +1,67 @@ +/* + * 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.asset.AssetManager; +import com.jme3.light.LightList; +import com.jme3.material.Material; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.VertexBuffer; +import com.jme3.texture.Texture2D; +import com.jme3.util.BufferUtils; + +/** + * + * @author codex + */ +public class FullScreenQuad { + + private final Geometry geometry; + private final Material transferMat; + + public FullScreenQuad(AssetManager assetManager) { + Mesh mesh = new Mesh(); + mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer( + 0, 0, 0, + 1, 0, 0, + 0, 1, 0, + 1, 1, 0 + )); + mesh.setBuffer(VertexBuffer.Type.Index, 3, BufferUtils.createIntBuffer( + 0, 1, 2, + 1, 3, 2 + )); + mesh.updateBound(); + mesh.updateCounts(); + mesh.setStatic(); + geometry = new Geometry("Screen", mesh); + transferMat = new Material(assetManager, "Common/MatDefs/ShadingCommon/TextureTransfer.j3md"); + } + + public void render(RenderManager rm, Material material) { + geometry.setMaterial(material); + geometry.updateGeometricState(); + rm.renderGeometry(geometry); + } + public void render(RenderManager rm, Material material, LightList lights) { + geometry.setMaterial(material); + geometry.updateGeometricState(); + rm.renderGeometry(geometry, lights); + } + public void render(RenderManager rm, Texture2D color, Texture2D depth) { + boolean writeDepth = depth != null; + if (color != null || writeDepth) { + transferMat.setTexture("ColorMap", color); + transferMat.setTexture("DepthMap", depth); + transferMat.getAdditionalRenderState().setDepthTest(writeDepth); + transferMat.getAdditionalRenderState().setDepthWrite(writeDepth); + render(rm, transferMat); + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java index e4bc65f021..8b875ed88e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java @@ -94,8 +94,23 @@ public boolean renderGeometry(RenderManager rm, Geometry geom) { return false; } - public void setDepth(ResourceTicket depth) { - this.depth = depth.copyIndexTo(this.depth); + public ResourceTicket getDepth() { + return depth; + } + public ResourceTicket getDiffuse() { + return diffuse; + } + public ResourceTicket getSpecular() { + return specular; + } + public ResourceTicket getEmissive() { + return emissive; + } + public ResourceTicket getNormal() { + return normal; + } + public ResourceTicket getLights() { + return lights; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputBucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputBucketPass.java new file mode 100644 index 0000000000..076ab00d8a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputBucketPass.java @@ -0,0 +1,51 @@ +/* + * 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.queue.RenderQueue.Bucket; + +/** + * + * @author codex + */ +public class OutputBucketPass extends RenderPass { + + private Bucket bucket; + private DepthRange depth; + + public OutputBucketPass(Bucket bucket) { + this(bucket, DepthRange.IDENTITY); + } + public OutputBucketPass(Bucket bucket, DepthRange depth) { + this.bucket = bucket; + this.depth = depth; + } + + + @Override + protected void initialize(FrameGraph frameGraph) {} + @Override + protected void prepare(FGRenderContext context) {} + @Override + protected void execute(FGRenderContext context) { + if (bucket == Bucket.Gui) { + context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); + } + context.getRenderer().setDepthRange(depth); + context.renderViewPortQueue(bucket, true); + if (bucket == Bucket.Gui) { + context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); + } + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + public boolean isReferenced() { + return true; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResultPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputPass.java similarity index 50% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/ResultPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputPass.java index ad7c1b508a..c1fa204497 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResultPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputPass.java @@ -4,40 +4,45 @@ */ package com.jme3.renderer.framegraph; -import com.jme3.material.RenderState; +import com.jme3.math.ColorRGBA; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; import com.jme3.texture.Texture2D; /** * * @author codex */ -public class ResultPass extends RenderPass { +public class OutputPass extends RenderPass { private ResourceTicket inColor, inDepth; - private Texture2D forcedTex; + private Texture2D fTex; @Override - public void initialize(FrameGraph frameGraph) { - forcedTex = (Texture2D)frameGraph.getAssetManager().loadTexture("Common/Textures/MissingTexture.png"); + protected void initialize(FrameGraph frameGraph) { + fTex = (Texture2D)frameGraph.getAssetManager().loadTexture("Common/Textures/MissingTexture.png"); } @Override - public void prepare(FGRenderContext context) { + protected void prepare(FGRenderContext context) { referenceOptional(inColor, inDepth); } @Override - public void execute(FGRenderContext context) { - Texture2D color = resources.acquire(inColor, null); - Texture2D depth = resources.acquire(inDepth, null); - context.transferTextures(color, depth, RenderState.BlendMode.Alpha); + protected void execute(FGRenderContext context) { + context.transferTextures(resources.acquire(inColor, null), resources.acquire(inDepth, null)); } @Override - public void reset(FGRenderContext context) {} + protected void reset(FGRenderContext context) {} @Override - public void cleanup(FrameGraph frameGraph) {} + protected void cleanup(FrameGraph frameGraph) {} + @Override + protected FrameBuffer createFrameBuffer(FGRenderContext context) { + return new FrameBuffer(context.getWidth(), context.getHeight(), 1); + } @Override public boolean isReferenced() { return true; } + public void setInColor(ResourceTicket inColor) { this.inColor = inColor; @@ -46,9 +51,4 @@ public void setInDepth(ResourceTicket inDepth) { this.inDepth = inDepth; } - @Override - public String toString() { - return "ResultPass[]"; - } - } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PostProcessingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PostProcessingPass.java new file mode 100644 index 0000000000..cfcd1e5a88 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PostProcessingPass.java @@ -0,0 +1,51 @@ +/* + * 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.post.SceneProcessor; +import com.jme3.profile.AppProfiler; +import com.jme3.profile.SpStep; +import com.jme3.profile.VpStep; +import com.jme3.util.SafeArrayList; + +/** + * + * @author codex + */ +public class PostProcessingPass extends RenderPass { + + @Override + protected void initialize(FrameGraph frameGraph) {} + @Override + protected void prepare(FGRenderContext context) {} + @Override + protected void execute(FGRenderContext context) { + SafeArrayList processors = context.getViewPort().getProcessors(); + if (!processors.isEmpty()) { + AppProfiler prof = context.getProfiler(); + if (prof != null) { + prof.vpStep(VpStep.PostFrame, context.getViewPort(), null); + } + for (SceneProcessor proc : processors.getArray()) { + if (prof != null) { + prof.spStep(SpStep.ProcPostFrame, proc.getClass().getSimpleName()); + } + proc.postFrame(context.getViewPort().getOutputFrameBuffer()); + } + if (prof != null) { + prof.vpStep(VpStep.ProcEndRender, context.getViewPort(), null); + } + } + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + public boolean isReferenced() { + return true; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java index 5d7b68c7f7..fa8384dede 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java @@ -19,7 +19,6 @@ public abstract class RenderPass implements ResourceProducer { private final LinkedList outputs = new LinkedList<>(); private final CameraSize camSize = new CameraSize(); private int refs = 0; - protected FrameBuffer frameBuffer; public void initializePass(FrameGraph frameGraph) { this.resources = frameGraph.getResources(); @@ -29,12 +28,6 @@ public void prepareRender(FGRenderContext context) { prepare(context); } public void executeRender(FGRenderContext context) { - if (camSize.update(context.getCameraSize()) || frameBuffer == null) { - if (frameBuffer != null) { - destroyFrameBuffer(context, frameBuffer); - } - frameBuffer = createFrameBuffer(context); - } execute(context); context.popRenderSettings(); releaseAll(); @@ -54,14 +47,6 @@ public void cleanupPass(FrameGraph frameGraph) { protected abstract void reset(FGRenderContext context); protected abstract void cleanup(FrameGraph frameGraph); - protected FrameBuffer createFrameBuffer(FGRenderContext context) { - return null; - } - protected void destroyFrameBuffer(FGRenderContext context, FrameBuffer fbo) { - fbo.dispose(); - //fbo.deleteObject(context.getRenderer()); - } - protected ResourceTicket register(ResourceDef def, ResourceTicket ticket) { ticket = resources.register(this, def, ticket); addOutput(ticket); @@ -87,12 +72,12 @@ protected void referenceOptional(ResourceTicket... tickets) { referenceOptional(t); } } - private void releaseAll() { + protected void releaseAll() { for (ResourceTicket t : inputs) { - resources.release(t); + resources.releaseOptional(t); } for (ResourceTicket t : outputs) { - resources.release(t); + resources.releaseOptional(t); } } @@ -129,5 +114,9 @@ public LinkedList getInputTickets() { public LinkedList getOutputTickets() { return outputs; } + @Override + public String toString() { + return getClass().getSimpleName(); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index d9ae99ca86..79e3891d70 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -17,6 +17,7 @@ public class RenderResource { private T resource; private int refs = 0; private int timeout = 0; + private boolean virtual = true; private boolean watched = false; public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { @@ -26,7 +27,7 @@ public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTic } public void create() { - resource = def.create(); + setResource(def.create()); } public void reference() { @@ -44,6 +45,7 @@ public void setTimeout(int timeout) { } public void setResource(T resource) { this.resource = resource; + virtual = false; } public void setWatched(boolean watched) { this.watched = watched; @@ -69,7 +71,7 @@ public int getNumReferences() { } public boolean isVirtual() { - return resource == null; + return virtual; } public boolean isReferenced() { return refs > 0; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index db3afa4a94..5ed0c33cf0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -77,20 +77,17 @@ public ResourceTicket register(ResourceProducer producer, ResourceDef ResourceTicket t = new ResourceTicket<>(); t.setIndex(add(new RenderResource<>(producer, def, t))); store = t.copyIndexTo(store); - System.out.println(" "+producer+": register "+t); return store; } public void reference(ResourceTicket ticket) { locate(ticket).reference(); - System.out.println(" "+locate(ticket).getProducer()+": reference "+ticket); } public boolean referenceOptional(ResourceTicket ticket) { if (ticket != null) { reference(ticket); return true; } - System.out.println(" optional reference failed"); return false; } public void reference(ResourceTicket... tickets) { @@ -111,28 +108,28 @@ public > R getDef(Class type, ResourceTicket t } return null; } + public void setDirect(ResourceTicket ticket, T resource) { + locate(ticket).setResource(resource); + } public T acquire(ResourceTicket ticket) { RenderResource res = locate(ticket); if (!res.isUsed()) { throw new IllegalStateException(res+" was unexpectedly acquired."); } - System.out.println(" acquire resource from "+ticket); - if (!res.isVirtual()) { - System.out.println(" resource already created"); - } if (res.isVirtual() && !recycler.recycle(res)) { - System.out.println(" create from scratch for "+res); res.create(); } return res.getResource(); } public T acquire(ResourceTicket ticket, T value) { if (ticket != null) { - return acquire(ticket); - } else { - return value; + T r = acquire(ticket); + if (r != null) { + return r; + } } + return value; } public void acquireColorTargets(FrameBuffer fbo, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { @@ -141,18 +138,26 @@ public void acquireColorTargets(FrameBuffer fbo, ResourceTicket(size); nextSlot = 0; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java index ca0e159e22..347e133539 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java @@ -16,17 +16,26 @@ public class ResourceRecycler { private final LinkedList resources = new LinkedList<>(); private int timeout = 1; - public void add(RenderResource res) { - if (res.isVirtual()) { - throw new IllegalArgumentException("Resource cannot be virtual."); + public void add(RenderResource resource) { + if (resource.isVirtual() && resource.getResource() != null) { + throw new IllegalArgumentException("Resource cannot be virtual or null."); } - if (res.getDefinition().getRecycleTimeout() >= 0) { - res.setTimeout(res.getDefinition().getRecycleTimeout()); + if (resource.getDefinition().getRecycleTimeout() >= 0) { + resource.setTimeout(resource.getDefinition().getRecycleTimeout()); } else { - res.setTimeout(timeout); + resource.setTimeout(timeout); } //res.getDefinition().destroy(res.getResource()); - resources.add(res); + resources.add(resource); + } + public void add(Object resource) { + if (resource == null) { + throw new NullPointerException("Resource cannot be null."); + } + RenderResource r = new RenderResource(null, null, null); + r.setResource(resource); + r.setTimeout(timeout); + resources.add(r); } public boolean recycle(RenderResource resource) { @@ -34,13 +43,11 @@ public boolean recycle(RenderResource resource) { if (!def.isAcceptsRecycled()) { return false; } - System.out.println(" try "+resources.size()+" available resources to recycle"); for (Iterator it = resources.iterator(); it.hasNext();) { RenderResource res = it.next(); if (def.isOfResourceType(res.getResource().getClass())) { T r = (T)res.getResource(); if (def.applyRecycled(r)) { - System.out.println(" recycle for "+resource); resource.setResource(r); it.remove(); return true; @@ -49,7 +56,6 @@ public boolean recycle(RenderResource resource) { } return false; } - public void flush() { // Note: flushing resources on the same frame they were created causes the // screen to render black. Guess: destroying output texture early causes @@ -63,7 +69,6 @@ public void flush() { it.remove(); } } - System.out.println("resources flushed: "+n); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java index b01d08b010..01945fd6b9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java @@ -13,13 +13,13 @@ public class TestConstructor implements GraphConstructor { private BucketPass opaque, sky; - private ResultPass result; + private OutputPass result; @Override public void addPasses(FrameGraph frameGraph) { opaque = frameGraph.add(new BucketPass(Bucket.Opaque)); sky = frameGraph.add(new BucketPass(Bucket.Sky, DepthRange.REAR)); - result = frameGraph.add(new ResultPass()); + result = frameGraph.add(new OutputPass()); } @Override public void preparePasses(FGRenderContext context) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TileDeferredPass.java new file mode 100644 index 0000000000..348b4cf96c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TileDeferredPass.java @@ -0,0 +1,99 @@ +/* + * 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.light.LightList; +import com.jme3.material.Material; +import com.jme3.material.TechniqueDef; +import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic; +import com.jme3.material.logic.TiledRenderGrid; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture2D; + +/** + * + * @author codex + */ +public class TileDeferredPass extends RenderPass { + + private ResourceTicket diffuse, specular, emissive, normal, depth, outColor; + private ResourceTicket lights; + private ResourceTicket tiles; + private ResourceTicket frameBuffer; + private Material material; + private final TiledRenderGrid tileInfo = new TiledRenderGrid(); + + @Override + protected void initialize(FrameGraph frameGraph) { + material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"); + for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("TileBasedDeferredPass")) { + t.setLogic(new TileBasedDeferredSinglePassLightingLogic(t, tileInfo)); + } + } + @Override + protected void prepare(FGRenderContext context) { + outColor = register(new TextureDef2D(context.getWidth(), context.getHeight(), Image.Format.RGBA8), outColor); + reference(diffuse, specular, emissive, normal, depth); + referenceOptional(lights, tiles); + } + @Override + protected void execute(FGRenderContext context) { + FrameBuffer fb = resources.acquire(frameBuffer); + fb.clearColorTargets(); + fb.setDepthTarget((FrameBuffer.FrameBufferTextureTarget)null); + resources.acquireColorTargets(fb, outColor); + context.setFrameBuffer(fb, true, true, true); + TiledRenderGrid trg = resources.acquire(tiles, null); + if (trg != null) { + tileInfo.copyFrom(trg); + } + tileInfo.update(context.getViewPort().getCamera()); + material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); + material.setTexture("Context_InGBuff1", resources.acquire(specular)); + material.setTexture("Context_InGBuff2", resources.acquire(emissive)); + material.setTexture("Context_InGBuff3", resources.acquire(normal)); + material.setTexture("Context_InGBuff4", resources.acquire(depth)); + material.selectTechnique("TileBasedDeferredPass", context.getRenderManager()); + LightList lightList = resources.acquire(lights, null); + if (lightList != null) { + context.getScreen().render(context.getRenderManager(), material, lightList); + } else { + context.renderFullscreen(material); + } + fb.clearColorTargets(); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + + public void setDiffuse(ResourceTicket diffuse) { + this.diffuse = diffuse; + } + public void setSpecular(ResourceTicket specular) { + this.specular = specular; + } + public void setEmissive(ResourceTicket emissive) { + this.emissive = emissive; + } + public void setNormal(ResourceTicket normal) { + this.normal = normal; + } + public void setDepth(ResourceTicket depth) { + this.depth = depth; + } + public void setLights(ResourceTicket lights) { + this.lights = lights; + } + public void setTiles(ResourceTicket tiles) { + this.tiles = tiles; + } + + public ResourceTicket getOutColor() { + return outColor; + } + +} 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 967ef1bd32..8aaa53dcac 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -42,12 +42,14 @@ void main(){ // unpack GBuffer vec4 shadingInfo = texture2D(Context_InGBuff2, innerTexCoord); int shadingModelId = int(floor(shadingInfo.a)); + float depth = texture2D(GBUFFER_DEPTH, texCoord).r; + gl_FragDepth = depth; // 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); + vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord); vec4 diffuseColor = texture2D(Context_InGBuff0, innerTexCoord); vec3 specularColor = floor(buff1.rgb) * 0.01f; @@ -128,7 +130,7 @@ void main(){ } else if(shadingModelId == STANDARD_LIGHTING){ // todo: - vec3 vPos = getPosition(innerTexCoord, viewProjectionMatrixInverse); + vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff0 = texture2D(Context_InGBuff0, innerTexCoord); vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord); vec3 emissive = shadingInfo.rgb; diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert index 0115cf495e..5e23007ec2 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert @@ -4,7 +4,7 @@ attribute vec3 inPosition; -#ifdef USE_LIGHTS_CULL_MODE +#ifndef USE_LIGHTS_CULL_MODE varying vec2 texCoord; #endif varying mat4 viewProjectionMatrixInverse; diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag index e44f5bbaff..3a2a451ec0 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag @@ -1,8 +1,12 @@ #import "Common/ShaderLib/GLSLCompat.glsllib" -#ifdef WRITE_COLOR +#ifdef WRITE_COLOR_MAP uniform sampler2D m_ColorMap; +#else + #ifdef WRITE_COLOR + uniform vec4 m_Color; + #endif #endif #ifdef WRITE_DEPTH uniform sampler2D m_DepthMap; @@ -15,10 +19,14 @@ varying vec2 texCoord; void main() { - #ifdef WRITE_COLOR + #ifdef WRITE_COLOR_MAP gl_FragColor = texture2D(m_ColorMap, texCoord); #else - gl_FragColor = vec4(0.0); + #ifdef WRITE_COLOR + gl_FragColor = m_Color; + #else + gl_FragColor = vec4(0.0); + #endif #endif #ifdef WRITE_DEPTH diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md index 2a70289dc2..d01aa1ca40 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md @@ -3,6 +3,7 @@ MaterialDef TextureTransfer { MaterialParameters { Texture2D ColorMap Texture2D DepthMap + Color Color Float Alpha } @@ -22,7 +23,8 @@ MaterialDef TextureTransfer { } Defines { - WRITE_COLOR : ColorMap + WRITE_COLOR_MAP : ColorMap + WRITE_COLOR : Color WRITE_DEPTH : DepthMap WRITE_ALPHA : 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 d316ed90e2..8aaaefe847 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag @@ -51,12 +51,14 @@ void main(){ // unpack GBuffer vec4 shadingInfo = texture2D(Context_InGBuff2, innerTexCoord); int shadingModelId = int(floor(shadingInfo.a)); + float depth = texture2D(GBUFFER_DEPTH, texCoord).r; + gl_FragDepth = depth; // 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); + vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord); vec4 diffuseColor = texture2D(Context_InGBuff0, innerTexCoord); vec3 specularColor = floor(buff1.rgb) * 0.01f; @@ -231,7 +233,7 @@ void main(){ } else if(shadingModelId == STANDARD_LIGHTING){ // todo: - vec3 vPos = getPosition(innerTexCoord, viewProjectionMatrixInverse); + vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff0 = texture2D(Context_InGBuff0, innerTexCoord); vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord); vec3 emissive = shadingInfo.rgb; 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 84abdc4aee..ba76966374 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md @@ -23,11 +23,10 @@ MaterialDef DeferredShading { 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 diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib index bc8c4cfa06..468f090896 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib @@ -44,22 +44,15 @@ vec3 decodeNormal(in vec4 enc){ } 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; + vec4 pos = vec4(1.0); + 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 + return getPosition(texCoord, texture2D(GBUFFER_DEPTH, texCoord).r, matrixInverse); +} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java index dcfc1a08b1..393ba498a3 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java @@ -41,8 +41,8 @@ import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.RenderPipelineFactory; +import com.jme3.renderer.framegraph.DeferredGraphConstructor; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; @@ -67,7 +67,10 @@ public static void main(String[] args) { @Override public void simpleInitApp() { - renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); + FrameGraph graph = new FrameGraph(assetManager, renderManager); + graph.setConstructor(new DeferredGraphConstructor()); + viewPort.setFrameGraph(graph); + //renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); // 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); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index 13f176edc9..b064fb19e2 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -13,9 +13,9 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.DeferredGraphConstructor; import com.jme3.renderer.framegraph.ForwardGraphConstructor; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.TestConstructor; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; @@ -58,7 +58,8 @@ public void simpleInitApp() { //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); FrameGraph graph = new FrameGraph(assetManager, renderManager); - graph.setConstructor(new ForwardGraphConstructor()); + graph.setConstructor(new DeferredGraphConstructor()); + //graph.setConstructor(new ForwardGraphConstructor()); //graph.setConstructor(new TestConstructor()); //MyFrameGraph graph = RenderPipelineFactory.createBackroundScreenTest(assetManager, renderManager); viewPort.setFrameGraph(graph); @@ -166,7 +167,7 @@ public void simpleRender(RenderManager rm) { if (frame == 2) { - //rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); + rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); } if (frame > 10 && modelNode.getParent() == null) { From 60841545541d743844743fd8e9d87078685289f5 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 7 May 2024 10:58:19 -0400 Subject: [PATCH 051/111] draft ready --- .../java/com/jme3/renderer/RenderManager.java | 20 +- .../framegraph/DeferredGraphConstructor.java | 9 +- .../renderer/framegraph/FGRenderContext.java | 19 +- .../framegraph/ForwardGraphConstructor.java | 1 + .../renderer/framegraph/FrameBufferDef.java | 57 ------ .../renderer/framegraph/FrameBufferParam.java | 41 ---- .../jme3/renderer/framegraph/FrameGraph.java | 20 +- .../renderer/framegraph/RenderObject.java | 101 ++++++++++ .../renderer/framegraph/RenderObjectMap.java | 84 ++++++++ .../framegraph/RenderPipelineFactory.java | 86 --------- .../framegraph/RenderQueueModule.java | 52 ----- .../renderer/framegraph/RenderResource.java | 42 ++-- .../jme3/renderer/framegraph/ResourceDef.java | 42 ---- .../renderer/framegraph/ResourceList.java | 181 ++++++++---------- .../renderer/framegraph/ResourceProducer.java | 2 + .../renderer/framegraph/ResourceRecycler.java | 74 ------- .../renderer/framegraph/ResourceTicket.java | 9 + .../renderer/framegraph/TestConstructor.java | 2 + .../jme3/renderer/framegraph/TimeFrame.java | 56 ++++++ .../jme3/renderer/framegraph/ValueDef.java | 49 ----- .../framegraph/definitions/ResourceDef.java | 24 +++ .../{ => definitions}/TextureDef2D.java | 27 +-- .../framegraph/definitions/ValueDef.java | 57 ++++++ .../framegraph/pass/AbstractModule.java | 59 ------ .../pass/BackgroundScreenTestModule.java | 61 ------ .../pass/DeferredShadingModule.java | 124 ------------ .../renderer/framegraph/pass/FGModule.java | 70 ------- .../framegraph/pass/ForwardModule.java | 58 ------ .../framegraph/pass/GBufferModule.java | 166 ---------------- .../framegraph/pass/PostProcessingModule.java | 91 --------- .../framegraph/pass/ScreenModule.java | 35 ---- .../pass/TileDeferredShadingModule.java | 132 ------------- .../framegraph/{ => passes}/BucketPass.java | 22 +-- .../framegraph/{ => passes}/DeferredPass.java | 30 +-- .../framegraph/{ => passes}/GBufferPass.java | 29 +-- .../{ => passes}/OutputBucketPass.java | 6 +- .../framegraph/{ => passes}/OutputPass.java | 8 +- .../{ => passes}/PostProcessingPass.java | 5 +- .../framegraph/{ => passes}/RenderPass.java | 49 ++++- .../{ => passes}/TileDeferredPass.java | 25 ++- .../java/com/jme3/texture/FrameBuffer.java | 22 ++- .../jme3test/renderpath/TestShadingModel.java | 22 --- 42 files changed, 636 insertions(+), 1433 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferDef.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferParam.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueDef.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => definitions}/TextureDef2D.java (74%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ScreenModule.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => passes}/BucketPass.java (81%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => passes}/DeferredPass.java (76%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => passes}/GBufferPass.java (83%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => passes}/OutputBucketPass.java (86%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => passes}/OutputPass.java (80%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => passes}/PostProcessingPass.java (89%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => passes}/RenderPass.java (69%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => passes}/TileDeferredPass.java (81%) 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 8a29212e3e..8d411b3e12 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -47,7 +47,7 @@ import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.ResourceRecycler; +import com.jme3.renderer.framegraph.RenderObjectMap; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; @@ -110,7 +110,7 @@ public String getInfo(){ private final ArrayList preViewPorts = new ArrayList<>(); private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); - private final ResourceRecycler recycler = new ResourceRecycler(); + private final RenderObjectMap renderObjects = new RenderObjectMap(); private FrameGraph frameGraph; private Camera prevCam = null; private Material forcedMaterial = null; @@ -152,8 +152,8 @@ public void setFrameGraph(FrameGraph frameGraph) { this.frameGraph = frameGraph; } - public ResourceRecycler getRecycler() { - return recycler; + public RenderObjectMap getRenderObjectsMap() { + return renderObjects; } /** @@ -1123,7 +1123,7 @@ public void renderTranslucentQueue(ViewPort vp) { } private void setViewPort(Camera cam) { - // this will make sure to update viewport only if needed + // this will make sure to clearReservations viewport only if needed if (cam != prevCam || cam.isViewportChanged()) { viewX = (int) (cam.getViewPortLeft() * cam.getWidth()); viewY = (int) (cam.getViewPortBottom() * cam.getHeight()); @@ -1345,13 +1345,17 @@ public void renderViewPort(ViewPort vp, float tpf) { } - // clear any remaining spatials that were not rendered. + // clearMap any remaining spatials that were not rendered. clearQueue(vp); if (prof != null) { prof.vpStep(VpStep.EndRender, vp, null); } + if (fg != null) { + renderObjects.clearReservations(); + } + } /** @@ -1406,8 +1410,8 @@ public void render(float tpf, boolean mainFrameBufferActive) { } } - // flush unrecycled resources - recycler.flush(); + // flushMap unrecycled resources + renderObjects.flushMap(); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java index 0d2cdf76a1..d5061a0e6a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java @@ -4,6 +4,11 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.passes.DeferredPass; +import com.jme3.renderer.framegraph.passes.GBufferPass; +import com.jme3.renderer.framegraph.passes.OutputBucketPass; +import com.jme3.renderer.framegraph.passes.OutputPass; +import com.jme3.renderer.framegraph.passes.PostProcessingPass; import com.jme3.renderer.queue.RenderQueue.Bucket; /** @@ -13,7 +18,7 @@ public class DeferredGraphConstructor implements GraphConstructor { private GBufferPass gbuf; - private TileDeferredPass deferred; + private DeferredPass deferred; private OutputPass defOut; private OutputBucketPass sky, transparent, gui, translucent; private PostProcessingPass post; @@ -21,7 +26,7 @@ public class DeferredGraphConstructor implements GraphConstructor { @Override public void addPasses(FrameGraph frameGraph) { gbuf = frameGraph.add(new GBufferPass()); - deferred = frameGraph.add(new TileDeferredPass()); + deferred = frameGraph.add(new DeferredPass()); defOut = frameGraph.add(new OutputPass()); sky = frameGraph.add(new OutputBucketPass(Bucket.Sky, DepthRange.REAR)); transparent = frameGraph.add(new OutputBucketPass(Bucket.Transparent)); 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 c8136a4d56..34499c3075 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 @@ -99,7 +99,7 @@ public void pushRenderSettings() { renderState = renderManager.getForcedRenderState(); } /** - * Applies saved render settings. + * Applies saved render settings, except the framebuffer. */ public void popRenderSettings() { renderManager.setForcedTechnique(forcedTechnique); @@ -113,6 +113,12 @@ public void popRenderSettings() { renderManager.getRenderer().setBackgroundColor(viewPort.getBackgroundColor()); } } + /** + * Applies the saved framebuffer. + */ + public void popFrameBuffer() { + renderManager.getRenderer().setFrameBuffer(frameBuffer); + } public void renderViewPortQueue(RenderQueue.Bucket bucket, boolean clear) { viewPort.getQueue().renderQueue(bucket, renderManager, viewPort.getCamera(), clear); @@ -124,17 +130,6 @@ public void transferTextures(Texture2D color, Texture2D depth) { screen.render(renderManager, color, depth); } - public void setFrameBuffer(FrameBuffer fbo) { - renderManager.getRenderer().setFrameBuffer(fbo); - } - public void setFrameBuffer(FrameBuffer fbo, boolean clearColor, boolean clearDepth, boolean clearStencil) { - setFrameBuffer(fbo); - renderManager.getRenderer().clearBuffers(clearColor, clearDepth, clearStencil); - } - public FrameBuffer.FrameBufferTextureTarget createTextureTarget(Texture tex) { - return FrameBuffer.FrameBufferTarget.newTarget(tex); - } - public RenderManager getRenderManager() { return renderManager; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java index 132a2e6c9d..d5609aae89 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.passes.OutputBucketPass; import com.jme3.renderer.queue.RenderQueue.Bucket; /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferDef.java deleted file mode 100644 index 53c3a41f5e..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferDef.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 FrameBufferDef extends ResourceDef { - - private int width, height, samples; - - public FrameBufferDef(int width, int height, int samples) { - super(FrameBuffer.class); - this.width = width; - this.height = height; - this.samples = samples; - } - - @Override - public FrameBuffer create() { - return new FrameBuffer(width, height, samples); - } - @Override - public boolean applyRecycled(FrameBuffer r) { - return r.getWidth() == width && r.getHeight() == height && r.getSamples() == samples; - } - @Override - public void destroy(FrameBuffer r) { - r.dispose(); - } - - public void setWidth(int width) { - this.width = width; - } - public void setHeight(int height) { - this.height = height; - } - public void setSamples(int samples) { - this.samples = samples; - } - - public int getWidth() { - return width; - } - public int getHeight() { - return height; - } - public int getSamples() { - return samples; - } - -} 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 deleted file mode 100644 index c5aed76253..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferParam.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.framegraph.parameters.ValueRenderParam; -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 d157c53e62..cc075ce976 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 @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.passes.RenderPass; import com.jme3.asset.AssetManager; import com.jme3.renderer.RenderManager; import java.util.LinkedList; @@ -15,6 +16,9 @@ */ public class FrameGraph { + private static int nextId = 0; + + private final int id; private final AssetManager assetManager; private final ResourceList resources; private final FGRenderContext context; @@ -23,13 +27,13 @@ public class FrameGraph { private boolean debug = false; public FrameGraph(AssetManager assetManager, RenderManager renderManager) { + this.id = nextId++; this.assetManager = assetManager; - this.resources = new ResourceList(renderManager.getRecycler()); + this.resources = new ResourceList(renderManager.getRenderObjectsMap()); this.context = new FGRenderContext(this, renderManager); } public void execute() { - System.out.println("render viewport: "+context.getViewPort().getName()); // prepare passes if (constructor != null) { constructor.preparePasses(context); @@ -45,10 +49,11 @@ public void execute() { context.pushRenderSettings(); for (RenderPass p : passes) { if (p.isReferenced()) { - System.out.println(" execute pass: "+p); p.executeRender(context); + context.popRenderSettings(); } } + context.popFrameBuffer(); // reset passes for (RenderPass p : passes) { p.resetRender(context); @@ -66,7 +71,7 @@ public void setConstructor(GraphConstructor constructor) { } public T add(T pass) { passes.addLast(pass); - pass.initializePass(this); + pass.initializePass(this, passes.size()-1); return pass; } public T get(Class type) { @@ -82,14 +87,17 @@ public void setDebug(boolean debug) { this.debug = debug; } + public int getId() { + return id; + } public AssetManager getAssetManager() { return assetManager; } public ResourceList getResources() { return resources; } - public ResourceRecycler getRecycler() { - return context.getRenderManager().getRecycler(); + public RenderObjectMap getRecycler() { + return context.getRenderManager().getRenderObjectsMap(); } public FGRenderContext getContext() { return context; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java new file mode 100644 index 0000000000..ca450a7137 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java @@ -0,0 +1,101 @@ +/* + * 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.util.NativeObject; +import java.util.BitSet; +import java.util.function.Consumer; + +/** + * + * @author codex + * @param + */ +public class RenderObject { + + private static final Consumer DEFAULT = object -> {}; + private static final Consumer NATIVE = object -> object.dispose(); + + private static int nextId = 0; + + private final int id; + private final T object; + private final int timeoutDuration; + private int timeout = 0; + private boolean acquired = false; + private final BitSet reservations = new BitSet(); + private final Consumer disposer; + + public RenderObject(T object, int timeout, Consumer disposer) { + this.id = nextId++; + this.object = object; + this.timeoutDuration = timeout; + if (disposer != null) { + this.disposer = disposer; + } else if (object instanceof NativeObject) { + this.disposer = NATIVE; + } else { + this.disposer = DEFAULT; + } + } + + public boolean acquire(TimeFrame time, boolean reserved) { + if (acquired || (!reserved && isReservedWithin(time))) { + return false; + } + acquire(); + return true; + } + public void acquire() { + timeout = timeoutDuration; + acquired = true; + } + public void release() { + if (!acquired) { + throw new IllegalStateException("Already released."); + } + acquired = false; + } + public void reserve(int index) { + reservations.set(index); + } + public void dispose() { + disposer.accept(object); + } + + public void clearReservations() { + reservations.clear(); + } + public boolean tickTimeout() { + return timeout-- > 0; + } + + public int getId() { + return id; + } + public T getObject() { + return object; + } + public boolean isAcquired() { + return acquired; + } + public boolean isReservedWithin(TimeFrame frame) { + if (frame.getStartIndex() >= reservations.size()) { + return false; + } + int n = Math.min(reservations.size()-1, frame.getEndIndex()); + for (int i = frame.getStartIndex(); i <= n; i++) { + if (reservations.get(i)) { + return true; + } + } + return false; + } + + public static int getNextId() { + return nextId; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java new file mode 100644 index 0000000000..465459b91c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -0,0 +1,84 @@ +/* + * 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.framegraph.definitions.ResourceDef; +import java.util.HashMap; +import java.util.Iterator; + +/** + * + * @author codex + */ +public class RenderObjectMap { + + private final HashMap objectMap = new HashMap<>(); + private final int timeout = 1; + + protected RenderObject create(ResourceDef def) { + RenderObject obj = new RenderObject(def.createResource(), timeout, def.getDisposalMethod()); + objectMap.put(obj.getId(), obj); + return obj; + } + protected boolean applyToResource(RenderResource resource, RenderObject object) { + T r = resource.getDefinition().applyResource(object.getObject()); + if (r != null) { + object.acquire(); + resource.setObject(object); + return true; + } + return false; + } + + public void allocate(RenderResource resource) { + ResourceDef def = resource.getDefinition(); + int id = resource.getTicket().getObjectId(); + if (id >= 0) { + RenderObject reserved = objectMap.get(id); + if (reserved != null && !reserved.isAcquired() && applyToResource(resource, reserved)) { + return; + } + } + for (RenderObject obj : objectMap.values()) { + if (!obj.isAcquired() && !obj.isReservedWithin(resource.getLifeTime()) + && applyToResource(resource, obj)) { + return; + } + } + RenderObject obj = create(def); + obj.acquire(); + resource.setObject(obj); + } + public boolean reserve(int objectId, int index) { + RenderObject obj = objectMap.get(objectId); + if (obj != null) { + obj.reserve(index); + return true; + } + return false; + } + + public void clearReservations() { + for (RenderObject obj : objectMap.values()) { + obj.clearReservations(); + } + } + public void flushMap() { + for (Iterator it = objectMap.values().iterator(); it.hasNext();) { + RenderObject obj = it.next(); + if (!obj.tickTimeout()) { + obj.dispose(); + it.remove(); + } + } + } + public void clearMap() { + for (RenderObject obj : objectMap.values()) { + obj.dispose(); + } + objectMap.clear(); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java deleted file mode 100644 index e48681e83e..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPipelineFactory.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.app.Application; -import com.jme3.asset.AssetManager; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.RenderManager.RenderPath; -import com.jme3.renderer.framegraph.pass.BackgroundScreenTestModule; -import com.jme3.renderer.framegraph.pass.DeferredShadingModule; -import com.jme3.renderer.framegraph.pass.ForwardModule; -import com.jme3.renderer.framegraph.pass.GBufferModule; -import com.jme3.renderer.pass.GuiModule; -import com.jme3.renderer.framegraph.pass.PostProcessingModule; -import com.jme3.renderer.framegraph.pass.TileDeferredShadingModule; - -/** - * Constructs basic framegraphs. - * - * @author codex - */ -public class RenderPipelineFactory { - - public static FrameGraph create(Application app, RenderPath path) { - RenderManager rm = app.getRenderManager(); - switch (path) { - case Forward: return createForwardPipeline(rm); - case ForwardPlus: return createForwardPlusPipeline(rm); - case Deferred: return createDeferredPipeline(app.getAssetManager(), rm); - case TiledDeferred: return createTileDeferredPipeline(app.getAssetManager(), rm); - default: return null; - } - } - - private static FrameGraph addBasicPasses(FrameGraph g) { - g.add(ForwardModule.opaque()); - g.add(ForwardModule.sky()); - g.add(ForwardModule.transparent()); - g.add(new GuiModule()); - g.add(new PostProcessingModule()); - g.add(ForwardModule.translucent()); - return g; - } - - public static FrameGraph createForwardPipeline(RenderManager rm) { - return addBasicPasses(new FrameGraph(rm)); - } - - public static FrameGraph createForwardPlusPipeline(RenderManager rm) { - throw new UnsupportedOperationException("ForwardPlus render pipeline is currently unsupported."); - } - - public static FrameGraph createDeferredPipeline(AssetManager am, RenderManager rm) { - FrameGraph g = new FrameGraph(rm); - g.add(new GBufferModule()); - //g.add(new DeferredShadingModule(am)); - g.add(ForwardModule.sky()); - g.add(ForwardModule.transparent()); - g.add(new GuiModule()); - g.add(new PostProcessingModule()); - g.add(ForwardModule.translucent()); - return g; - } - - public static FrameGraph createTileDeferredPipeline(AssetManager am, RenderManager rm) { - FrameGraph g = new FrameGraph(rm); - g.add(new GBufferModule()); - g.add(new TileDeferredShadingModule(am)); - return addBasicPasses(g); - } - - public static FrameGraph createBackroundScreenTest(AssetManager am, RenderManager rm) { - FrameGraph g = new FrameGraph(rm); - g.add(new BackgroundScreenTestModule(am)); - g.add(ForwardModule.opaque()); - g.add(ForwardModule.sky()); - g.add(ForwardModule.transparent()); - g.add(new GuiModule()); - g.add(new PostProcessingModule()); - g.add(ForwardModule.translucent()); - return g; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java deleted file mode 100644 index caaca217f7..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.framegraph.pass.AbstractModule; -import com.jme3.renderer.ViewPort; -import com.jme3.renderer.queue.GeometryList; -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.renderer.pass.GeometryRenderHandler; - -/** - * - * @author codex - */ -public abstract class RenderQueueModule extends AbstractModule implements GeometryRenderHandler { - - protected ViewPort forcedViewPort; - protected GeometryList drawCommands; - protected boolean canExecute = false; - - public abstract void dispatchPassSetup(RenderQueue queue); - - public abstract void executeDrawCommands(RenderContext context); - - @Override - public void execute(RenderContext context) { - context.getRenderManager().setGeometryRenderHandler(this); - dispatchPassSetup(context.getRenderQueue()); - //if (canExecute) { - executeDrawCommands(context); - //} - context.getRenderManager().setGeometryRenderHandler(null); - } - - @Override - public void reset() { - if (drawCommands != null && drawCommands.size() > 0) { - drawCommands.clear(); - } - } - - public void setForcedViewPort(ViewPort vp) { - this.forcedViewPort = vp; - } - - public ViewPort getForcedViewPort() { - return forcedViewPort; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 79e3891d70..34e043b0c6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -4,6 +4,8 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.definitions.ResourceDef; + /** * * @author codex @@ -14,23 +16,20 @@ public class RenderResource { private final ResourceProducer producer; private final ResourceDef def; private final ResourceTicket ticket; - private T resource; + private final TimeFrame lifetime; + private RenderObject object; private int refs = 0; private int timeout = 0; - private boolean virtual = true; - private boolean watched = false; public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { this.producer = producer; this.def = def; this.ticket = ticket; + this.lifetime = new TimeFrame(this.producer.getIndex(), 0); } - public void create() { - setResource(def.create()); - } - - public void reference() { + public void reference(int index) { + lifetime.extendTo(index); refs++; } public void release() { @@ -43,12 +42,11 @@ public boolean tickTimeout() { public void setTimeout(int timeout) { this.timeout = timeout; } - public void setResource(T resource) { - this.resource = resource; - virtual = false; - } - public void setWatched(boolean watched) { - this.watched = watched; + public void setObject(RenderObject object) { + this.object = object; + if (this.object != null) { + ticket.setObjectId(this.object.getId()); + } } public ResourceProducer getProducer() { @@ -60,8 +58,14 @@ public ResourceDef getDefinition() { public ResourceTicket getTicket() { return ticket; } + public TimeFrame getLifeTime() { + return lifetime; + } + public RenderObject getObject() { + return object; + } public T getResource() { - return resource; + return object.getObject(); } public int getIndex() { return ticket.getIndex(); @@ -71,7 +75,7 @@ public int getNumReferences() { } public boolean isVirtual() { - return virtual; + return object == null; } public boolean isReferenced() { return refs > 0; @@ -79,14 +83,10 @@ public boolean isReferenced() { public boolean isUsed() { return refs >= 0; } - public boolean isWatched() { - return watched; - } @Override public String toString() { - return "RenderResource[index="+ticket.getIndex()+", resource=" - +(resource != null ? resource.getClass().getName() : "null")+"]"; + return "RenderResource[index="+ticket.getIndex()+"]"; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java deleted file mode 100644 index bcf7767e6a..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceDef.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 abstract class ResourceDef { - - private final Class resType; - private int timeout = -1; - - public ResourceDef(Class resType) { - this.resType = resType; - } - - public abstract T create(); - public abstract boolean applyRecycled(T resource); - public void destroy(T resource) {} - - public void setRecycleTimeout(int timeout) { - this.timeout = timeout; - } - - public boolean isOfResourceType(Class type) { - return resType != null && resType.isAssignableFrom(type); - } - public boolean isAcceptsRecycled() { - return resType != null; - } - public boolean isRecycleable() { - return true; - } - public int getRecycleTimeout() { - return timeout; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 5ed0c33cf0..6e4a8f124d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -4,8 +4,10 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture; +import java.nio.Buffer; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -18,14 +20,19 @@ public class ResourceList { private static final int INITIAL_SIZE = 20; - private ResourceRecycler recycler; + private RenderObjectMap map; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); private int nextSlot = 0; - public ResourceList(ResourceRecycler recycler) { - this.recycler = recycler; + public ResourceList(RenderObjectMap recycler) { + this.map = recycler; } + protected RenderResource create(ResourceProducer producer, ResourceDef def) { + RenderResource res = new RenderResource<>(producer, def, new ResourceTicket<>()); + res.getTicket().setIndex(add(res)); + return res; + } protected RenderResource locate(ResourceTicket ticket) { if (ticket == null) { throw new NullPointerException("Ticket cannot be null."); @@ -70,92 +77,104 @@ protected RenderResource remove(int index) { return prev; } - public ResourceTicket register(ResourceProducer producer, ResourceDef def) { - return register(producer, def, null); - } public ResourceTicket register(ResourceProducer producer, ResourceDef def, ResourceTicket store) { - ResourceTicket t = new ResourceTicket<>(); - t.setIndex(add(new RenderResource<>(producer, def, t))); - store = t.copyIndexTo(store); - return store; + return create(producer, def).getTicket().copyIndexTo(store); + } + + public void reserve(int passIndex, ResourceTicket ticket) { + if (ticket.getObjectId() >= 0) { + map.reserve(ticket.getObjectId(), passIndex); + locate(ticket).getTicket().setObjectId(ticket.getObjectId()); + } + } + public void reserve(int passIndex, ResourceTicket... tickets) { + for (ResourceTicket t : tickets) { + reserve(passIndex, t); + } } - public void reference(ResourceTicket ticket) { - locate(ticket).reference(); + public void reference(int passIndex, ResourceTicket ticket) { + locate(ticket).reference(passIndex); } - public boolean referenceOptional(ResourceTicket ticket) { + public boolean referenceOptional(int passIndex, ResourceTicket ticket) { if (ticket != null) { - reference(ticket); + reference(passIndex, ticket); return true; } return false; } - public void reference(ResourceTicket... tickets) { + public void reference(int passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { - reference(t); + reference(passIndex, t); } } - public void referenceOptional(ResourceTicket... tickets) { + public void referenceOptional(int passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { - referenceOptional(t); + referenceOptional(passIndex, t); } } - public > R getDef(Class type, ResourceTicket ticket) { + public > R getDefinition(Class type, ResourceTicket ticket) { ResourceDef def = locate(ticket).getDefinition(); if (type.isAssignableFrom(def.getClass())) { return (R)def; } return null; } - public void setDirect(ResourceTicket ticket, T resource) { - locate(ticket).setResource(resource); - } public T acquire(ResourceTicket ticket) { - RenderResource res = locate(ticket); - if (!res.isUsed()) { - throw new IllegalStateException(res+" was unexpectedly acquired."); + RenderResource resource = locate(ticket); + if (!resource.isUsed()) { + throw new IllegalStateException(resource+" was unexpectedly acquired."); } - if (res.isVirtual() && !recycler.recycle(res)) { - res.create(); + if (resource.isVirtual()) { + map.allocate(resource); } - return res.getResource(); + ticket.setObjectId(resource.getObject().getId()); + return resource.getResource(); } - public T acquire(ResourceTicket ticket, T value) { + public T acquireOrElse(ResourceTicket ticket, T value) { if (ticket != null) { - T r = acquire(ticket); - if (r != null) { - return r; - } + return acquire(ticket); } return value; } + public void acquireColorTargets(FrameBuffer fbo, ResourceTicket... tickets) { - for (ResourceTicket t : tickets) { - fbo.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(acquire(t))); + if (tickets.length == 0) { + fbo.clearColorTargets(); + return; + } + if (tickets.length < fbo.getNumColorTargets()) { + fbo.removeColorTargetsAbove(tickets.length-1); + } + int i = 0; + for (int n = Math.min(fbo.getNumColorTargets(), tickets.length); i < n; i++) { + Texture existing = fbo.getColorTarget(i).getTexture(); + Texture acquired = acquire((ResourceTicket)tickets[i]); + if (acquired != existing) { + fbo.setColorTarget(i, FrameBuffer.FrameBufferTarget.newTarget(acquired)); + } + } + for (; i < tickets.length; i++) { + fbo.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(acquire(tickets[i]))); } } - - public void release(ResourceTicket ticket) { - RenderResource res = locate(ticket); - res.release(); - if (!res.isUsed()) { - remove(ticket.getIndex()); - if (res.getDefinition().isRecycleable()) { - recycler.add(res); - } else if (res.getResource() != null) { - res.getDefinition().destroy(res.getResource()); - } + public void acquireDepthTarget(FrameBuffer fbo, ResourceTicket ticket) { + Texture acquired = acquire((ResourceTicket)ticket); + if (fbo.getDepthTarget() != null && acquired == fbo.getDepthTarget().getTexture()) { + return; } + fbo.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(acquired)); } - public void releaseNoRecycle(ResourceTicket ticket) { + + public void release(ResourceTicket ticket) { RenderResource res = locate(ticket); res.release(); if (!res.isUsed()) { remove(ticket.getIndex()); - } else if (res.getResource() != null) { - res.getDefinition().destroy(res.getResource()); + res.getObject().release(); + res.setObject(null); } } public boolean releaseOptional(ResourceTicket ticket) { @@ -170,47 +189,12 @@ public void release(ResourceTicket... tickets) { release(t); } } - public void releaseNoRecycle(ResourceTicket... tickets) { - for (ResourceTicket t : tickets) { - releaseNoRecycle(t); - } - } public void releaseOptional(ResourceTicket... tickets) { for (ResourceTicket t : tickets) { releaseOptional(t); } } - public void watch(ResourceTicket ticket) { - locate(ticket).setWatched(true); - } - public boolean watchOptional(ResourceTicket ticket) { - if (ticket != null) { - watch(ticket); - return true; - } - return false; - } - public void watch(ResourceTicket... tickets) { - for (ResourceTicket t : tickets) { - watch(t); - } - } - public void watchOptional(ResourceTicket... tickets) { - for (ResourceTicket t : tickets) { - watchOptional(t); - } - } - - public void dereferenceListed(List tickets, List target) { - for (ResourceTicket t : tickets) { - RenderResource r = locate(t); - r.release(); - if (!r.isReferenced()) { - target.add(r); - } - } - } public void cullUnreferenced() { LinkedList cull = new LinkedList<>(); for (RenderResource r : resources) { @@ -221,24 +205,29 @@ public void cullUnreferenced() { RenderResource resource; while ((resource = cull.pollFirst()) != null) { // dereference producer of resource - if (!resource.getProducer().dereference()) { - // if producer is not referenced, dereference all input resources - for (ResourceTicket t : resource.getProducer().getInputTickets()) { - RenderResource r = locate(t); - r.release(); - if (!r.isReferenced()) { - cull.addLast(r); + ResourceProducer producer = resource.getProducer(); + if (producer != null) { + if (!producer.dereference()) { + // if producer is not referenced, dereference all input resources + for (ResourceTicket t : resource.getProducer().getInputTickets()) { + RenderResource r = locate(t); + r.release(); + if (!r.isReferenced()) { + cull.addLast(r); + } + } + // remove all output resources + for (ResourceTicket t : resource.getProducer().getOutputTickets()) { + remove(t.getIndex()); } } - // remove all output resources - for (ResourceTicket t : resource.getProducer().getOutputTickets()) { - remove(t.getIndex()); - } + } else { + remove(resource.getIndex()); } } } - public void clear() { + // TODO: throw exceptions for unreleased resources. int size = resources.size(); resources = new ArrayList<>(size); nextSlot = 0; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java index 4baa372f07..aa8d82d1ee 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java @@ -12,6 +12,8 @@ */ public interface ResourceProducer { + public int getIndex(); + public boolean dereference(); public boolean isReferenced(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java deleted file mode 100644 index 347e133539..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceRecycler.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.Iterator; -import java.util.LinkedList; - -/** - * - * @author codex - */ -public class ResourceRecycler { - - private final LinkedList resources = new LinkedList<>(); - private int timeout = 1; - - public void add(RenderResource resource) { - if (resource.isVirtual() && resource.getResource() != null) { - throw new IllegalArgumentException("Resource cannot be virtual or null."); - } - if (resource.getDefinition().getRecycleTimeout() >= 0) { - resource.setTimeout(resource.getDefinition().getRecycleTimeout()); - } else { - resource.setTimeout(timeout); - } - //res.getDefinition().destroy(res.getResource()); - resources.add(resource); - } - public void add(Object resource) { - if (resource == null) { - throw new NullPointerException("Resource cannot be null."); - } - RenderResource r = new RenderResource(null, null, null); - r.setResource(resource); - r.setTimeout(timeout); - resources.add(r); - } - - public boolean recycle(RenderResource resource) { - ResourceDef def = resource.getDefinition(); - if (!def.isAcceptsRecycled()) { - return false; - } - for (Iterator it = resources.iterator(); it.hasNext();) { - RenderResource res = it.next(); - if (def.isOfResourceType(res.getResource().getClass())) { - T r = (T)res.getResource(); - if (def.applyRecycled(r)) { - resource.setResource(r); - it.remove(); - return true; - } - } - } - return false; - } - public void flush() { - // Note: flushing resources on the same frame they were created causes the - // screen to render black. Guess: destroying output texture early causes - // the input to become null? - int n = 0; - for (Iterator it = resources.iterator(); it.hasNext();) { - RenderResource r = it.next(); - if (!r.tickTimeout()) { - n++; - r.getDefinition().destroy(r.getResource()); - it.remove(); - } - } - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index c767578854..3251cceebd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -21,6 +21,7 @@ public class ResourceTicket { private final long id; private String name; private int index; + private int objectId; public ResourceTicket() { this(null, -1); @@ -78,6 +79,10 @@ protected ResourceTicket setIndex(int index) { return this; } + public void setObjectId(int objectId) { + this.objectId = objectId; + } + /** * Gets the id unique to this ticket. * @@ -105,6 +110,10 @@ public int getIndex() { return index; } + public int getObjectId() { + return objectId; + } + @Override public String toString() { return "Ticket[id="+id+", name="+name+", index="+index+"]"; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java index 01945fd6b9..de156813d7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java @@ -4,6 +4,8 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.passes.BucketPass; +import com.jme3.renderer.framegraph.passes.OutputPass; import com.jme3.renderer.queue.RenderQueue.Bucket; /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java new file mode 100644 index 0000000000..1d833fe619 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java @@ -0,0 +1,56 @@ +/* + * 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 TimeFrame { + + private int index, length; + + private TimeFrame() {} + public TimeFrame(int passIndex, int length) { + this.index = passIndex; + this.length = length; + if (this.index < 0) { + throw new IllegalArgumentException("Pass index cannot be negative."); + } + if (this.length < 0) { + throw new IllegalArgumentException("Length cannot be negative."); + } + } + + public void extendTo(int passIndex) { + length = Math.max(length, passIndex-this.index); + } + public TimeFrame copyTo(TimeFrame target) { + if (target == null) { + target = new TimeFrame(); + } + target.index = index; + target.length = length; + return target; + } + + public int getStartIndex() { + return index; + } + public int getLength() { + return length; + } + public int getEndIndex() { + return index+length; + } + + public boolean overlaps(TimeFrame time) { + return index <= time.index+time.length && index+length >= time.index; + } + public boolean contains(int index) { + return index <= index && index+length >= index; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueDef.java deleted file mode 100644 index 8acf33bf1c..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueDef.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.function.Function; - -/** - * - * @author codex - * @param - */ -public abstract class ValueDef extends ResourceDef { - - public ValueDef() { - super(null); - } - - @Override - public boolean applyRecycled(T resource) { - return false; - } - - @Override - public boolean isRecycleable() { - return false; - } - - public static ValueDef create(Function func) { - return new ValueDefImpl(func); - } - - private static class ValueDefImpl extends ValueDef { - - private final Function func; - - public ValueDefImpl(Function func) { - this.func = func; - } - - @Override - public T create() { - return func.apply(null); - } - - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java new file mode 100644 index 0000000000..3ab057b13a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -0,0 +1,24 @@ +/* + * 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.definitions; + +import java.util.function.Consumer; + +/** + * + * @author codex + * @param + */ +public interface ResourceDef { + + public T createResource(); + + public T applyResource(Object resource); + + public default Consumer getDisposalMethod() { + return null; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef2D.java similarity index 74% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef2D.java index 48a95b9b44..81376dd4f5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureDef2D.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef2D.java @@ -2,16 +2,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; +package com.jme3.renderer.framegraph.definitions; import com.jme3.texture.Image; +import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; /** * * @author codex */ -public class TextureDef2D extends ResourceDef { +public class TextureDef2D implements ResourceDef { private int width, height, samples; private Image.Format format; @@ -20,7 +21,6 @@ public TextureDef2D(int width, int height, Image.Format format) { this(width, height, 1, format); } public TextureDef2D(int width, int height, int samples, Image.Format format) { - super(Texture2D.class); this.width = width; this.height = height; this.samples = samples; @@ -28,7 +28,7 @@ public TextureDef2D(int width, int height, int samples, Image.Format format) { } @Override - public Texture2D create() { + public Texture2D createResource() { if (samples != 1) { return new Texture2D(width, height, samples, format); } else { @@ -36,14 +36,17 @@ public Texture2D create() { } } @Override - public boolean applyRecycled(Texture2D resource) { - Image img = resource.getImage(); - return img.getWidth() == width && img.getHeight() == height - && img.getFormat() == format && img.getMultiSamples() == samples; - } - @Override - public void destroy(Texture2D tex) { - tex.getImage().dispose(); + public Texture2D applyResource(Object resource) { + if (!(resource instanceof Texture2D)) { + return null; + } + Texture2D tex = (Texture2D)resource; + Image img = tex.getImage(); + if (img.getWidth() == width && img.getHeight() == height + && img.getFormat() == format && img.getMultiSamples() == samples) { + return tex; + } + return null; } public void setWidth(int width) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java new file mode 100644 index 0000000000..91ff7dc1d2 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java @@ -0,0 +1,57 @@ +/* + * 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.definitions; + +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * + * @author codex + * @param + */ +public class ValueDef implements ResourceDef { + + private final Class type; + private Function create; + private Consumer reset; + + public ValueDef(Class type, Function create) { + this.type = type; + this.create = create; + } + + @Override + public T createResource() { + return create.apply(null); + } + @Override + public T applyResource(Object resource) { + if (reset != null && type.isAssignableFrom(resource.getClass())) { + T res = (T)resource; + reset.accept(res); + return res; + } + return null; + } + + public void setCreate(Function create) { + this.create = create; + } + public void setReset(Consumer reset) { + this.reset = reset; + } + + public Class getType() { + return type; + } + public Function getCreate() { + return create; + } + public Consumer getReset() { + return reset; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java deleted file mode 100644 index 84ebad36a8..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/AbstractModule.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.pass; - -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.parameters.ParamSocket; -import com.jme3.renderer.framegraph.parameters.Referenceable; -import java.util.Collection; -import java.util.LinkedList; - -/** - * - * @author codex - */ -public abstract class AbstractModule implements FGModule { - - private final LinkedList inSockets = new LinkedList<>(); - private final LinkedList outSockets = new LinkedList<>(); - private int refs = 0; - - @Override - public Collection getInputSockets() { - return inSockets; - } - - @Override - public Collection getOutputSockets() { - return outSockets; - } - - @Override - public void preFrame(RenderContext context) {} - - @Override - public void postQueue(RenderContext context) {} - - @Override - public int compileNumReferences() { - return (refs = outSockets.size()); - } - - @Override - public int removeReference() { - return --refs; - } - - @Override - public void dereferenceUpstream(Collection derefs) { - derefs.addAll(inSockets); - } - - @Override - public int getNumReferences() { - return refs; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java deleted file mode 100644 index b0c10a9b58..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/BackgroundScreenTestModule.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.pass; - -import com.jme3.asset.AssetManager; -import com.jme3.material.Material; -import com.jme3.material.RenderState; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.texture.Texture2D; -import com.jme3.ui.Picture; - -/** - * - * @author codex - */ -public class BackgroundScreenTestModule extends AbstractModule { - - private final AssetManager assetManager; - private Picture screen; - - public BackgroundScreenTestModule(AssetManager assetManager) { - this.assetManager = assetManager; - } - - @Override - public void initialize(FrameGraph frameGraph) { - - screen = new Picture("TestScreen"); - screen.setWidth(1f); - screen.setHeight(1f); - - Material mat = new Material(assetManager, "Common/MatDefs/Misc/Screen.j3md"); - mat.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg")); - screen.setMaterial(mat); - - RenderState rs = screen.getMaterial().getAdditionalRenderState(); - rs.setDepthTest(!true); - rs.setDepthWrite(!true); - //rs.setDepthFunc(RenderState.TestFunction.Less); - - } - @Override - public boolean prepare(RenderContext context) { - return true; - } - @Override - public void execute(RenderContext context) { - - //context.setDepthRange(1, 1); - screen.updateGeometricState(); - screen.getMaterial().render(screen, screen.getLocalLightList(), context.getRenderManager()); - //context.getRenderer().clearBuffers(false, true, false); - - } - @Override - public void reset() {} - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java deleted file mode 100644 index dbcc423572..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/DeferredShadingModule.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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.pass; - -import com.jme3.asset.AssetManager; -import com.jme3.light.LightList; -import com.jme3.material.Material; -import com.jme3.material.RenderState; -import com.jme3.material.TechniqueDef; -import com.jme3.material.logic.DeferredSinglePassLightingLogic; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.Renderer; -import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.parameters.MatRenderParam; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.parameters.TextureTargetParam; -import com.jme3.renderer.framegraph.parameters.ValueRenderParam; -import com.jme3.shader.VarType; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture2D; -import com.jme3.ui.Picture; - -/** - * - * @author codex - */ -public class DeferredShadingModule extends ScreenModule { - - public final static String RT_0 = "Context_InGBuff0"; - public final static String RT_1 = "Context_InGBuff1"; - public final static String RT_2 = "Context_InGBuff2"; - public final static String RT_3 = "Context_InGBuff3"; - public final static String RT_4 = "Context_InGBuff4"; - public final static String LIGHT_DATA = "DeferredShadingPass.LightData"; - public final static String EXECUTE_STATE = "DeferredShadingPass.ExecuteState"; - public final static String IN_FRAME_BUFFER = "DeferredShadingPass.InFrameBuffer"; - public final static String DEPTH_DEBUG = "DeferredShadingPass.DepthDebug"; - private final static String PASS = "DeferredPass"; - private static final String MATDEF = "Common/MatDefs/ShadingCommon/DeferredShading.j3md"; - - protected final AssetManager assetManager; - protected MatRenderParam[] matParams = new MatRenderParam[5]; - protected ValueRenderParam lightList; - protected ValueRenderParam executeState; - protected ValueRenderParam gBuffer; - private FrameBuffer debug; - private TextureTargetParam depthCopy; - - public DeferredShadingModule(AssetManager assetManager) { - this.assetManager = assetManager; - } - - @Override - public void initialize(FrameGraph frameGraph) { - - super.initialize(frameGraph); - - Material screenMat = screenRect.getMaterial(); - RenderState rs = screenMat.getAdditionalRenderState(); - rs.setDepthTest(true); - rs.setDepthWrite(true); - rs.setDepthFunc(RenderState.TestFunction.Greater); - screenMat.setBoolean("UseLightsCullMode", false); - - for (TechniqueDef t : screenMat.getMaterialDef().getTechniqueDefs(PASS)) { - t.setLogic(new DeferredSinglePassLightingLogic(t, true)); - } - - // material render parameters automatically apply their values - matParams[0] = addInput(new MatRenderParam(RT_0, screenMat, VarType.Texture2D)); - matParams[1] = addInput(new MatRenderParam(RT_1, screenMat, VarType.Texture2D)); - matParams[2] = addInput(new MatRenderParam(RT_2, screenMat, VarType.Texture2D)); - matParams[3] = addInput(new MatRenderParam(RT_3, screenMat, VarType.Texture2D)); - matParams[4] = addInput(new MatRenderParam(RT_4, screenMat, VarType.Texture2D)); - lightList = addInput(new ValueRenderParam<>(LIGHT_DATA)); - executeState = addInput(new ValueRenderParam<>(EXECUTE_STATE)); - gBuffer = addInput(new ValueRenderParam<>(IN_FRAME_BUFFER)); - depthCopy = addOutput(new TextureTargetParam(DEPTH_DEBUG, null)); - - for (int i = 0; i < matParams.length; i++) { - frameGraph.bindToOutput(GBufferModule.RENDER_TARGETS[i], matParams[i]); - } - frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); - frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); - frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, gBuffer); - - } - @Override - public boolean prepare(RenderContext context) { - if (debug == null) { - debug = new FrameBuffer(context.getWidth(), context.getHeight(), 1); - FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget( - new Texture2D(context.getWidth(), context.getHeight(), GBufferModule.DEPTH_FORMAT)); - debug.setDepthTarget(t); - depthCopy.setTextureTarget(t); - } - return true; - } - @Override - public void execute(RenderContext context) { - - context.getRenderer().copyFrameBuffer(gBuffer.get(), - context.getViewPort().getOutputFrameBuffer(), false, true); - - context.getRenderer().copyFrameBuffer(gBuffer.get(), debug, false, true); - - screenRect.getMaterial().selectTechnique(PASS, context.getRenderManager()); - context.setDepthRange(1, 1); - context.getRenderer().setFrameBuffer(context.getViewPort().getOutputFrameBuffer()); - screenRect.updateGeometricState(); - context.getRenderManager().renderGeometry(screenRect, lightList.get()); - - } - @Override - public void reset() {} - @Override - protected Material createScreenMaterial() { - return new Material(assetManager, MATDEF); - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java deleted file mode 100644 index b6ec8b3614..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/FGModule.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.pass; - -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.parameters.SocketGroup; - -/** - * - * @author codex - * @param - */ -public interface FGModule extends SocketGroup { - - /** - * Initializes the pass to the framegraph. - *

    - * This is called when the pass is first added to the framegraph. - * - * @param frameGraph - */ - public void initialize(T frameGraph); - - /** - * Called before the render buckets are queued. - *

    - * This method is called before parameters are pulled. - * - * @param context - */ - public void preFrame(RenderContext context); - - /** - * Called after the render buckets are queued. - *

    - * This method is called before parameters are pulled. - * - * @param context - */ - public void postQueue(RenderContext context); - - /** - * Prepares the pass for execution and determines if execution should occur. - *

    - * If execution is vetoed on this step, parameter pulling, execution, parameter - * pushing, and render state reset will not occur. - *

    - * This method is called before parameters are pulled. - * - * @param context - * @return true if execution should occur - */ - public boolean prepare(RenderContext context); - - /** - * Executes this pass. - * - * @param context - */ - public void execute(RenderContext context); - - /** - * Resets this pass after all passes have been executed. - */ - public void reset(); - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java deleted file mode 100644 index 6f7301c395..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ForwardModule.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.pass; - -import com.jme3.renderer.framegraph.DepthRange; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.queue.RenderQueue; - -/** - * - * @author codex - */ -public class ForwardModule extends AbstractModule { - - private final RenderQueue.Bucket bucket; - protected DepthRange depth; - - public ForwardModule(RenderQueue.Bucket bucket) { - this(bucket, DepthRange.IDENTITY); - } - public ForwardModule(RenderQueue.Bucket bucket, DepthRange depth) { - this.bucket = bucket; - this.depth = depth; - } - - @Override - public void initialize(FrameGraph frameGraph) {} - @Override - public boolean prepare(RenderContext context) { - return !context.getRenderQueue().isQueueEmpty(bucket); - } - @Override - public void execute(RenderContext context) { - if (depth != null) { - context.setDepthRange(depth); - } - context.getRenderQueue().renderQueue(bucket, context.getRenderManager(), context.getViewPort().getCamera(), true); - } - @Override - public void reset() {} - - public static ForwardModule opaque() { - return new ForwardModule(RenderQueue.Bucket.Opaque, DepthRange.IDENTITY); - } - public static ForwardModule sky() { - return new ForwardModule(RenderQueue.Bucket.Sky, new DepthRange(1, 1)); - } - public static ForwardModule transparent() { - return new ForwardModule(RenderQueue.Bucket.Transparent, DepthRange.IDENTITY); - } - public static ForwardModule translucent() { - return new ForwardModule(RenderQueue.Bucket.Translucent, DepthRange.IDENTITY); - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java deleted file mode 100644 index c6dbce0bd9..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/GBufferModule.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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.pass; - -import com.jme3.light.Light; -import com.jme3.light.LightList; -import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; -import com.jme3.renderer.GeometryRenderHandler; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.Renderer; -import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.parameters.TextureTargetParam; -import com.jme3.renderer.framegraph.parameters.ValueRenderParam; -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.scene.Geometry; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture2D; -import java.util.ArrayList; - -/** - * - * @author codex - */ -public class GBufferModule extends ForwardModule implements GeometryRenderHandler { - - private final static String GBUFFER_PASS = "GBufferPass"; - public final static String[] RENDER_TARGETS = { - "GBufferPass.RT0", "GBufferPass.RT1", "GBufferPass.RT2", "GBufferPass.RT3", "GBufferPass.RT4" - }; - public final static String G_FRAME_BUFFER = "GBufferPass.Framebuffer"; - public final static String LIGHT_DATA = "GBufferPass.LightData"; - public final static String EXECUTE_STATE = "GBufferPass.ExecuteState"; - public final static Image.Format DEPTH_FORMAT = Image.Format.Depth; - - private final LightList lightData = new LightList(null); - private final ArrayList tempLights = new ArrayList<>(); - private ValueRenderParam hasDraw; - private FrameBuffer gBuffer; - private ValueRenderParam bufferParam; - private final TextureTargetParam[] targets = new TextureTargetParam[5]; - private final ColorRGBA mask = new ColorRGBA(); - - public GBufferModule() { - super(RenderQueue.Bucket.Opaque); - } - - @Override - public void initialize(FrameGraph frameGraph) { - super.initialize(frameGraph); - for (int i = 0; i < targets.length; i++) { - targets[i] = addParameter(new TextureTargetParam(RENDER_TARGETS[i], null)); - } - addParameter(new ValueRenderParam<>(LIGHT_DATA, lightData)); - hasDraw = addParameter(new ValueRenderParam<>(EXECUTE_STATE, false)); - bufferParam = addParameter(new ValueRenderParam<>(G_FRAME_BUFFER, gBuffer)); - } - - @Override - public boolean prepare(RenderContext context) { - if (context.isSizeChanged() || gBuffer == null) { - reshape(context.getRenderer(), context.getWidth(), context.getHeight()); - } - return super.prepare(context); - } - - @Override - public void execute(RenderContext context) { - ViewPort vp = context.getViewPort(); - String tempFT = context.getRenderManager().getForcedTechnique(); - context.getRenderer().setFrameBuffer(gBuffer); - context.getRenderer().setBackgroundColor(mask.set(vp.getBackgroundColor()).setAlpha(0)); - context.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); - context.getRenderManager().setForcedTechnique(GBUFFER_PASS); - context.getRenderManager().setGeometryRenderHandler(this); - super.execute(context); - context.getRenderManager().setGeometryRenderHandler(null); - context.getRenderManager().setForcedTechnique(tempFT); - context.getRenderer().setBackgroundColor(vp.getBackgroundColor()); - context.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer()); - for (Light light : tempLights) { - lightData.add(light); - } - } - - @Override - public boolean renderGeometry(RenderManager rm, Geometry geom) { - Material material = geom.getMaterial(); - if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null) { - return false; - } - rm.renderGeometry(geom); - if (material.getActiveTechnique() != null) { - if (material.getMaterialDef().getTechniqueDefs(GBUFFER_PASS) != null) { - LightList lights = geom.getFilterWorldLights(); - for (Light light : lights) { - if (!tempLights.contains(light)) { - tempLights.add(light); - } - } - // Whether it has lights or not, material objects containing GBufferPass will perform - // DeferredShading, and shade according to shadingModelId - hasDraw.set(true); - return true; - } - } - return false; - } - - @Override - public void reset() { - super.reset(); - tempLights.clear(); - lightData.clear(); - hasDraw.set(false); - } - - protected void reshape(Renderer renderer, int w, int h) { - if (gBuffer != null) { - //w = gBuffer.getWidth(); - //h = gBuffer.getHeight(); - gBuffer.dispose(); - gBuffer.deleteObject(renderer); - } - gBuffer = new FrameBuffer(w, h, 1); - // To ensure accurate results, 32bit is used here for generalization. - Texture2D[] textures = new Texture2D[5]; - textures[0] = new Texture2D(w, h, Image.Format.RGBA16F); - textures[1] = new Texture2D(w, h, Image.Format.RGBA16F); - textures[2] = new Texture2D(w, h, Image.Format.RGBA16F); - // The third buffer provides 32-bit floating point to store high-precision information, such as normals - textures[3] = new Texture2D(w, h, Image.Format.RGBA32F); - // 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. - textures[4] = new Texture2D(w, h, DEPTH_FORMAT); - //gBuffer.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(Image.Format.RGBA8)); - //for (int i = 0; i < textures.length; i++) { - // FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget(textures[i]); - // gBuffer.addColorTarget(t); - // targets[i].setTextureTarget(t); - //} - FrameBuffer.FrameBufferTextureTarget t0 = FrameBuffer.FrameBufferTarget.newTarget(textures[0]); - gBuffer.addColorTarget(t0); - targets[0].setTextureTarget(t0); - FrameBuffer.FrameBufferTextureTarget t1 = FrameBuffer.FrameBufferTarget.newTarget(textures[1]); - gBuffer.addColorTarget(t1); - targets[1].setTextureTarget(t1); - FrameBuffer.FrameBufferTextureTarget t2 = FrameBuffer.FrameBufferTarget.newTarget(textures[2]); - gBuffer.addColorTarget(t2); - targets[2].setTextureTarget(t2); - FrameBuffer.FrameBufferTextureTarget t3 = FrameBuffer.FrameBufferTarget.newTarget(textures[3]); - gBuffer.addColorTarget(t3); - targets[3].setTextureTarget(t3); - FrameBuffer.FrameBufferTextureTarget t4 = FrameBuffer.FrameBufferTarget.newTarget(textures[4]); - gBuffer.setDepthTarget(t4); - targets[4].setTextureTarget(t4); - gBuffer.setMultiTarget(true); - bufferParam.set(gBuffer); - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java deleted file mode 100644 index 516286196e..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/PostProcessingModule.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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.pass; - -import com.jme3.post.SceneProcessor; -import com.jme3.profile.AppProfiler; -import com.jme3.profile.SpStep; -import com.jme3.profile.VpStep; -import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.DepthRange; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.util.SafeArrayList; - -/** - * - * @author codex - */ -public class PostProcessingModule extends AbstractModule { - - @Override - public void initialize(FrameGraph frameGraph) {} - @Override - public void preFrame(RenderContext context) { - ViewPort vp = context.getViewPort(); - SafeArrayList processors = vp.getProcessors(); - AppProfiler prof = context.getProfiler(); - if (processors != null && !processors.isEmpty()) { - if (prof != null) { - prof.vpStep(VpStep.PreFrame, vp, null); - } - for (SceneProcessor p : processors.getArray()) { - if (!p.isInitialized()) { - p.initialize(context.getRenderManager(), vp); - } - p.setProfiler(context.getProfiler()); - if (prof != null) { - prof.spStep(SpStep.ProcPreFrame, p.getClass().getSimpleName()); - } - p.preFrame(context.getTpf()); - } - } - } - @Override - public void postQueue(RenderContext context) { - ViewPort vp = context.getViewPort(); - SafeArrayList processors = vp.getProcessors(); - AppProfiler prof = context.getProfiler(); - if (processors != null && !processors.isEmpty()) { - 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()); - } - } - } - @Override - public boolean prepare(RenderContext context) { - return true; - } - @Override - public void execute(RenderContext context) { - context.setDepthRange(DepthRange.IDENTITY); - ViewPort vp = context.getViewPort(); - SafeArrayList processors = vp.getProcessors(); - AppProfiler prof = context.getProfiler(); - if (processors != null && !processors.isEmpty()) { - if (prof != null) { - prof.vpStep(VpStep.PostFrame, vp, null); - } - for (SceneProcessor p : processors.getArray()) { - if (prof != null) { - prof.spStep(SpStep.ProcPostFrame, p.getClass().getSimpleName()); - } - p.postFrame(vp.getOutputFrameBuffer()); - } - if (prof != null) { - prof.vpStep(VpStep.ProcEndRender, vp, null); - } - } - } - @Override - public void reset() {} - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ScreenModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ScreenModule.java deleted file mode 100644 index 6f00a90613..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/ScreenModule.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.pass; - -import com.jme3.material.Material; -import com.jme3.material.RenderState; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.ui.Picture; - -/** - * - * @author codex - */ -public abstract class ScreenModule extends AbstractModule { - - protected Picture screenRect; - - @Override - public void initialize(FrameGraph frameGraph) { - screenRect = new Picture("ScreenRect"); - screenRect.setWidth(1); - screenRect.setHeight(1); - screenRect.setIgnoreTransform(true); - Material mat = createScreenMaterial(); - screenRect.setMaterial(mat); - RenderState rs = mat.getAdditionalRenderState(); - rs.setDepthWrite(false); - rs.setDepthTest(false); - } - - protected abstract Material createScreenMaterial(); - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java deleted file mode 100644 index eab576f9a9..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/pass/TileDeferredShadingModule.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.pass; - -import com.jme3.asset.AssetManager; -import com.jme3.light.LightList; -import com.jme3.material.Material; -import com.jme3.material.RenderState; -import com.jme3.material.TechniqueDef; -import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic; -import com.jme3.material.logic.TiledRenderGrid; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.RenderContext; -import com.jme3.renderer.framegraph.parameters.MatRenderParam; -import com.jme3.renderer.framegraph.parameters.TextureTargetParam; -import com.jme3.renderer.framegraph.parameters.ValueRenderParam; -import com.jme3.renderer.framegraph.parameters.WorldRenderParam; -import com.jme3.shader.VarType; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture2D; - -/** - * - * @author codex - */ -public class TileDeferredShadingModule extends ScreenModule { - - public final static String RT_0 = "Context_InGBuff0"; - public final static String RT_1 = "Context_InGBuff1"; - public final static String RT_2 = "Context_InGBuff2"; - public final static String RT_3 = "Context_InGBuff3"; - public final static String RT_4 = "Context_InGBuff4"; - public final static String LIGHT_DATA = "TileDeferredShadingPass.LightData"; - public final static String EXECUTE_STATE = "TileDeferredShadingPass.ExecuteState"; - public final static String IN_FRAME_BUFFER = "TileDeferredShadingPass.InFrameBuffer"; - public final static String TILE_INFO = "TileDeferredShadingPass.TileInfo"; - public final static String DEPTH_DEBUG = "TileDeferredShadingPass.DepthDebug"; - private final static String PASS = "TileBasedDeferredPass"; - private static final String MATDEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"; - - protected final AssetManager assetManager; - private final TiledRenderGrid tileInfo = new TiledRenderGrid(); - protected MatRenderParam[] matParams = new MatRenderParam[5]; - protected ValueRenderParam lightList; - protected ValueRenderParam executeState; - protected ValueRenderParam gBuffer; - private WorldRenderParam tileParam; - private FrameBuffer debug; - private TextureTargetParam depthCopy; - - public TileDeferredShadingModule(AssetManager assetManager) { - this.assetManager = assetManager; - } - - @Override - public void initialize(FrameGraph frameGraph) { - - super.initialize(frameGraph); - - Material screenMat = screenRect.getMaterial(); - RenderState rs = screenMat.getAdditionalRenderState(); - rs.setDepthTest(true); - rs.setDepthWrite(true); - rs.setDepthFunc(RenderState.TestFunction.Greater); - screenMat.setBoolean("UseLightsCullMode", false); - - for (TechniqueDef t : screenMat.getMaterialDef().getTechniqueDefs(PASS)) { - t.setLogic(new TileBasedDeferredSinglePassLightingLogic(t, tileInfo)); - } - - // material render parameters automatically apply their values - matParams[0] = addParameter(new MatRenderParam(RT_0, screenMat, VarType.Texture2D)); - matParams[1] = addParameter(new MatRenderParam(RT_1, screenMat, VarType.Texture2D)); - matParams[2] = addParameter(new MatRenderParam(RT_2, screenMat, VarType.Texture2D)); - matParams[3] = addParameter(new MatRenderParam(RT_3, screenMat, VarType.Texture2D)); - matParams[4] = addParameter(new MatRenderParam(RT_4, screenMat, VarType.Texture2D)); - lightList = addParameter(new ValueRenderParam<>(LIGHT_DATA)); - executeState = addParameter(new ValueRenderParam<>(EXECUTE_STATE)); - gBuffer = addParameter(new ValueRenderParam<>(IN_FRAME_BUFFER)); - tileParam = addParameter(new WorldRenderParam<>(TILE_INFO, frameGraph.getWorldParameters(), TILE_INFO)); - depthCopy = addParameter(new TextureTargetParam(DEPTH_DEBUG, null)); - - for (int i = 0; i < matParams.length; i++) { - frameGraph.bindToOutput(GBufferModule.RENDER_TARGETS[i], matParams[i]); - } - frameGraph.bindToOutput(GBufferModule.LIGHT_DATA, lightList); - frameGraph.bindToOutput(GBufferModule.EXECUTE_STATE, executeState); - frameGraph.bindToOutput(GBufferModule.G_FRAME_BUFFER, gBuffer); - - } - @Override - public boolean prepare(RenderContext context) { - if (debug == null) { - debug = new FrameBuffer(context.getWidth(), context.getHeight(), 1); - FrameBuffer.FrameBufferTextureTarget t = FrameBuffer.FrameBufferTarget.newTarget( - new Texture2D(context.getWidth(), context.getHeight(), GBufferModule.DEPTH_FORMAT)); - debug.setDepthTarget(t); - depthCopy.setTextureTarget(t); - } - return true; - } - @Override - public void execute(RenderContext context) { - - TiledRenderGrid t = tileParam.get(); - if (t != null) { - tileInfo.copyFrom(t); - } - tileInfo.update(context.getRenderManager().getCurrentCamera()); - - context.getRenderer().copyFrameBuffer(gBuffer.get(), - context.getViewPort().getOutputFrameBuffer(), false, true); - - context.getRenderer().copyFrameBuffer(gBuffer.get(), debug, false, true); - - screenRect.getMaterial().selectTechnique(PASS, context.getRenderManager()); - context.setDepthRange(1, 1); - context.getRenderer().setFrameBuffer(context.getViewPort().getOutputFrameBuffer()); - screenRect.updateGeometricState(); - context.getRenderManager().renderGeometry(screenRect, lightList.get()); - - } - @Override - public void reset() {} - @Override - protected Material createScreenMaterial() { - return new Material(assetManager, MATDEF); - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java similarity index 81% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index cc1e85a6d4..6851fbe852 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -2,9 +2,14 @@ * 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; +package com.jme3.renderer.framegraph.passes; +import com.jme3.renderer.framegraph.definitions.TextureDef2D; import com.jme3.math.ColorRGBA; +import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; @@ -21,7 +26,6 @@ public class BucketPass extends RenderPass { private int samples = 1; private boolean flush = true; private ResourceTicket inColor, inDepth, outColor, outDepth; - private ResourceTicket frameBuffer; private Texture2D fTex; public BucketPass(Bucket bucket) { @@ -45,19 +49,16 @@ protected void prepare(FGRenderContext context) { int h = context.getHeight(); outColor = register(new TextureDef2D(w, h, samples, Image.Format.RGBA8), outColor); outDepth = register(new TextureDef2D(w, h, samples, Image.Format.Depth), outDepth); - frameBuffer = register(new FrameBufferDef(w, h, samples), frameBuffer); referenceOptional(inColor, inDepth); } @Override protected void execute(FGRenderContext context) { - FrameBuffer fb = resources.acquire(frameBuffer); - fb.clearColorTargets(); - // no need to clear the depth target, since we are assigning one below - fb.addColorTarget(context.createTextureTarget(resources.acquire(outColor))); - fb.setDepthTarget(context.createTextureTarget(resources.acquire(outDepth))); - context.setFrameBuffer(fb, true, true, true); + resources.acquireColorTargets(frameBuffer, outColor); + resources.acquireDepthTarget(frameBuffer, inDepth); + context.getRenderer().setFrameBuffer(frameBuffer); + context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); - context.transferTextures(resources.acquire(inColor, null), resources.acquire(inDepth, null)); + context.transferTextures(resources.acquireOrElse(inColor, null), resources.acquireOrElse(inDepth, null)); context.getRenderer().setDepthRange(depth); if (bucket == Bucket.Gui) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); @@ -66,7 +67,6 @@ protected void execute(FGRenderContext context) { if (bucket == Bucket.Gui) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); } - fb.clearColorTargets(); } @Override protected void reset(FGRenderContext context) {} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java similarity index 76% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 32f30a5b1f..cd4152a596 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -2,12 +2,16 @@ * 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; +package com.jme3.renderer.framegraph.passes; +import com.jme3.renderer.framegraph.definitions.TextureDef2D; import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.material.TechniqueDef; import com.jme3.material.logic.DeferredSinglePassLightingLogic; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; @@ -20,9 +24,7 @@ public class DeferredPass extends RenderPass { private ResourceTicket depth, diffuse, specular, emissive, normal, outColor; private ResourceTicket lights; - private ResourceTicket frameBuffer; private Material material; - private final CameraSize camSize = new CameraSize(); @Override protected void initialize(FrameGraph frameGraph) { @@ -36,35 +38,37 @@ protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); outColor = register(new TextureDef2D(w, h, Image.Format.RGBA8), outColor); - frameBuffer = register(new FrameBufferDef(w, h, 1), frameBuffer); + reserve(outColor); reference(depth, diffuse, specular, emissive, normal); referenceOptional(lights); } @Override protected void execute(FGRenderContext context) { - FrameBuffer fb = resources.acquire(frameBuffer); - fb.clearColorTargets(); - fb.setDepthTarget((FrameBuffer.FrameBufferTextureTarget)null); - resources.acquireColorTargets(fb, outColor); - context.setFrameBuffer(fb, true, true, true); + resources.acquireColorTargets(frameBuffer, outColor); + context.getRenderer().setFrameBuffer(frameBuffer); + context.getRenderer().clearBuffers(true, true, true); material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); material.setTexture("Context_InGBuff1", resources.acquire(specular)); material.setTexture("Context_InGBuff2", resources.acquire(emissive)); material.setTexture("Context_InGBuff3", resources.acquire(normal)); material.setTexture("Context_InGBuff4", resources.acquire(depth)); material.selectTechnique("DeferredPass", context.getRenderManager()); - LightList lightList = resources.acquire(lights, null); + LightList lightList = resources.acquireOrElse(lights, null); + context.getRenderer().setDepthRange(0, 1); if (lightList != null) { context.getScreen().render(context.getRenderManager(), material, lightList); } else { context.renderFullscreen(material); } - fb.clearColorTargets(); } @Override - public void reset(FGRenderContext context) {} + protected void reset(FGRenderContext context) {} @Override - public void cleanup(FrameGraph frameGraph) {} + protected void cleanup(FrameGraph frameGraph) {} + @Override + protected FrameBuffer createFrameBuffer(FGRenderContext context) { + return new FrameBuffer(context.getWidth(), context.getHeight(), 1); + } public void setDepth(ResourceTicket depth) { this.depth = depth; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java similarity index 83% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 8b875ed88e..55256335f2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -2,15 +2,19 @@ * 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; +package com.jme3.renderer.framegraph.passes; +import com.jme3.renderer.framegraph.definitions.ValueDef; +import com.jme3.renderer.framegraph.definitions.TextureDef2D; import com.jme3.light.Light; import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; @@ -37,24 +41,27 @@ protected void initialize(FrameGraph frameGraph) {} protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - depth = register(new TextureDef2D(w, h, Image.Format.Depth), depth).setName("depth"); - diffuse = register(new TextureDef2D(w, h, Image.Format.RGBA16F), diffuse).setName("diffuse"); - specular = register(new TextureDef2D(w, h, Image.Format.RGBA16F), specular).setName("specular"); - emissive = register(new TextureDef2D(w, h, Image.Format.RGBA16F), emissive).setName("emissive"); - normal = register(new TextureDef2D(w, h, Image.Format.RGBA32F), normal).setName("normal"); - lights = register(ValueDef.create(n -> new LightList(null)), lights).setName("lights"); + depth = register(new TextureDef2D(w, h, Image.Format.Depth), depth); + diffuse = register(new TextureDef2D(w, h, Image.Format.RGBA16F), diffuse); + specular = register(new TextureDef2D(w, h, Image.Format.RGBA16F), specular); + emissive = register(new TextureDef2D(w, h, Image.Format.RGBA16F), emissive); + normal = register(new TextureDef2D(w, h, Image.Format.RGBA32F), normal); + lights = register(new ValueDef(LightList.class, n -> new LightList(null)), lights); + reserve(depth, diffuse, specular, emissive, normal); } @Override protected void execute(FGRenderContext context) { - // acquire and attach texture targets - frameBuffer.setDepthTarget(context.createTextureTarget(resources.acquire(depth))); + // acquire texture targets resources.acquireColorTargets(frameBuffer, diffuse, specular, emissive, normal); + resources.acquireDepthTarget(frameBuffer, depth); + context.getRenderer().setFrameBuffer(frameBuffer); + context.getRenderer().clearBuffers(true, true, true); LightList lightList = resources.acquire(lights); // render to gBuffer - context.setFrameBuffer(frameBuffer, true, true, true); context.getRenderer().setBackgroundColor(mask.set(context.getViewPort().getBackgroundColor()).setAlpha(0)); context.getRenderManager().setForcedTechnique(GBUFFER_PASS); context.getRenderManager().setGeometryRenderHandler(this); + context.getRenderer().setDepthRange(0, 1); context.renderViewPortQueue(RenderQueue.Bucket.Opaque, true); // add accumulated lights while (!accumulatedLights.isEmpty()) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputBucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java similarity index 86% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputBucketPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java index 076ab00d8a..01c4a92580 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputBucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java @@ -2,8 +2,11 @@ * 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; +package com.jme3.renderer.framegraph.passes; +import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.queue.RenderQueue.Bucket; /** @@ -30,6 +33,7 @@ protected void initialize(FrameGraph frameGraph) {} protected void prepare(FGRenderContext context) {} @Override protected void execute(FGRenderContext context) { + context.popFrameBuffer(); if (bucket == Bucket.Gui) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java similarity index 80% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java index c1fa204497..147d570fa1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/OutputPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java @@ -2,9 +2,12 @@ * 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; +package com.jme3.renderer.framegraph.passes; import com.jme3.math.ColorRGBA; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; @@ -28,7 +31,8 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { - context.transferTextures(resources.acquire(inColor, null), resources.acquire(inDepth, null)); + context.popFrameBuffer(); + context.transferTextures(resources.acquireOrElse(inColor, null), resources.acquireOrElse(inDepth, null)); } @Override protected void reset(FGRenderContext context) {} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PostProcessingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java similarity index 89% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/PostProcessingPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java index cfcd1e5a88..6a1f35e0ea 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PostProcessingPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java @@ -2,12 +2,14 @@ * 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; +package com.jme3.renderer.framegraph.passes; import com.jme3.post.SceneProcessor; import com.jme3.profile.AppProfiler; import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.util.SafeArrayList; /** @@ -24,6 +26,7 @@ protected void prepare(FGRenderContext context) {} protected void execute(FGRenderContext context) { SafeArrayList processors = context.getViewPort().getProcessors(); if (!processors.isEmpty()) { + context.popFrameBuffer(); AppProfiler prof = context.getProfiler(); if (prof != null) { prof.vpStep(VpStep.PostFrame, context.getViewPort(), null); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java similarity index 69% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index fa8384dede..7905600e0c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -2,8 +2,15 @@ * 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; +package com.jme3.renderer.framegraph.passes; +import com.jme3.renderer.framegraph.CameraSize; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceList; +import com.jme3.renderer.framegraph.ResourceProducer; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import java.util.Arrays; import java.util.LinkedList; @@ -14,13 +21,16 @@ */ public abstract class RenderPass implements ResourceProducer { - protected ResourceList resources; private final LinkedList inputs = new LinkedList<>(); private final LinkedList outputs = new LinkedList<>(); private final CameraSize camSize = new CameraSize(); + private int index = -1; private int refs = 0; + protected ResourceList resources; + protected FrameBuffer frameBuffer; - public void initializePass(FrameGraph frameGraph) { + public void initializePass(FrameGraph frameGraph, int index) { + this.index = index; this.resources = frameGraph.getResources(); initialize(frameGraph); } @@ -28,8 +38,13 @@ public void prepareRender(FGRenderContext context) { prepare(context); } public void executeRender(FGRenderContext context) { + if (camSize.update(context.getCameraSize()) || frameBuffer == null) { + if (frameBuffer != null) { + disposeFrameBuffer(frameBuffer); + } + frameBuffer = createFrameBuffer(context); + } execute(context); - context.popRenderSettings(); releaseAll(); } public void resetRender(FGRenderContext context) { @@ -47,21 +62,34 @@ public void cleanupPass(FrameGraph frameGraph) { protected abstract void reset(FGRenderContext context); protected abstract void cleanup(FrameGraph frameGraph); + protected FrameBuffer createFrameBuffer(FGRenderContext context) { + return null; + } + protected void disposeFrameBuffer(FrameBuffer fb) { + fb.dispose(); + } + protected ResourceTicket register(ResourceDef def, ResourceTicket ticket) { ticket = resources.register(this, def, ticket); addOutput(ticket); return ticket; } + protected void reserve(ResourceTicket ticket) { + resources.reserve(index, ticket); + } + protected void reserve(ResourceTicket... tickets) { + resources.reserve(index, tickets); + } protected void reference(ResourceTicket ticket) { - resources.reference(ticket); + resources.reference(index, ticket); addInput(ticket); } protected void reference(ResourceTicket... tickets) { - resources.reference(tickets); + resources.reference(index, tickets); addInputs(tickets); } protected boolean referenceOptional(ResourceTicket ticket) { - if (resources.referenceOptional(ticket)) { + if (resources.referenceOptional(index, ticket)) { addInput(ticket); return true; } @@ -96,7 +124,14 @@ protected ResourceTicket addOutput(ResourceTicket output) { public void countReferences() { refs = outputs.size(); } + public boolean isAssigned() { + return index >= 0; + } + @Override + public int getIndex() { + return index; + } @Override public boolean dereference() { refs--; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java similarity index 81% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/TileDeferredPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index 348b4cf96c..14a58d8915 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java @@ -2,15 +2,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; +package com.jme3.renderer.framegraph.passes; import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.material.TechniqueDef; import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic; import com.jme3.material.logic.TiledRenderGrid; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef2D; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; +import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; /** @@ -22,7 +27,6 @@ public class TileDeferredPass extends RenderPass { private ResourceTicket diffuse, specular, emissive, normal, depth, outColor; private ResourceTicket lights; private ResourceTicket tiles; - private ResourceTicket frameBuffer; private Material material; private final TiledRenderGrid tileInfo = new TiledRenderGrid(); @@ -41,12 +45,10 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { - FrameBuffer fb = resources.acquire(frameBuffer); - fb.clearColorTargets(); - fb.setDepthTarget((FrameBuffer.FrameBufferTextureTarget)null); - resources.acquireColorTargets(fb, outColor); - context.setFrameBuffer(fb, true, true, true); - TiledRenderGrid trg = resources.acquire(tiles, null); + resources.acquireColorTargets(frameBuffer, outColor); + context.getRenderer().setFrameBuffer(frameBuffer); + context.getRenderer().clearBuffers(true, true, true); + TiledRenderGrid trg = resources.acquireOrElse(tiles, null); if (trg != null) { tileInfo.copyFrom(trg); } @@ -57,18 +59,21 @@ protected void execute(FGRenderContext context) { material.setTexture("Context_InGBuff3", resources.acquire(normal)); material.setTexture("Context_InGBuff4", resources.acquire(depth)); material.selectTechnique("TileBasedDeferredPass", context.getRenderManager()); - LightList lightList = resources.acquire(lights, null); + LightList lightList = resources.acquireOrElse(lights, null); if (lightList != null) { context.getScreen().render(context.getRenderManager(), material, lightList); } else { context.renderFullscreen(material); } - fb.clearColorTargets(); } @Override protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} + @Override + protected FrameBuffer createFrameBuffer(FGRenderContext context) { + return new FrameBuffer(context.getWidth(), context.getHeight(), 1); + } public void setDiffuse(ResourceTicket diffuse) { this.diffuse = diffuse; diff --git a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java index 4cefa6ab6f..c33446a977 100644 --- a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java +++ b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java @@ -260,12 +260,32 @@ public void addColorTarget(FrameBufferBufferTarget colorBuf){ colorBuf.slot=colorBufs.size(); colorBufs.add(colorBuf); } - + public void addColorTarget(FrameBufferTextureTarget colorBuf){ // checkSetTexture(colorBuf.getTexture(), false); // TODO: this won't work for levels. colorBuf.slot=colorBufs.size(); colorBufs.add(colorBuf); } + + /** + * Sets the color target at the index. + * + * @param i + * @param colorBuf + */ + public void setColorTarget(int i, FrameBufferTextureTarget colorBuf) { + colorBuf.slot = i; + colorBufs.set(i, colorBuf); + } + + /** + * Removes all color targets stored at indices above the specified index. + * + * @param i + */ + public void removeColorTargetsAbove(int i) { + colorBufs.removeIf(rb -> rb.slot > i); + } /** * Adds a texture to one of the color Buffers Array. It uses {@link TextureCubeMap} ordinal number for the diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index b064fb19e2..7ed16d2e8f 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -14,7 +14,6 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.DeferredGraphConstructor; -import com.jme3.renderer.framegraph.ForwardGraphConstructor; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; @@ -133,7 +132,6 @@ public void simpleInitApp() { // 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)); - //fpp.addFilter(new DepthDebugFilter()); viewPort.addProcessor(fpp); DirectionalLightShadowRenderer dr = new DirectionalLightShadowRenderer(assetManager, 1024, 2); @@ -157,7 +155,6 @@ public void simpleInitApp() { @Override public void simpleUpdate(float tpf) { cam.lookAt(new Vector3f(), Vector3f.UNIT_Y); - System.out.println("------------------- FRAME"); } @Override @@ -175,23 +172,4 @@ public void simpleRender(RenderManager rm) { } } - private class DepthDebugFilter extends Filter { - - @Override - protected void initFilter(AssetManager assetManager, RenderManager renderManager, ViewPort vp, int w, int h) { - material = new Material(assetManager, "Common/MatDefs/Post/DepthDebug.j3md"); - } - - @Override - protected Material getMaterial() { - return material; - } - - @Override - protected boolean isRequiresDepthTexture() { - return true; - } - - } - } From 5bbe40f8f959428789b6aa107871dccb75f7bf02 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 7 May 2024 11:35:55 -0400 Subject: [PATCH 052/111] rename registration method --- .../main/java/com/jme3/renderer/framegraph/ResourceList.java | 2 +- .../java/com/jme3/renderer/framegraph/passes/RenderPass.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 6e4a8f124d..16a136e47a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -77,7 +77,7 @@ protected RenderResource remove(int index) { return prev; } - public ResourceTicket register(ResourceProducer producer, ResourceDef def, ResourceTicket store) { + public ResourceTicket declare(ResourceProducer producer, ResourceDef def, ResourceTicket store) { return create(producer, def).getTicket().copyIndexTo(store); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 7905600e0c..92aa3fb1cc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -70,7 +70,7 @@ protected void disposeFrameBuffer(FrameBuffer fb) { } protected ResourceTicket register(ResourceDef def, ResourceTicket ticket) { - ticket = resources.register(this, def, ticket); + ticket = resources.declare(this, def, ticket); addOutput(ticket); return ticket; } From 86a458bbc17b60a237d879063c00747c3e386994 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 7 May 2024 17:31:16 -0400 Subject: [PATCH 053/111] renamed method --- .../jme3/renderer/framegraph/passes/BucketPass.java | 4 ++-- .../renderer/framegraph/passes/DeferredPass.java | 2 +- .../jme3/renderer/framegraph/passes/GBufferPass.java | 12 ++++++------ .../jme3/renderer/framegraph/passes/RenderPass.java | 2 +- .../renderer/framegraph/passes/TileDeferredPass.java | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 6851fbe852..747693d313 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -47,8 +47,8 @@ protected void initialize(FrameGraph frameGraph) { protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - outColor = register(new TextureDef2D(w, h, samples, Image.Format.RGBA8), outColor); - outDepth = register(new TextureDef2D(w, h, samples, Image.Format.Depth), outDepth); + outColor = declare(new TextureDef2D(w, h, samples, Image.Format.RGBA8), outColor); + outDepth = declare(new TextureDef2D(w, h, samples, Image.Format.Depth), outDepth); referenceOptional(inColor, inDepth); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index cd4152a596..30dcc84b2b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -37,7 +37,7 @@ protected void initialize(FrameGraph frameGraph) { protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - outColor = register(new TextureDef2D(w, h, Image.Format.RGBA8), outColor); + outColor = declare(new TextureDef2D(w, h, Image.Format.RGBA8), outColor); reserve(outColor); reference(depth, diffuse, specular, emissive, normal); referenceOptional(lights); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 55256335f2..8d8c829179 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -41,12 +41,12 @@ protected void initialize(FrameGraph frameGraph) {} protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - depth = register(new TextureDef2D(w, h, Image.Format.Depth), depth); - diffuse = register(new TextureDef2D(w, h, Image.Format.RGBA16F), diffuse); - specular = register(new TextureDef2D(w, h, Image.Format.RGBA16F), specular); - emissive = register(new TextureDef2D(w, h, Image.Format.RGBA16F), emissive); - normal = register(new TextureDef2D(w, h, Image.Format.RGBA32F), normal); - lights = register(new ValueDef(LightList.class, n -> new LightList(null)), lights); + depth = declare(new TextureDef2D(w, h, Image.Format.Depth), depth); + diffuse = declare(new TextureDef2D(w, h, Image.Format.RGBA16F), diffuse); + specular = declare(new TextureDef2D(w, h, Image.Format.RGBA16F), specular); + emissive = declare(new TextureDef2D(w, h, Image.Format.RGBA16F), emissive); + normal = declare(new TextureDef2D(w, h, Image.Format.RGBA32F), normal); + lights = declare(new ValueDef(LightList.class, n -> new LightList(null)), lights); reserve(depth, diffuse, specular, emissive, normal); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 92aa3fb1cc..15a708c5c6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -69,7 +69,7 @@ protected void disposeFrameBuffer(FrameBuffer fb) { fb.dispose(); } - protected ResourceTicket register(ResourceDef def, ResourceTicket ticket) { + protected ResourceTicket declare(ResourceDef def, ResourceTicket ticket) { ticket = resources.declare(this, def, ticket); addOutput(ticket); return ticket; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index 14a58d8915..0d8fd2408d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java @@ -39,7 +39,7 @@ protected void initialize(FrameGraph frameGraph) { } @Override protected void prepare(FGRenderContext context) { - outColor = register(new TextureDef2D(context.getWidth(), context.getHeight(), Image.Format.RGBA8), outColor); + outColor = declare(new TextureDef2D(context.getWidth(), context.getHeight(), Image.Format.RGBA8), outColor); reference(diffuse, specular, emissive, normal, depth); referenceOptional(lights, tiles); } From f68d0ea86adf43ae42882539228e9882370abf6b Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 7 May 2024 18:49:41 -0400 Subject: [PATCH 054/111] delete personal changelog --- CodexChangeLog.txt | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 CodexChangeLog.txt diff --git a/CodexChangeLog.txt b/CodexChangeLog.txt deleted file mode 100644 index 6084df7ae7..0000000000 --- a/CodexChangeLog.txt +++ /dev/null @@ -1,7 +0,0 @@ - -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. - From 1e0af2557abf5041ce0c717556cbe265c12a674d Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 8 May 2024 06:56:42 -0400 Subject: [PATCH 055/111] remove enums --- .../java/com/jme3/material/TechniqueDef.java | 55 ------------------- .../java/com/jme3/renderer/RenderManager.java | 23 -------- .../main/java/com/jme3/renderer/ViewPort.java | 14 ----- .../Common/MatDefs/Light/Lighting.j3md | 4 +- .../Common/MatDefs/Light/PBRLighting.j3md | 4 +- .../Common/MatDefs/Misc/Unshaded.j3md | 6 +- .../ShadingCommon/DeferredShading.j3md | 2 - .../TileBasedDeferredShading.j3md | 2 - .../com/jme3/material/plugins/J3MLoader.java | 13 +---- 9 files changed, 8 insertions(+), 115 deletions(-) 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 f8b1355f31..dce83fb022 100644 --- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java +++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java @@ -62,47 +62,6 @@ 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. */ @@ -215,7 +174,6 @@ public enum LightSpace { private LightMode lightMode = LightMode.Disable; private ShadowMode shadowMode = ShadowMode.Disable; - private Pipeline pipeline = Pipeline.Forward; private TechniqueDefLogic logic; private ArrayList worldBinds; @@ -299,19 +257,6 @@ 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; } 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 8d411b3e12..f9c493522c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -82,29 +82,6 @@ */ public class RenderManager { - // 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 final Renderer renderer; private final UniformBindingManager uniformBindingManager = new UniformBindingManager(); private final ArrayList preViewPorts = new ArrayList<>(); 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 936f4bcf2d..4fdc167357 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java +++ b/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java @@ -112,8 +112,6 @@ 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:
    *

      @@ -131,18 +129,6 @@ 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/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md index 386b1c8996..70991f2da3 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md @@ -261,8 +261,8 @@ MaterialDef Phong Lighting { } - Technique GBufferPass{ - Pipeline Deferred + Technique GBufferPass { + VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/Light/LightingGBufferPack.vert FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/Light/LightingGBufferPack.frag 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 ee88826407..c9b419dd76 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md @@ -217,8 +217,8 @@ MaterialDef PBR Lighting { } - Technique GBufferPass{ - Pipeline Deferred + Technique GBufferPass { + VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/Light/PBRLightingGBufferPack.vert FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/Light/PBRLightingGBufferPack.frag 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 7af5add5b9..d0066f23de 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md @@ -92,9 +92,9 @@ MaterialDef Unshaded { } } - Technique GBufferPass{ - Pipeline Deferred - VertexShader GLSL310 GLSL300 GLSL150 GLSL100 : Common/MatDefs/Misc/Unshaded.vert + Technique GBufferPass { + + VertexShader GLSL310 GLSL300 GLSL150 GLSL100 : Common/MatDefs/Misc/Unshaded.vert FragmentShader GLSL310 GLSL300 GLSL150 GLSL100 : Common/MatDefs/Misc/UnshadedGBufferPack.frag WorldParameters { 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 d89b62495a..2e76ec0cd8 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md @@ -21,8 +21,6 @@ MaterialDef DeferredShading { } Technique DeferredPass { - - Pipeline Deferred VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/DeferredShading.vert FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/DeferredShading.frag 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 ba76966374..07c033ab5e 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md @@ -25,8 +25,6 @@ MaterialDef DeferredShading { } Technique TileBasedDeferredPass { - - Pipeline Deferred VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/DeferredShading.vert FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag 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 6c30e710f7..9ce2a09ca1 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 @@ -121,17 +121,6 @@ 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); @@ -578,7 +567,7 @@ private void readTechniqueStatement(Statement statement) throws IOException{ split[0].equals("TessellationEvaluationShader")) { readShaderStatement(statement.getLine()); }else if(split[0].equals("Pipeline")){ - readPipeline(statement.getLine()); + throw new UnsupportedOperationException("Pipeline statement is not supported."); }else if (split[0].equals("LightMode")){ readLightMode(statement.getLine()); }else if (split[0].equals("LightSpace")){ From 9ff4f5d0486c1e09e11fa9c393b09ed83321cefa Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 9 May 2024 09:28:23 -0400 Subject: [PATCH 056/111] added information management passes --- .../renderer/framegraph/RenderObject.java | 25 ++-- .../renderer/framegraph/RenderObjectMap.java | 17 ++- .../renderer/framegraph/RenderResource.java | 4 +- .../renderer/framegraph/ResourceList.java | 60 +++++---- .../renderer/framegraph/ResourceTicket.java | 115 +++++++++--------- .../renderer/framegraph/TestConstructor.java | 39 ------ .../framegraph/definitions/ResourceDef.java | 38 ++++++ .../framegraph/definitions/ValueDef.java | 13 +- .../renderer/framegraph/passes/Attribute.java | 58 +++++++++ .../framegraph/passes/BucketPass.java | 25 +--- .../renderer/framegraph/passes/Junction.java | 38 ++++++ .../framegraph/passes/RenderPass.java | 29 ++++- .../java/com/jme3/texture/FrameBuffer.java | 2 +- 13 files changed, 302 insertions(+), 161 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java index ca450a7137..f47e587ecc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java @@ -4,6 +4,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.util.NativeObject; import java.util.BitSet; import java.util.function.Consumer; @@ -22,19 +23,25 @@ public class RenderObject { private final int id; private final T object; - private final int timeoutDuration; + private int timeoutDuration; private int timeout = 0; private boolean acquired = false; private final BitSet reservations = new BitSet(); - private final Consumer disposer; + private Consumer disposer; - public RenderObject(T object, int timeout, Consumer disposer) { + public RenderObject(ResourceDef def, T object, int timeout) { this.id = nextId++; + if (object == null) { + throw new NullPointerException("Object cannot be null."); + } this.object = object; - this.timeoutDuration = timeout; - if (disposer != null) { - this.disposer = disposer; - } else if (object instanceof NativeObject) { + this.timeoutDuration = def.getStaticTimeout(); + if (this.timeoutDuration < 0) { + this.timeoutDuration = timeout; + } + disposer = def.getDisposalMethod(); + if (disposer != null); + else if (object instanceof NativeObject) { this.disposer = NATIVE; } else { this.disposer = DEFAULT; @@ -42,7 +49,7 @@ public RenderObject(T object, int timeout, Consumer disposer) { } public boolean acquire(TimeFrame time, boolean reserved) { - if (acquired || (!reserved && isReservedWithin(time))) { + if (acquired || (!reserved && isReserved(time))) { return false; } acquire(); @@ -81,7 +88,7 @@ public T getObject() { public boolean isAcquired() { return acquired; } - public boolean isReservedWithin(TimeFrame frame) { + public boolean isReserved(TimeFrame frame) { if (frame.getStartIndex() >= reservations.size()) { return false; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 465459b91c..269d042899 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -18,7 +18,10 @@ public class RenderObjectMap { private final int timeout = 1; protected RenderObject create(ResourceDef def) { - RenderObject obj = new RenderObject(def.createResource(), timeout, def.getDisposalMethod()); + return create(def, def.createResource()); + } + protected RenderObject create(ResourceDef def, T value) { + RenderObject obj = new RenderObject(def, value, timeout); objectMap.put(obj.getId(), obj); return obj; } @@ -42,7 +45,8 @@ public void allocate(RenderResource resource) { } } for (RenderObject obj : objectMap.values()) { - if (!obj.isAcquired() && !obj.isReservedWithin(resource.getLifeTime()) + if (!obj.isAcquired() + && !obj.isReserved(resource.getLifeTime()) && applyToResource(resource, obj)) { return; } @@ -59,6 +63,15 @@ public boolean reserve(int objectId, int index) { } return false; } + public void dispose(RenderResource resource) { + int id = resource.getTicket().getObjectId(); + if (id >= 0) { + RenderObject obj = objectMap.remove(id); + if (obj != null) { + obj.dispose(); + } + } + } public void clearReservations() { for (RenderObject obj : objectMap.values()) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 34e043b0c6..0db86e3403 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -68,7 +68,7 @@ public T getResource() { return object.getObject(); } public int getIndex() { - return ticket.getIndex(); + return ticket.getWorldIndex(); } public int getNumReferences() { return refs; @@ -86,7 +86,7 @@ public boolean isUsed() { @Override public String toString() { - return "RenderResource[index="+ticket.getIndex()+"]"; + return "RenderResource[index="+ticket.getWorldIndex()+"]"; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 16a136e47a..5d003ea9e0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -11,33 +11,34 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.logging.Logger; /** * * @author codex */ public class ResourceList { - + private static final int INITIAL_SIZE = 20; - private RenderObjectMap map; + private final RenderObjectMap map; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); private int nextSlot = 0; - public ResourceList(RenderObjectMap recycler) { - this.map = recycler; + public ResourceList(RenderObjectMap map) { + this.map = map; } protected RenderResource create(ResourceProducer producer, ResourceDef def) { RenderResource res = new RenderResource<>(producer, def, new ResourceTicket<>()); - res.getTicket().setIndex(add(res)); + res.getTicket().setLocalIndex(add(res)); return res; } protected RenderResource locate(ResourceTicket ticket) { if (ticket == null) { throw new NullPointerException("Ticket cannot be null."); } - final int i = ticket.getIndex(); + final int i = ticket.getWorldIndex(); if (i >= 0 && i < resources.size()) { RenderResource res = resources.get(i); if (res != null) { @@ -84,7 +85,7 @@ public ResourceTicket declare(ResourceProducer producer, ResourceDef d public void reserve(int passIndex, ResourceTicket ticket) { if (ticket.getObjectId() >= 0) { map.reserve(ticket.getObjectId(), passIndex); - locate(ticket).getTicket().setObjectId(ticket.getObjectId()); + ticket.copyObjectTo(locate(ticket).getTicket()); } } public void reserve(int passIndex, ResourceTicket... tickets) { @@ -97,7 +98,7 @@ public void reference(int passIndex, ResourceTicket ticket) { locate(ticket).reference(passIndex); } public boolean referenceOptional(int passIndex, ResourceTicket ticket) { - if (ticket != null) { + if (ticket != null && ticket.getWorldIndex() >= 0) { reference(passIndex, ticket); return true; } @@ -130,7 +131,7 @@ public T acquire(ResourceTicket ticket) { if (resource.isVirtual()) { map.allocate(resource); } - ticket.setObjectId(resource.getObject().getId()); + resource.getTicket().copyObjectTo(ticket); return resource.getResource(); } public T acquireOrElse(ResourceTicket ticket, T value) { @@ -139,14 +140,13 @@ public T acquireOrElse(ResourceTicket ticket, T value) { } return value; } - public void acquireColorTargets(FrameBuffer fbo, ResourceTicket... tickets) { if (tickets.length == 0) { fbo.clearColorTargets(); return; } if (tickets.length < fbo.getNumColorTargets()) { - fbo.removeColorTargetsAbove(tickets.length-1); + fbo.trimColorTargetsTo(tickets.length-1); } int i = 0; for (int n = Math.min(fbo.getNumColorTargets(), tickets.length); i < n; i++) { @@ -172,13 +172,16 @@ public void release(ResourceTicket ticket) { RenderResource res = locate(ticket); res.release(); if (!res.isUsed()) { - remove(ticket.getIndex()); + remove(ticket.getWorldIndex()); res.getObject().release(); res.setObject(null); + if (res.getDefinition().isDisposeOnRelease()) { + map.dispose(res); + } } } public boolean releaseOptional(ResourceTicket ticket) { - if (ticket != null) { + if (ticket != null && ticket.getWorldIndex() >= 0) { release(ticket); return true; } @@ -206,23 +209,26 @@ public void cullUnreferenced() { while ((resource = cull.pollFirst()) != null) { // dereference producer of resource ResourceProducer producer = resource.getProducer(); - if (producer != null) { - if (!producer.dereference()) { - // if producer is not referenced, dereference all input resources - for (ResourceTicket t : resource.getProducer().getInputTickets()) { - RenderResource r = locate(t); - r.release(); - if (!r.isReferenced()) { - cull.addLast(r); - } + if (producer == null) { + remove(resource.getIndex()); + continue; + } + if (!producer.dereference()) { + // if producer is not referenced, dereference all input resources + for (ResourceTicket t : producer.getInputTickets()) { + if (t.getWorldIndex() < 0) { + continue; } - // remove all output resources - for (ResourceTicket t : resource.getProducer().getOutputTickets()) { - remove(t.getIndex()); + RenderResource r = locate(t); + r.release(); + if (!r.isReferenced()) { + cull.addLast(r); } } - } else { - remove(resource.getIndex()); + // remove all output resources + for (ResourceTicket t : producer.getOutputTickets()) { + remove(t.getWorldIndex()); + } } } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index 3251cceebd..d4f6980d58 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -4,12 +4,15 @@ */ package com.jme3.renderer.framegraph; +import java.util.ArrayList; +import java.util.Objects; + /** * References a {@link RenderResource} by either name or index. *

      - * If a resource is referenced by name, the index of the resource - * will be assigned to the ticket, in order to make future references - * faster. + If a resource is referenced by name, the index of the resource + will be assigned to the ticket, in order to make future references + faster. * * @author codex * @param @@ -20,8 +23,10 @@ public class ResourceTicket { private final long id; private String name; - private int index; - private int objectId; + private int localIndex; + private int objectId = -1; + private int sourceIndex = 0; + private ArrayList> sources; public ResourceTicket() { this(null, -1); @@ -35,88 +40,88 @@ public ResourceTicket(int index) { public ResourceTicket(String name, int index) { this.id = nextId++; this.name = name; - this.index = index; + this.localIndex = index; + } + + public int addSource(ResourceTicket source) { + if (sources == null) { + sources = new ArrayList<>(1); + } + if (sources.add(source)) { + return sources.size()-1; + } + return -1; + } + public boolean removeSource(ResourceTicket source) { + return sources.remove(source); + } + public void clearSources() { + sources.clear(); } - /** - * Copies this ticket's info to the target. - *

      - * If the target is null, a new instance will be created and - * written to. - * - * @param target copy target (can be null) - * @return target - */ public ResourceTicket copyIndexTo(ResourceTicket target) { if (target == null) { target = new ResourceTicket(); } - target.index = index; + return target.setLocalIndex(localIndex); + } + public ResourceTicket copyObjectTo(ResourceTicket target) { + if (target == null) { + target = new ResourceTicket(); + } + target.setObjectId(objectId); return target; } - /** - * Sets the name of this ticket. - *

      - * Names are used to locate a particular ticket among a group. - * - * @param name - * @return this ticket instance - */ public ResourceTicket setName(String name) { this.name = name; return this; } - - /** - * Sets the index. - * - * @param index - * @return this instance - */ - protected ResourceTicket setIndex(int index) { - this.index = index; + protected ResourceTicket setLocalIndex(int index) { + this.localIndex = index; return this; } - public void setObjectId(int objectId) { this.objectId = objectId; } + public boolean setSourceIndex(int sourceIndex) { + this.sourceIndex = sourceIndex; + return this.sourceIndex >= 0 && this.sourceIndex < sources.size(); + } - /** - * Gets the id unique to this ticket. - * - * @return - */ public long getId() { return id; } - - /** - * Gets the name of this ticket. - * - * @return - */ public String getName() { return name; } - - /** - * Gets the resource index. - * - * @return - */ - public int getIndex() { - return index; + public int getWorldIndex() { + ResourceTicket src = getCurrentSource(); + if (src != null) { + int i = src.getWorldIndex(); + if (i >= 0) return i; + } + return localIndex; + } + public int getLocalIndex() { + return localIndex; } - public int getObjectId() { return objectId; } + public ResourceTicket getCurrentSource() { + if (sourceIndex >= 0 && sourceIndex < sources.size()) { + return sources.get(sourceIndex); + } + return null; + } + public ArrayList> getSources() { + return sources; + } @Override public String toString() { - return "Ticket[id="+id+", name="+name+", index="+index+"]"; + return "Ticket[id="+id+", name="+name+", index="+localIndex+"]"; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java deleted file mode 100644 index de156813d7..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TestConstructor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.framegraph.passes.BucketPass; -import com.jme3.renderer.framegraph.passes.OutputPass; -import com.jme3.renderer.queue.RenderQueue.Bucket; - -/** - * - * @author codex - */ -public class TestConstructor implements GraphConstructor { - - private BucketPass opaque, sky; - private OutputPass result; - - @Override - public void addPasses(FrameGraph frameGraph) { - opaque = frameGraph.add(new BucketPass(Bucket.Opaque)); - sky = frameGraph.add(new BucketPass(Bucket.Sky, DepthRange.REAR)); - result = frameGraph.add(new OutputPass()); - } - @Override - public void preparePasses(FGRenderContext context) { - //opaque.setInput(sky); - opaque.prepareRender(context); - sky.setInput(opaque); - sky.prepareRender(context); - //result.setInColor(opaque.getOutColor()); - //result.setInDepth(opaque.getOutDepth()); - result.setInColor(sky.getOutColor()); - result.setInDepth(sky.getOutDepth()); - result.prepareRender(context); - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index 3ab057b13a..5d454960c5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -13,12 +13,50 @@ */ public interface ResourceDef { + /** + * Creates a new resources from scratch. + * + * @return + */ public T createResource(); + /** + * Repurposes the given resource. + * + * @param resource + * @return repurposed resource, or null if the given resource is not usable. + */ public T applyResource(Object resource); + /** + * Gets the Consumer used to dispose of a resource. + * + * @return resource disposer, or null + */ public default Consumer getDisposalMethod() { return null; } + /** + * Returns true if the resource should be disposed after being + * released and having no users. + * + * @return + */ + public default boolean isDisposeOnRelease() { + return false; + } + + /** + * Returns the number of frames which the resource must be + * static (unused throughout rendering) before it is disposed. + *

      + * If negative, the default timeout value will be used instead. + * + * @return static timeout duration + */ + public default int getStaticTimeout() { + return -1; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java index 91ff7dc1d2..93de7eed27 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java @@ -17,7 +17,8 @@ public class ValueDef implements ResourceDef { private final Class type; private Function create; private Consumer reset; - + private boolean dispose = false; + public ValueDef(Class type, Function create) { this.type = type; this.create = create; @@ -36,6 +37,10 @@ public T applyResource(Object resource) { } return null; } + @Override + public boolean isDisposeOnRelease() { + return dispose; + } public void setCreate(Function create) { this.create = create; @@ -43,6 +48,9 @@ public void setCreate(Function create) { public void setReset(Consumer reset) { this.reset = reset; } + public void setDispose(boolean dispose) { + this.dispose = dispose; + } public Class getType() { return type; @@ -53,5 +61,8 @@ public Function getCreate() { public Consumer getReset() { return reset; } + public boolean isDispose() { + return dispose; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java new file mode 100644 index 0000000000..6bdabdd96d --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -0,0 +1,58 @@ +/* + * 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.passes; + +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.ValueDef; +import java.util.function.Function; + +/** + * + * @author codex + * @param + */ +public class Attribute extends RenderPass implements Function { + + private ResourceTicket ticket; + private ValueDef def; + private T value; + + @Override + protected void initialize(FrameGraph frameGraph) { + ticket = addOutput("Attribute"); + def = new ValueDef<>(null, this); + def.setDispose(true); + } + @Override + protected void prepare(FGRenderContext context) { + declare(def, ticket); + } + @Override + protected void execute(FGRenderContext context) { + resources.acquire(ticket); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + public T apply(Object t) { + if (value == null) { + throw new NullPointerException("Attribute value cannot be null."); + } + return value; + } + + public void setValue(T value) { + this.value = value; + } + + public T getValue() { + return value; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 747693d313..5660c3b2ed 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -11,7 +11,6 @@ import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.queue.RenderQueue.Bucket; -import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; @@ -42,13 +41,17 @@ public BucketPass(Bucket bucket, DepthRange depth) { @Override protected void initialize(FrameGraph frameGraph) { fTex = (Texture2D)frameGraph.getAssetManager().loadTexture("Common/Textures/MissingTexture.png"); + inColor = addInput("InColor"); + inDepth = addInput("InDepth"); + outColor = addOutput("OutDepth"); + outDepth = addOutput("OutDepth"); } @Override protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - outColor = declare(new TextureDef2D(w, h, samples, Image.Format.RGBA8), outColor); - outDepth = declare(new TextureDef2D(w, h, samples, Image.Format.Depth), outDepth); + declare(new TextureDef2D(w, h, samples, Image.Format.RGBA8), outColor); + declare(new TextureDef2D(w, h, samples, Image.Format.Depth), outDepth); referenceOptional(inColor, inDepth); } @Override @@ -76,26 +79,10 @@ protected void cleanup(FrameGraph frameGraph) {} public void setDepthRange(DepthRange depth) { this.depth = depth; } - public void setInColor(ResourceTicket inColor) { - this.inColor = inColor; - } - public void setInDepth(ResourceTicket inDepth) { - this.inDepth = inDepth; - } - public void setInput(BucketPass pass) { - inColor = pass.outColor.copyIndexTo(null); - inDepth = pass.outDepth.copyIndexTo(null); - } public DepthRange getDepthRange() { return depth; } - public ResourceTicket getOutColor() { - return outColor; - } - public ResourceTicket getOutDepth() { - return outDepth; - } @Override public String toString() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java new file mode 100644 index 0000000000..754d7c72f3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -0,0 +1,38 @@ +/* + * 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.passes; + +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; + +/** + * + * @author codex + */ +public class Junction extends RenderPass { + + private ResourceTicket ticket; + + @Override + protected void initialize(FrameGraph frameGraph) { + ticket = addInput(addOutput("Junction")); + } + @Override + protected void prepare(FGRenderContext context) { + referenceOptional(ticket); + } + @Override + protected void execute(FGRenderContext context) {} + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + + public boolean setIndex(int index) { + return ticket.setSourceIndex(index); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 15a708c5c6..73b79ad279 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -49,11 +49,11 @@ public void executeRender(FGRenderContext context) { } public void resetRender(FGRenderContext context) { reset(context); - inputs.clear(); - outputs.clear(); } public void cleanupPass(FrameGraph frameGraph) { cleanup(frameGraph); + inputs.clear(); + outputs.clear(); } protected abstract void initialize(FrameGraph frameGraph); @@ -71,7 +71,7 @@ protected void disposeFrameBuffer(FrameBuffer fb) { protected ResourceTicket declare(ResourceDef def, ResourceTicket ticket) { ticket = resources.declare(this, def, ticket); - addOutput(ticket); + //addOutput(ticket); return ticket; } protected void reserve(ResourceTicket ticket) { @@ -82,15 +82,15 @@ protected void reserve(ResourceTicket... tickets) { } protected void reference(ResourceTicket ticket) { resources.reference(index, ticket); - addInput(ticket); + //addInput(ticket); } protected void reference(ResourceTicket... tickets) { resources.reference(index, tickets); - addInputs(tickets); + //addInputs(tickets); } protected boolean referenceOptional(ResourceTicket ticket) { if (resources.referenceOptional(index, ticket)) { - addInput(ticket); + //addInput(ticket); return true; } return false; @@ -121,6 +121,23 @@ protected ResourceTicket addOutput(ResourceTicket output) { return output; } + protected ResourceTicket addInput(String name) { + return addInput(new ResourceTicket<>(name)); + } + protected ResourceTicket addOutput(String name) { + return addOutput(new ResourceTicket<>(name)); + } + + public ResourceTicket connectToOutput(String name, ResourceTicket ticket) { + for (ResourceTicket t : outputs) { + if (name.equals(t.getName())) { + ticket.addSource(t); + return t; + } + } + return null; + } + public void countReferences() { refs = outputs.size(); } diff --git a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java index c33446a977..f1a9a97140 100644 --- a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java +++ b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java @@ -283,7 +283,7 @@ public void setColorTarget(int i, FrameBufferTextureTarget colorBuf) { * * @param i */ - public void removeColorTargetsAbove(int i) { + public void trimColorTargetsTo(int i) { colorBufs.removeIf(rb -> rb.slot > i); } From 8a39bf0ae4c30a068c3ce8e2c438712c0acc5c48 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 9 May 2024 10:10:27 -0400 Subject: [PATCH 057/111] migrated to new ticket protocol --- .../renderer/framegraph/RenderResource.java | 15 ++++++++++++- .../renderer/framegraph/ResourceList.java | 20 +++++++++++++---- .../framegraph/definitions/ResourceDef.java | 9 ++++++++ .../framegraph/definitions/ValueDef.java | 19 +++++++++++++--- .../renderer/framegraph/passes/Attribute.java | 10 +++++---- .../framegraph/passes/DeferredPass.java | 8 ++++++- .../framegraph/passes/GBufferPass.java | 22 +++++++++++++------ .../framegraph/passes/OutputPass.java | 4 ++-- .../framegraph/passes/TileDeferredPass.java | 9 +++++++- 9 files changed, 93 insertions(+), 23 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 0db86e3403..7c8f0260fc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -20,6 +20,7 @@ public class RenderResource { private RenderObject object; private int refs = 0; private int timeout = 0; + private boolean undefined = false; public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { this.producer = producer; @@ -43,11 +44,20 @@ public void setTimeout(int timeout) { this.timeout = timeout; } public void setObject(RenderObject object) { + if (undefined) { + throw new IllegalStateException("Resource is already undefined."); + } this.object = object; if (this.object != null) { ticket.setObjectId(this.object.getId()); } } + public void setUndefined() { + if (object != null) { + throw new IllegalArgumentException("Resource is already defined."); + } + undefined = true; + } public ResourceProducer getProducer() { return producer; @@ -75,7 +85,7 @@ public int getNumReferences() { } public boolean isVirtual() { - return object == null; + return object == null && !undefined; } public boolean isReferenced() { return refs > 0; @@ -83,6 +93,9 @@ public boolean isReferenced() { public boolean isUsed() { return refs >= 0; } + public boolean isUndefined() { + return undefined; + } @Override public String toString() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 5d003ea9e0..ec5c3a7ac2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -122,9 +122,11 @@ public > R getDefinition(Class type, ResourceTick } return null; } + public void markUndefined(ResourceTicket ticket) { + locate(ticket).setUndefined(); + } - public T acquire(ResourceTicket ticket) { - RenderResource resource = locate(ticket); + protected T acquire(RenderResource resource, ResourceTicket ticket) { if (!resource.isUsed()) { throw new IllegalStateException(resource+" was unexpectedly acquired."); } @@ -134,9 +136,19 @@ public T acquire(ResourceTicket ticket) { resource.getTicket().copyObjectTo(ticket); return resource.getResource(); } + public T acquire(ResourceTicket ticket) { + RenderResource resource = locate(ticket); + if (resource.isUndefined()) { + throw new NullPointerException("Resource is undefined."); + } + return acquire(resource, ticket); + } public T acquireOrElse(ResourceTicket ticket, T value) { - if (ticket != null) { - return acquire(ticket); + if (ticket != null && ticket.getWorldIndex() >= 0) { + RenderResource resource = locate(ticket); + if (!resource.isUndefined()) { + return acquire(resource, ticket); + } } return value; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index 5d454960c5..f0c382dbd7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -37,6 +37,15 @@ public default Consumer getDisposalMethod() { return null; } + /** + * Returns true if resources can be reallocated to this definition. + * + * @return + */ + public default boolean isUseExisting() { + return true; + } + /** * Returns true if the resource should be disposed after being * released and having no users. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java index 93de7eed27..5d36ecdb69 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java @@ -17,6 +17,8 @@ public class ValueDef implements ResourceDef { private final Class type; private Function create; private Consumer reset; + private Consumer disposal; + private boolean useExisting = true; private boolean dispose = false; public ValueDef(Class type, Function create) { @@ -38,6 +40,14 @@ public T applyResource(Object resource) { return null; } @Override + public Consumer getDisposalMethod() { + return disposal; + } + @Override + public boolean isUseExisting() { + return useExisting; + } + @Override public boolean isDisposeOnRelease() { return dispose; } @@ -48,6 +58,12 @@ public void setCreate(Function create) { public void setReset(Consumer reset) { this.reset = reset; } + public void setDisposal(Consumer disposal) { + this.disposal = disposal; + } + public void setUseExisting(boolean useExisting) { + this.useExisting = useExisting; + } public void setDispose(boolean dispose) { this.dispose = dispose; } @@ -61,8 +77,5 @@ public Function getCreate() { public Consumer getReset() { return reset; } - public boolean isDispose() { - return dispose; - } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index 6bdabdd96d..5e15841ab0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -26,6 +26,7 @@ protected void initialize(FrameGraph frameGraph) { ticket = addOutput("Attribute"); def = new ValueDef<>(null, this); def.setDispose(true); + def.setUseExisting(false); } @Override protected void prepare(FGRenderContext context) { @@ -33,7 +34,11 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { - resources.acquire(ticket); + if (value != null) { + resources.acquire(ticket); + } else { + resources.markUndefined(ticket); + } } @Override protected void reset(FGRenderContext context) {} @@ -41,9 +46,6 @@ protected void reset(FGRenderContext context) {} protected void cleanup(FrameGraph frameGraph) {} @Override public T apply(Object t) { - if (value == null) { - throw new NullPointerException("Attribute value cannot be null."); - } return value; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 30dcc84b2b..f9a5925e2a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -28,6 +28,12 @@ public class DeferredPass extends RenderPass { @Override protected void initialize(FrameGraph frameGraph) { + depth = addInput("Depth"); + diffuse = addInput("Diffuse"); + specular = addInput("Specular"); + emissive = addInput("Emissive"); + normal = addInput("Normal"); + outColor = addOutput("Color"); material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { t.setLogic(new DeferredSinglePassLightingLogic(t)); @@ -37,7 +43,7 @@ protected void initialize(FrameGraph frameGraph) { protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - outColor = declare(new TextureDef2D(w, h, Image.Format.RGBA8), outColor); + declare(new TextureDef2D(w, h, Image.Format.RGBA8), outColor); reserve(outColor); reference(depth, diffuse, specular, emissive, normal); referenceOptional(lights); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 8d8c829179..6f379c83f5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -32,21 +32,29 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private ResourceTicket depth, diffuse, specular, emissive, normal; private ResourceTicket lights; + private final ValueDef lightDef = new ValueDef(LightList.class, n -> new LightList(null)); private final LinkedList accumulatedLights = new LinkedList<>(); private final ColorRGBA mask = new ColorRGBA(); @Override - protected void initialize(FrameGraph frameGraph) {} + protected void initialize(FrameGraph frameGraph) { + depth = addOutput("Depth"); + diffuse = addOutput("Diffuse"); + specular = addOutput("Specular"); + emissive = addOutput("Emissive"); + normal = addOutput("normal"); + lightDef.setReset(list -> list.clear()); + } @Override protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - depth = declare(new TextureDef2D(w, h, Image.Format.Depth), depth); - diffuse = declare(new TextureDef2D(w, h, Image.Format.RGBA16F), diffuse); - specular = declare(new TextureDef2D(w, h, Image.Format.RGBA16F), specular); - emissive = declare(new TextureDef2D(w, h, Image.Format.RGBA16F), emissive); - normal = declare(new TextureDef2D(w, h, Image.Format.RGBA32F), normal); - lights = declare(new ValueDef(LightList.class, n -> new LightList(null)), lights); + declare(new TextureDef2D(w, h, Image.Format.Depth), depth); + declare(new TextureDef2D(w, h, Image.Format.RGBA16F), diffuse); + declare(new TextureDef2D(w, h, Image.Format.RGBA16F), specular); + declare(new TextureDef2D(w, h, Image.Format.RGBA16F), emissive); + declare(new TextureDef2D(w, h, Image.Format.RGBA32F), normal); + declare(lightDef, lights); reserve(depth, diffuse, specular, emissive, normal); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java index 147d570fa1..738607ae00 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java @@ -4,12 +4,10 @@ */ package com.jme3.renderer.framegraph.passes; -import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; import com.jme3.texture.Texture2D; /** @@ -23,6 +21,8 @@ public class OutputPass extends RenderPass { @Override protected void initialize(FrameGraph frameGraph) { + inColor = addInput("Color"); + inDepth = addInput("Depth"); fTex = (Texture2D)frameGraph.getAssetManager().loadTexture("Common/Textures/MissingTexture.png"); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index 0d8fd2408d..6a3b6385b3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java @@ -32,6 +32,12 @@ public class TileDeferredPass extends RenderPass { @Override protected void initialize(FrameGraph frameGraph) { + diffuse = addInput("Diffuse"); + specular = addInput("Specular"); + emissive = addInput("Emissive"); + normal = addInput("Normal"); + depth = addInput("Depth"); + outColor = addOutput("Color"); material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"); for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("TileBasedDeferredPass")) { t.setLogic(new TileBasedDeferredSinglePassLightingLogic(t, tileInfo)); @@ -39,7 +45,8 @@ protected void initialize(FrameGraph frameGraph) { } @Override protected void prepare(FGRenderContext context) { - outColor = declare(new TextureDef2D(context.getWidth(), context.getHeight(), Image.Format.RGBA8), outColor); + declare(new TextureDef2D(context.getWidth(), context.getHeight(), Image.Format.RGBA8), outColor); + reserve(outColor); reference(diffuse, specular, emissive, normal, depth); referenceOptional(lights, tiles); } From bd441033ff02fca949066b3df8e7634ba0eae9e7 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 9 May 2024 11:21:21 -0400 Subject: [PATCH 058/111] added resource extraction --- .../java/com/jme3/renderer/RenderManager.java | 6 ++ .../renderer/framegraph/FGRenderContext.java | 9 +-- .../renderer/framegraph/RenderObjectMap.java | 13 ++++ .../framegraph/RenderingBlackboard.java | 65 +++++++++++++++++++ .../renderer/framegraph/ResourceList.java | 23 +++++++ .../renderer/framegraph/passes/Attribute.java | 22 ++++++- .../renderer/framegraph/passes/Junction.java | 3 + 7 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.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 f9c493522c..f0e25590c1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -48,6 +48,7 @@ import com.jme3.profile.VpStep; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderObjectMap; +import com.jme3.renderer.framegraph.RenderingBlackboard; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; @@ -88,6 +89,7 @@ public class RenderManager { private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); private final RenderObjectMap renderObjects = new RenderObjectMap(); + private final RenderingBlackboard blackboard = new RenderingBlackboard(); private FrameGraph frameGraph; private Camera prevCam = null; private Material forcedMaterial = null; @@ -133,6 +135,10 @@ public RenderObjectMap getRenderObjectsMap() { return renderObjects; } + public RenderingBlackboard getBlackboard() { + return blackboard; + } + /** * Sets the GeometryRenderHandler used to render geometry. *

      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 34499c3075..4f71ca9435 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 @@ -31,10 +31,8 @@ */ package com.jme3.renderer.framegraph; -import com.jme3.asset.AssetManager; import com.jme3.material.Material; import com.jme3.material.RenderState; -import com.jme3.material.RenderState.BlendMode; import com.jme3.profile.AppProfiler; import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.RenderManager; @@ -42,12 +40,8 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; -import com.jme3.scene.VertexBuffer; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; -import com.jme3.util.BufferUtils; import java.util.function.Predicate; /** @@ -155,6 +149,9 @@ public RenderQueue getRenderQueue() { public FullScreenQuad getScreen() { return screen; } + public RenderingBlackboard getBlackboard() { + return renderManager.getBlackboard(); + } public float getTpf() { return tpf; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 269d042899..3e0d8abd5b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -36,6 +36,9 @@ protected boolean applyToResource(RenderResource resource, RenderObject o } public void allocate(RenderResource resource) { + if (resource.isUndefined()) { + throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); + } ResourceDef def = resource.getDefinition(); int id = resource.getTicket().getObjectId(); if (id >= 0) { @@ -63,6 +66,16 @@ public boolean reserve(int objectId, int index) { } return false; } + public T extract(RenderResource resource) { + if (resource.isUndefined()) { + return null; + } + if (resource.isVirtual()) { + allocate(resource); + } + RenderObject obj = objectMap.remove(resource.getTicket().getObjectId()); + return (obj != null ? obj.getObject() : null); + } public void dispose(RenderResource resource) { int id = resource.getTicket().getObjectId(); if (id >= 0) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java new file mode 100644 index 0000000000..acbfd9738f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java @@ -0,0 +1,65 @@ +/* + * 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.HashMap; + +/** + * + * @author codex + */ +public class RenderingBlackboard { + + private final HashMap parameters = new HashMap<>(); + + public void set(String name, Class type, T value) { + if (value == null) { + delete(name); + return; + } + Parameter param = parameters.get(name); + if (param != null) { + param.setValue(value); + } else { + parameters.put(name, new Parameter(type, value)); + } + } + public T get(String name, Class type) { + Parameter param = parameters.get(name); + if (param == null || !type.isAssignableFrom(param.type)) { + return null; + } + return (T)param.value; + } + + public boolean delete(String name) { + return parameters.remove(name) != null; + } + public void clear() { + parameters.clear(); + } + + private static class Parameter { + + private final Class type; + private T value; + + public Parameter(Class type, T value) { + this.type = type; + this.value = value; + } + + public void setValue(Object val) { + if (type.isAssignableFrom(val.getClass())) { + value = (T)val; + } else { + throw new IllegalArgumentException("Value of type "+val.getClass()+" replaces " + + "another value of a different type."); + } + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index ec5c3a7ac2..8088da36d3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -180,6 +180,29 @@ public void acquireDepthTarget(FrameBuffer fbo, ResourceTicket T extract(RenderResource resource, ResourceTicket ticket) { + if (!resource.isUsed()) { + throw new IllegalStateException(resource+" was unexpectedly extracted."); + } + resource.getTicket().copyObjectTo(ticket); + return map.extract(resource); + } + public T extract(ResourceTicket ticket) { + RenderResource resource = locate(ticket); + T object = extract(resource, ticket); + if (object == null) { + throw new NullPointerException("Failed to extract resource."); + } + return object; + } + public T extractOrElse(ResourceTicket ticket, T value) { + if (ticket != null && ticket.getWorldIndex() >= 0) { + T object = extract(locate(ticket), ticket); + if (object != null) return object; + } + return value; + } + public void release(ResourceTicket ticket) { RenderResource res = locate(ticket); res.release(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index 5e15841ab0..f80eefe494 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -16,10 +16,16 @@ * @param */ public class Attribute extends RenderPass implements Function { - + + private final Class paramType; + private String paramName; + private T value; private ResourceTicket ticket; private ValueDef def; - private T value; + + public Attribute(Class paramType) { + this.paramType = paramType; + } @Override protected void initialize(FrameGraph frameGraph) { @@ -34,6 +40,9 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { + if (paramName != null) { + value = context.getBlackboard().get(paramName, paramType); + } if (value != null) { resources.acquire(ticket); } else { @@ -49,10 +58,19 @@ public T apply(Object t) { return value; } + public void setParamName(String name) { + this.paramName = name; + } public void setValue(T value) { this.value = value; } + public Class getParamType() { + return paramType; + } + public String getParamName() { + return paramName; + } public T getValue() { return value; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 754d7c72f3..81be04aceb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -34,5 +34,8 @@ protected void cleanup(FrameGraph frameGraph) {} public boolean setIndex(int index) { return ticket.setSourceIndex(index); } + public int getNumOptions() { + return ticket.getSources().size(); + } } From 45ee1b242e4d782dd3bd4f7ad45a145e38773703 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 11 May 2024 08:22:37 -0400 Subject: [PATCH 059/111] provide logical control of framegraph --- frameGraphSrcFileDraft.txt | 19 +++++ .../jme3/renderer/framegraph/FrameGraph.java | 80 +++++++++++++++++-- .../renderer/framegraph/RenderObject.java | 12 ++- .../renderer/framegraph/RenderObjectMap.java | 24 +++--- .../renderer/framegraph/RenderResource.java | 12 +-- .../framegraph/RenderingBlackboard.java | 11 ++- .../renderer/framegraph/ResourceList.java | 20 ++++- .../renderer/framegraph/ResourceProducer.java | 2 +- .../renderer/framegraph/ResourceTicket.java | 42 ++-------- .../definitions/AbstractResourceDef.java | 50 ++++++++++++ .../framegraph/definitions/ResourceDef.java | 24 +++--- .../{TextureDef2D.java => TextureDef.java} | 34 +++++--- .../framegraph/definitions/ValueDef.java | 26 +----- .../renderer/framegraph/passes/Attribute.java | 7 +- .../framegraph/passes/BucketPass.java | 6 +- .../framegraph/passes/DeferredPass.java | 4 +- .../framegraph/passes/GBufferPass.java | 12 +-- .../renderer/framegraph/passes/Junction.java | 28 ++++--- .../framegraph/passes/RenderPass.java | 50 ++++++++++-- .../framegraph/passes/TileDeferredPass.java | 4 +- .../framegraph/passes/ValueOutput.java | 59 ++++++++++++++ .../src/main/java/com/jme3/texture/Image.java | 4 +- 22 files changed, 382 insertions(+), 148 deletions(-) create mode 100644 frameGraphSrcFileDraft.txt create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/{TextureDef2D.java => TextureDef.java} (63%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ValueOutput.java diff --git a/frameGraphSrcFileDraft.txt b/frameGraphSrcFileDraft.txt new file mode 100644 index 0000000000..27c03d5467 --- /dev/null +++ b/frameGraphSrcFileDraft.txt @@ -0,0 +1,19 @@ + +nextId=4 + +define jme_Attr = com.jme3.renderer.framegraph.passes.Attribute +define jme_Bucket = com.jme3.renderer.framegraph.passes.BucketPass +define jme_Output = com.jme3.renderer.framegraph.passes.OutputPass +define jme_Junction = com.jme3.renderer.framegraph.passes.Junction + +pass{src=jme_Attr; id=0; name=Attribute} +pass{src=jme_Attr; id=2; name=Attribute} +pass{src=jme_Junction; id=4; name=Junction; length=2} +pass{src=jme_Bucket; id=1; name=Opaque Bucket; bucket=Opaque} +pass{src=jme_Output; id=3; name=Output} + +connection{out=0:Value; in=4:Input0} +connection{out=2:Value; in=4:Input1} +connection{out=4:Value; in=1:Color} +connection{out=1:Color; in=3:Color} + 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 cc075ce976..11a2a020b7 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 @@ -7,6 +7,7 @@ import com.jme3.renderer.framegraph.passes.RenderPass; import com.jme3.asset.AssetManager; import com.jme3.renderer.RenderManager; +import java.util.Iterator; import java.util.LinkedList; /** @@ -62,18 +63,25 @@ public void execute() { resources.clear(); } - public void setConstructor(GraphConstructor constructor) { - if (this.constructor != null || constructor == null) { - throw new IllegalStateException(); - } - this.constructor = constructor; - this.constructor.addPasses(this); - } public T add(T pass) { passes.addLast(pass); pass.initializePass(this, passes.size()-1); return pass; } + public T add(T pass, int index) { + if (index < 0) { + throw new IndexOutOfBoundsException("Index cannot be negative."); + } + if (index >= passes.size()) { + return add(pass); + } + passes.add(index, pass); + pass.initializePass(this, index); + for (RenderPass p : passes) { + p.shiftExecutionIndex(index, 1); + } + return pass; + } public T get(Class type) { for (RenderPass p : passes) { if (type.isAssignableFrom(p.getClass())) { @@ -82,7 +90,65 @@ public T get(Class type) { } return null; } + public T get(Class type, String name) { + for (RenderPass p : passes) { + if (name.equals(p.getName()) && type.isAssignableFrom(p.getClass())) { + return (T)p; + } + } + return null; + } + public T get(Class type, int id) { + for (RenderPass p : passes) { + if (id == p.getId() && type.isAssignableFrom(p.getClass())) { + return (T)p; + } + } + return null; + } + public RenderPass remove(int i) { + RenderPass pass = passes.remove(i); + pass.cleanupPass(this); + for (RenderPass p : passes) { + p.disconnectFrom(pass); + p.shiftExecutionIndex(i, -1); + } + return pass; + } + public boolean remove(RenderPass pass) { + int i = 0; + for (Iterator it = passes.iterator(); it.hasNext();) { + RenderPass p = it.next(); + if (p == pass) { + it.remove(); + break; + } + i++; + } + if (i < passes.size()) { + pass.cleanupPass(this); + for (RenderPass p : passes) { + p.disconnectFrom(pass); + p.shiftExecutionIndex(i, -1); + } + return true; + } + return false; + } + public void clear() { + for (RenderPass p : passes) { + p.cleanupPass(this); + } + passes.clear(); + } + public void setConstructor(GraphConstructor constructor) { + if (this.constructor != null || constructor == null) { + throw new IllegalStateException(); + } + this.constructor = constructor; + this.constructor.addPasses(this); + } public void setDebug(boolean debug) { this.debug = debug; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java index f47e587ecc..593012e8c8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java @@ -16,17 +16,18 @@ */ public class RenderObject { - private static final Consumer DEFAULT = object -> {}; + private static final Consumer DEFAULT = object -> {}; private static final Consumer NATIVE = object -> object.dispose(); private static int nextId = 0; private final int id; private final T object; + private final BitSet reservations = new BitSet(); private int timeoutDuration; private int timeout = 0; private boolean acquired = false; - private final BitSet reservations = new BitSet(); + private boolean constant = true; private Consumer disposer; public RenderObject(ResourceDef def, T object, int timeout) { @@ -79,6 +80,10 @@ public boolean tickTimeout() { return timeout-- > 0; } + public void setConstant(boolean constant) { + this.constant = constant; + } + public int getId() { return id; } @@ -100,6 +105,9 @@ public boolean isReserved(TimeFrame frame) { } return false; } + public boolean isConstant() { + return constant; + } public static int getNextId() { return nextId; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 3e0d8abd5b..be846bea3c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -26,11 +26,13 @@ protected RenderObject create(ResourceDef def, T value) { return obj; } protected boolean applyToResource(RenderResource resource, RenderObject object) { - T r = resource.getDefinition().applyResource(object.getObject()); - if (r != null) { - object.acquire(); - resource.setObject(object); - return true; + if (!object.isAcquired() && !object.isConstant()) { + T r = resource.getDefinition().applyResource(object.getObject()); + if (r != null) { + object.acquire(); + resource.setObject(object, r); + return true; + } } return false; } @@ -42,21 +44,19 @@ public void allocate(RenderResource resource) { ResourceDef def = resource.getDefinition(); int id = resource.getTicket().getObjectId(); if (id >= 0) { - RenderObject reserved = objectMap.get(id); - if (reserved != null && !reserved.isAcquired() && applyToResource(resource, reserved)) { + RenderObject obj = objectMap.get(id); + if (obj != null && applyToResource(resource, obj)) { return; } } for (RenderObject obj : objectMap.values()) { - if (!obj.isAcquired() - && !obj.isReserved(resource.getLifeTime()) - && applyToResource(resource, obj)) { + if (!obj.isReserved(resource.getLifeTime()) && applyToResource(resource, obj)) { return; } } RenderObject obj = create(def); obj.acquire(); - resource.setObject(obj); + resource.setObject(obj, obj.getObject()); } public boolean reserve(int objectId, int index) { RenderObject obj = objectMap.get(objectId); @@ -97,7 +97,9 @@ public void flushMap() { if (!obj.tickTimeout()) { obj.dispose(); it.remove(); + continue; } + obj.setConstant(false); } } public void clearMap() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 7c8f0260fc..467297a298 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -17,7 +17,8 @@ public class RenderResource { private final ResourceDef def; private final ResourceTicket ticket; private final TimeFrame lifetime; - private RenderObject object; + private RenderObject object; + private T resource; private int refs = 0; private int timeout = 0; private boolean undefined = false; @@ -26,7 +27,7 @@ public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTic this.producer = producer; this.def = def; this.ticket = ticket; - this.lifetime = new TimeFrame(this.producer.getIndex(), 0); + this.lifetime = new TimeFrame(this.producer.getExecutionIndex(), 0); } public void reference(int index) { @@ -43,11 +44,12 @@ public boolean tickTimeout() { public void setTimeout(int timeout) { this.timeout = timeout; } - public void setObject(RenderObject object) { + public void setObject(RenderObject object, T resource) { if (undefined) { throw new IllegalStateException("Resource is already undefined."); } this.object = object; + this.resource = resource; if (this.object != null) { ticket.setObjectId(this.object.getId()); } @@ -71,11 +73,11 @@ public ResourceTicket getTicket() { public TimeFrame getLifeTime() { return lifetime; } - public RenderObject getObject() { + public RenderObject getObject() { return object; } public T getResource() { - return object.getObject(); + return resource; } public int getIndex() { return ticket.getWorldIndex(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java index acbfd9738f..18971238b3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java @@ -15,6 +15,12 @@ public class RenderingBlackboard { private final HashMap parameters = new HashMap<>(); public void set(String name, Class type, T value) { + if (type == null) { + throw new NullPointerException("Parameter type cannot be null."); + } + if (name == null) { + return; + } if (value == null) { delete(name); return; @@ -27,6 +33,9 @@ public void set(String name, Class type, T value) { } } public T get(String name, Class type) { + if (name == null) { + return null; + } Parameter param = parameters.get(name); if (param == null || !type.isAssignableFrom(param.type)) { return null; @@ -35,7 +44,7 @@ public T get(String name, Class type) { } public boolean delete(String name) { - return parameters.remove(name) != null; + return name != null && parameters.remove(name) != null; } public void clear() { parameters.clear(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 8088da36d3..4f9e3442b9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -48,6 +48,9 @@ protected RenderResource locate(ResourceTicket ticket) { } throw new IndexOutOfBoundsException(ticket+" is out of bounds for size "+resources.size()); } + protected boolean validate(ResourceTicket ticket) { + return ticket != null && ticket.getWorldIndex() >= 0; + } protected int add(RenderResource res) { assert res != null; if (nextSlot >= resources.size()) { @@ -122,9 +125,20 @@ public > R getDefinition(Class type, ResourceTick } return null; } - public void markUndefined(ResourceTicket ticket) { + public void setUndefined(ResourceTicket ticket) { locate(ticket).setUndefined(); } + public void setConstant(ResourceTicket ticket) { + RenderObject obj = locate(ticket).getObject(); + if (obj != null) { + obj.setConstant(true); + } + } + public void setConstantOptional(ResourceTicket ticket) { + if (validate(ticket)) { + setConstant(ticket); + } + } protected T acquire(RenderResource resource, ResourceTicket ticket) { if (!resource.isUsed()) { @@ -144,7 +158,7 @@ public T acquire(ResourceTicket ticket) { return acquire(resource, ticket); } public T acquireOrElse(ResourceTicket ticket, T value) { - if (ticket != null && ticket.getWorldIndex() >= 0) { + if (validate(ticket)) { RenderResource resource = locate(ticket); if (!resource.isUndefined()) { return acquire(resource, ticket); @@ -209,7 +223,7 @@ public void release(ResourceTicket ticket) { if (!res.isUsed()) { remove(ticket.getWorldIndex()); res.getObject().release(); - res.setObject(null); + res.setObject(null, null); if (res.getDefinition().isDisposeOnRelease()) { map.dispose(res); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java index aa8d82d1ee..0bade655af 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java @@ -12,7 +12,7 @@ */ public interface ResourceProducer { - public int getIndex(); + public int getExecutionIndex(); public boolean dereference(); public boolean isReferenced(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index d4f6980d58..168b6762b6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -5,7 +5,6 @@ package com.jme3.renderer.framegraph; import java.util.ArrayList; -import java.util.Objects; /** * References a {@link RenderResource} by either name or index. @@ -25,8 +24,7 @@ public class ResourceTicket { private String name; private int localIndex; private int objectId = -1; - private int sourceIndex = 0; - private ArrayList> sources; + private ResourceTicket source; public ResourceTicket() { this(null, -1); @@ -43,22 +41,6 @@ public ResourceTicket(String name, int index) { this.localIndex = index; } - public int addSource(ResourceTicket source) { - if (sources == null) { - sources = new ArrayList<>(1); - } - if (sources.add(source)) { - return sources.size()-1; - } - return -1; - } - public boolean removeSource(ResourceTicket source) { - return sources.remove(source); - } - public void clearSources() { - sources.clear(); - } - public ResourceTicket copyIndexTo(ResourceTicket target) { if (target == null) { target = new ResourceTicket(); @@ -73,6 +55,9 @@ public ResourceTicket copyObjectTo(ResourceTicket target) { return target; } + public void setSource(ResourceTicket source) { + this.source = source; + } public ResourceTicket setName(String name) { this.name = name; return this; @@ -84,10 +69,6 @@ protected ResourceTicket setLocalIndex(int index) { public void setObjectId(int objectId) { this.objectId = objectId; } - public boolean setSourceIndex(int sourceIndex) { - this.sourceIndex = sourceIndex; - return this.sourceIndex >= 0 && this.sourceIndex < sources.size(); - } public long getId() { return id; @@ -96,9 +77,8 @@ public String getName() { return name; } public int getWorldIndex() { - ResourceTicket src = getCurrentSource(); - if (src != null) { - int i = src.getWorldIndex(); + if (source != null) { + int i = source.getWorldIndex(); if (i >= 0) return i; } return localIndex; @@ -109,14 +89,8 @@ public int getLocalIndex() { public int getObjectId() { return objectId; } - public ResourceTicket getCurrentSource() { - if (sourceIndex >= 0 && sourceIndex < sources.size()) { - return sources.get(sourceIndex); - } - return null; - } - public ArrayList> getSources() { - return sources; + public ResourceTicket getSource() { + return source; } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java new file mode 100644 index 0000000000..b3a8ba9481 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java @@ -0,0 +1,50 @@ +/* + * 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.definitions; + +import java.util.function.Consumer; + +/** + * + * @author codex + */ +public abstract class AbstractResourceDef implements ResourceDef { + + private Consumer disposalMethod; + private int staticTimeout = -1; + private boolean useExisting = true; + private boolean disposeOnRelease = false; + + @Override + public int getStaticTimeout() { + return staticTimeout; + } + @Override + public Consumer getDisposalMethod() { + return disposalMethod; + } + @Override + public boolean isUseExisting() { + return useExisting; + } + @Override + public boolean isDisposeOnRelease() { + return disposeOnRelease; + } + + public void setDisposalMethod(Consumer disposalMethod) { + this.disposalMethod = disposalMethod; + } + public void setStaticTimeout(int staticTimout) { + this.staticTimeout = staticTimout; + } + public void setUseExisting(boolean useExisting) { + this.useExisting = useExisting; + } + public void setDisposeOnRelease(boolean disposeOnRelease) { + this.disposeOnRelease = disposeOnRelease; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index f0c382dbd7..65ad268f48 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -28,6 +28,18 @@ public interface ResourceDef { */ public T applyResource(Object resource); + /** + * Returns the number of frames which the resource must be + * static (unused throughout rendering) before it is disposed. + *

      + * If negative, the default timeout value will be used instead. + * + * @return static timeout duration + */ + public default int getStaticTimeout() { + return -1; + } + /** * Gets the Consumer used to dispose of a resource. * @@ -56,16 +68,4 @@ public default boolean isDisposeOnRelease() { return false; } - /** - * Returns the number of frames which the resource must be - * static (unused throughout rendering) before it is disposed. - *

      - * If negative, the default timeout value will be used instead. - * - * @return static timeout duration - */ - public default int getStaticTimeout() { - return -1; - } - } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef2D.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java similarity index 63% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef2D.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 81376dd4f5..d5abfe6b50 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef2D.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -7,28 +7,31 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; +import com.jme3.texture.Texture3D; /** * * @author codex + * @param */ -public class TextureDef2D implements ResourceDef { +public class TextureDef extends AbstractResourceDef { - private int width, height, samples; + private int width, height, depth, samples; private Image.Format format; - public TextureDef2D(int width, int height, Image.Format format) { - this(width, height, 1, format); + public TextureDef(int width, int height, Image.Format format) { + this(width, height, 0, 1, format); } - public TextureDef2D(int width, int height, int samples, Image.Format format) { + public TextureDef(int width, int height, int depth, int samples, Image.Format format) { this.width = width; this.height = height; + this.depth = depth; this.samples = samples; this.format = format; } @Override - public Texture2D createResource() { + public Texture createResource() { if (samples != 1) { return new Texture2D(width, height, samples, format); } else { @@ -36,15 +39,22 @@ public Texture2D createResource() { } } @Override - public Texture2D applyResource(Object resource) { - if (!(resource instanceof Texture2D)) { + public Texture applyResource(Object resource) { + Image img; + if (resource instanceof Texture) { + img = ((Texture)resource).getImage(); + } else if (resource instanceof Image) { + img = (Image)resource; + } else { return null; } - Texture2D tex = (Texture2D)resource; - Image img = tex.getImage(); - if (img.getWidth() == width && img.getHeight() == height + if (img.getWidth() == width && img.getHeight() == height && (img.getDepth() == depth || depth <= 0) && img.getFormat() == format && img.getMultiSamples() == samples) { - return tex; + if (depth <= 0) { + return new Texture2D(img); + } else { + return new Texture3D(img); + } } return null; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java index 5d36ecdb69..2dc51adb6f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java @@ -12,14 +12,11 @@ * @author codex * @param */ -public class ValueDef implements ResourceDef { +public class ValueDef extends AbstractResourceDef { private final Class type; private Function create; private Consumer reset; - private Consumer disposal; - private boolean useExisting = true; - private boolean dispose = false; public ValueDef(Class type, Function create) { this.type = type; @@ -39,18 +36,6 @@ public T applyResource(Object resource) { } return null; } - @Override - public Consumer getDisposalMethod() { - return disposal; - } - @Override - public boolean isUseExisting() { - return useExisting; - } - @Override - public boolean isDisposeOnRelease() { - return dispose; - } public void setCreate(Function create) { this.create = create; @@ -58,15 +43,6 @@ public void setCreate(Function create) { public void setReset(Consumer reset) { this.reset = reset; } - public void setDisposal(Consumer disposal) { - this.disposal = disposal; - } - public void setUseExisting(boolean useExisting) { - this.useExisting = useExisting; - } - public void setDispose(boolean dispose) { - this.dispose = dispose; - } public Class getType() { return type; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index f80eefe494..f074a8950b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -29,9 +29,9 @@ public Attribute(Class paramType) { @Override protected void initialize(FrameGraph frameGraph) { - ticket = addOutput("Attribute"); + ticket = addOutput("Value"); def = new ValueDef<>(null, this); - def.setDispose(true); + def.setDisposeOnRelease(true); def.setUseExisting(false); } @Override @@ -45,8 +45,9 @@ protected void execute(FGRenderContext context) { } if (value != null) { resources.acquire(ticket); + resources.setConstant(ticket); } else { - resources.markUndefined(ticket); + resources.setUndefined(ticket); } } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 5660c3b2ed..80847ae8a9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -4,7 +4,7 @@ */ package com.jme3.renderer.framegraph.passes; -import com.jme3.renderer.framegraph.definitions.TextureDef2D; +import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; @@ -50,8 +50,8 @@ protected void initialize(FrameGraph frameGraph) { protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - declare(new TextureDef2D(w, h, samples, Image.Format.RGBA8), outColor); - declare(new TextureDef2D(w, h, samples, Image.Format.Depth), outDepth); + declare(new TextureDef(w, h, samples, Image.Format.RGBA8), outColor); + declare(new TextureDef(w, h, samples, Image.Format.Depth), outDepth); referenceOptional(inColor, inDepth); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index f9a5925e2a..06f1a1ca93 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -4,7 +4,7 @@ */ package com.jme3.renderer.framegraph.passes; -import com.jme3.renderer.framegraph.definitions.TextureDef2D; +import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.material.TechniqueDef; @@ -43,7 +43,7 @@ protected void initialize(FrameGraph frameGraph) { protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - declare(new TextureDef2D(w, h, Image.Format.RGBA8), outColor); + declare(new TextureDef(w, h, Image.Format.RGBA8), outColor); reserve(outColor); reference(depth, diffuse, specular, emissive, normal); referenceOptional(lights); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 6f379c83f5..754388c05f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -5,7 +5,7 @@ package com.jme3.renderer.framegraph.passes; import com.jme3.renderer.framegraph.definitions.ValueDef; -import com.jme3.renderer.framegraph.definitions.TextureDef2D; +import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.light.Light; import com.jme3.light.LightList; import com.jme3.material.Material; @@ -49,11 +49,11 @@ protected void initialize(FrameGraph frameGraph) { protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - declare(new TextureDef2D(w, h, Image.Format.Depth), depth); - declare(new TextureDef2D(w, h, Image.Format.RGBA16F), diffuse); - declare(new TextureDef2D(w, h, Image.Format.RGBA16F), specular); - declare(new TextureDef2D(w, h, Image.Format.RGBA16F), emissive); - declare(new TextureDef2D(w, h, Image.Format.RGBA32F), normal); + declare(new TextureDef(w, h, Image.Format.Depth), depth); + declare(new TextureDef(w, h, Image.Format.RGBA16F), diffuse); + declare(new TextureDef(w, h, Image.Format.RGBA16F), specular); + declare(new TextureDef(w, h, Image.Format.RGBA16F), emissive); + declare(new TextureDef(w, h, Image.Format.RGBA32F), normal); declare(lightDef, lights); reserve(depth, diffuse, specular, emissive, normal); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 81be04aceb..364bc99e68 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -11,18 +11,24 @@ /** * * @author codex + * @param */ -public class Junction extends RenderPass { +public class Junction extends RenderPass { - private ResourceTicket ticket; + private int length = 2; + private int index = 0; + private ResourceTicket output; @Override protected void initialize(FrameGraph frameGraph) { - ticket = addInput(addOutput("Junction")); + for (int i = 0; i < length; i++) { + addInput("Input"+i); + } + output = addOutput("Value"); } @Override protected void prepare(FGRenderContext context) { - referenceOptional(ticket); + output.setSource(getInputTickets().get(index)); } @Override protected void execute(FGRenderContext context) {} @@ -30,12 +36,16 @@ protected void execute(FGRenderContext context) {} protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} - - public boolean setIndex(int index) { - return ticket.setSourceIndex(index); + @Override + public boolean isReferenced() { + return true; + } + + public void setIndex(int index) { + this.index = 0; } - public int getNumOptions() { - return ticket.getSources().size(); + public void setLength(int length) { + this.length = length; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 73b79ad279..7fa40bd5c3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -21,9 +21,13 @@ */ public abstract class RenderPass implements ResourceProducer { + private static int nextId = 0; + private final LinkedList inputs = new LinkedList<>(); private final LinkedList outputs = new LinkedList<>(); private final CameraSize camSize = new CameraSize(); + private int id = nextId++; + private String name = ""; private int index = -1; private int refs = 0; protected ResourceList resources; @@ -35,6 +39,9 @@ public void initializePass(FrameGraph frameGraph, int index) { initialize(frameGraph); } public void prepareRender(FGRenderContext context) { + if (index < 0) { + throw new IllegalStateException("Pass is not properly initialized for rendering."); + } prepare(context); } public void executeRender(FGRenderContext context) { @@ -52,8 +59,12 @@ public void resetRender(FGRenderContext context) { } public void cleanupPass(FrameGraph frameGraph) { cleanup(frameGraph); + for (ResourceTicket t : inputs) { + t.setSource(null); + } inputs.clear(); outputs.clear(); + index = -1; } protected abstract void initialize(FrameGraph frameGraph); @@ -120,7 +131,6 @@ protected ResourceTicket addOutput(ResourceTicket output) { outputs.add(output); return output; } - protected ResourceTicket addInput(String name) { return addInput(new ResourceTicket<>(name)); } @@ -128,25 +138,45 @@ protected ResourceTicket addOutput(String name) { return addOutput(new ResourceTicket<>(name)); } - public ResourceTicket connectToOutput(String name, ResourceTicket ticket) { - for (ResourceTicket t : outputs) { - if (name.equals(t.getName())) { - ticket.addSource(t); - return t; + public void disconnectFrom(RenderPass pass) { + for (ResourceTicket in : inputs) { + if (pass.getOutputTickets().contains(in.getSource())) { + in.setSource(null); } } - return null; } public void countReferences() { refs = outputs.size(); } + public void setName(String name) { + this.name = name; + } + public void setId(int id) { + this.id = id; + } + public void useNextId() { + id = nextId++; + } + public void shiftExecutionIndex(int base, int amount) { + if (index > base) { + index += amount; + } + } + + public String getName() { + return name; + } + public int getId() { + return id; + } + public boolean isAssigned() { return index >= 0; } @Override - public int getIndex() { + public int getExecutionIndex() { return index; } @Override @@ -171,4 +201,8 @@ public String toString() { return getClass().getSimpleName(); } + public static void setNextId(int id) { + nextId = id; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index 6a3b6385b3..d7c95f2d9a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java @@ -12,7 +12,7 @@ import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; -import com.jme3.renderer.framegraph.definitions.TextureDef2D; +import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture; @@ -45,7 +45,7 @@ protected void initialize(FrameGraph frameGraph) { } @Override protected void prepare(FGRenderContext context) { - declare(new TextureDef2D(context.getWidth(), context.getHeight(), Image.Format.RGBA8), outColor); + declare(new TextureDef(context.getWidth(), context.getHeight(), Image.Format.RGBA8), outColor); reserve(outColor); reference(diffuse, specular, emissive, normal, depth); referenceOptional(lights, tiles); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ValueOutput.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ValueOutput.java new file mode 100644 index 0000000000..f03f72035b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ValueOutput.java @@ -0,0 +1,59 @@ +/* + * 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.passes; + +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; + +/** + * + * @author codex + * @param + */ +public class ValueOutput extends RenderPass { + + private final Class type; + private String target; + private ViewPort viewPort; + private ResourceTicket ticket; + + public ValueOutput(Class type, String target) { + this.type = type; + this.target = target; + } + + @Override + protected void initialize(FrameGraph frameGraph) { + ticket = addInput("Value"); + } + @Override + protected void prepare(FGRenderContext context) { + referenceOptional(ticket); + } + @Override + protected void execute(FGRenderContext context) { + if (viewPort == null || context.getViewPort() == viewPort) { + T value = resources.acquireOrElse(ticket, null); + if (value != null) { + context.getBlackboard().set(target, type, value); + resources.setConstant(ticket); + } + } + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + + public void setTarget(String target) { + this.target = target; + } + public void setViewPort(ViewPort viewPort) { + this.viewPort = viewPort; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/texture/Image.java b/jme3-core/src/main/java/com/jme3/texture/Image.java index c5c0395021..8cdba26db3 100644 --- a/jme3-core/src/main/java/com/jme3/texture/Image.java +++ b/jme3-core/src/main/java/com/jme3/texture/Image.java @@ -737,7 +737,7 @@ public Image clone(){ */ public Image() { super(); - data = new ArrayList(1); + data = new ArrayList<>(1); } protected Image(int id){ @@ -837,7 +837,7 @@ public Image(Format format, int width, int height, ByteBuffer data, this.width = width; this.height = height; if (data != null){ - this.data = new ArrayList(1); + this.data = new ArrayList<>(1); this.data.add(data); } this.mipMapSizes = mipMapSizes; From f9156e2230003ff7af79bd272b8afbc4877f1b03 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 16 May 2024 22:14:41 -0400 Subject: [PATCH 060/111] finalized user value sources and targets --- FrameGraphComponents | 36 ++++ FrameGraphTutorial.md | 36 ++++ .../java/com/jme3/export/InputCapsule.java | 10 +- .../java/com/jme3/renderer/RenderManager.java | 14 +- .../jme3/renderer/framegraph/DepthRange.java | 34 +++- .../renderer/framegraph/FGRenderContext.java | 3 - .../jme3/renderer/framegraph/FrameGraph.java | 24 ++- .../jme3/renderer/framegraph/GraphTarget.java | 19 ++ .../renderer/framegraph/RenderObject.java | 22 +-- .../renderer/framegraph/RenderObjectMap.java | 58 ++++-- .../renderer/framegraph/RenderResource.java | 9 + .../framegraph/RenderingBlackboard.java | 74 -------- .../renderer/framegraph/ResourceList.java | 109 +++++++++++ .../renderer/framegraph/ResourceProducer.java | 2 +- .../renderer/framegraph/ResourceTicket.java | 20 +- .../definitions/AbstractResourceDef.java | 3 +- .../framegraph/definitions/ResourceDef.java | 14 +- .../framegraph/definitions/TextureDef.java | 178 +++++++++++++++--- .../framegraph/definitions/ValueDef.java | 34 ++-- .../{Attribute.java => AttributePass.java} | 45 +++-- .../framegraph/passes/BucketPass.java | 55 +++++- .../framegraph/passes/DeferredPass.java | 11 +- .../framegraph/passes/GBufferPass.java | 41 ++-- .../framegraph/passes/GraphSource.java | 18 ++ .../{Junction.java => JunctionPass.java} | 22 ++- .../framegraph/passes/OutputBucketPass.java | 2 +- .../framegraph/passes/OutputPass.java | 2 +- .../framegraph/passes/PostProcessingPass.java | 2 +- .../framegraph/passes/RenderPass.java | 47 ++++- .../framegraph/passes/TileDeferredPass.java | 10 +- .../framegraph/passes/ValueOutput.java | 59 ------ .../com/jme3/render/plugins/J3GLoader.java | 38 ++++ 32 files changed, 756 insertions(+), 295 deletions(-) create mode 100644 FrameGraphComponents create mode 100644 FrameGraphTutorial.md create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphTarget.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/{Attribute.java => AttributePass.java} (57%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GraphSource.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/{Junction.java => JunctionPass.java} (74%) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ValueOutput.java create mode 100644 jme3-core/src/plugins/java/com/jme3/render/plugins/J3GLoader.java diff --git a/FrameGraphComponents b/FrameGraphComponents new file mode 100644 index 0000000000..a6e534435f --- /dev/null +++ b/FrameGraphComponents @@ -0,0 +1,36 @@ +What is a render resource? + +A render resource is a wrapper for a render object. It also tracks references and lifetime, and knows its producer and resource definition. When a resource is not + +What is a resource ticket? + +A resource ticket points to a resource. It is used to tell the resource manager which resource various operations should be performed on. + +What does declaring a resource do? + +Declaring a resource makes the resource manager create a new virtual resource that does not yet hold an actual value. Passes should declare all resources they plan on creating during execution in the preperation step. + +What does referencing a resource do? + +Referencing is similar to declaring, except it acts on an existing resource. It tells the resource manager that that resource will be used in the future. This is used by passes referencing resources produced by other passes. + +What does acquiring a resource do? + +Acquiring a resource either returns the actual object held by the resource if the resource is not virtual, otherwise creates and returns a new object or returns an existing unused object. + +What does releasing a resource do? + +Releasing indicates that the resource is not used by a pass anymore. Resources track how many passes are using them using declarations and references. Once a resource finds that all passes that declared or referenced it have also released it, the resource will be deleted, and the object held by the resource will be posted for reallocation. + +What does setting a resource as constant do? + +This command does not actually change the resource, but it does set a flag on the object held by the resource (if the resource is not virtual) indicating that the object should not be reallocated for the remainder of rendering. The Attribute pass uses this to ensure that user-provided or user-consumed objects do not change unexpectedly. + +What does setting a resource as undefined do? + +Setting a resource as undefined makes it real (not virtual) but unable to hold an actual object. This is used by the Attribute pass when no (non-null) value is provided for output. Exceptions can occur if a pass attempts to acquire (without using an optional acquire) an undefined resource. + +What is a resource definition? + +A resource definition determines how new objects should be built or how existing objects should be adapted for the resource the definition is assigned to. It also defines how the resource and object should be handled in various situations. + diff --git a/FrameGraphTutorial.md b/FrameGraphTutorial.md new file mode 100644 index 0000000000..f1d600ce56 --- /dev/null +++ b/FrameGraphTutorial.md @@ -0,0 +1,36 @@ + +/** + * For this tutorial, we will create a simple FrameGraph that renders + * the opaque, sky, and transparent buckets in that order, followed + * by a pass that renders the result to the screen. + */ + +// Begin by declaring a new FrameGraph. +FrameGraph fg = new FrameGraph(); + +// Add the passes we will use, in the correct order. +// Make sure to specify the correct bucket on each pass. +BucketPass opaque = fg.add(new BucketPass(Bucket.Opaque)); +BucketPass sky = fg.add(new BucketPass(Bucket.Sky)); +BucketPass transparent = fg.add(new BucketPass(Bucket.Transparent)); +OutputPass output = fg.add(new OutputPass()); + +// Now, each pass needs to pass its resulting color and depth to the next pass. +// We will do that by connecting certain tickets belonging to the passes. +sky.makeInput(opaque, "Color", "Color"); +sky.makeInput(opaque, "Depth", "Depth"); +transparent.makeInput(sky, "Color", "Color"); +transparent.makeInput(sky, "Depth", "Depth"); +output.makeInput(transparent, "Color", "Color"); +output.makeInput(transparent, "Depth", "Depth"); + +// The graph now, visually, looks like this: +// +// Opaque: Sky: Transparent: Output: +// color -> color -> color -------> color +// depth -> depth -> depth -------> depth + +// Finally, assign the FrameGraph to the ViewPort. +viewPort.setFrameGraph(fg); + + diff --git a/jme3-core/src/main/java/com/jme3/export/InputCapsule.java b/jme3-core/src/main/java/com/jme3/export/InputCapsule.java index 133ea34678..fd9cbff26a 100644 --- a/jme3-core/src/main/java/com/jme3/export/InputCapsule.java +++ b/jme3-core/src/main/java/com/jme3/export/InputCapsule.java @@ -113,7 +113,15 @@ public interface InputCapsule { public Savable readSavable(String name, Savable defVal) throws IOException; public Savable[] readSavableArray(String name, Savable[] defVal) throws IOException; public Savable[][] readSavableArray2D(String name, Savable[][] defVal) throws IOException; - + public default T readSavable(String name, Class type, T defVal) throws IOException { + Savable s = readSavable(name, defVal); + if (s != defVal && type.isAssignableFrom(s.getClass())) { + return (T)s; + } else { + return defVal; + } + } + // ArrayLists 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 f0e25590c1..324c2b8d7c 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,6 @@ import com.jme3.profile.VpStep; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderObjectMap; -import com.jme3.renderer.framegraph.RenderingBlackboard; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; @@ -72,10 +71,10 @@ import java.util.function.Predicate; /** - * A high-level rendering interface that is - * above the Renderer implementation. RenderManager takes care - * of rendering the scene graphs attached to each viewport and - * handling SceneProcessors. + * A high-level rendering interface that is above the Renderer implementation. + *

      + * RenderManager takes care of rendering the scene graphs attached to each + * viewport and handling SceneProcessors. * * @see SceneProcessor * @see ViewPort @@ -89,7 +88,6 @@ public class RenderManager { private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); private final RenderObjectMap renderObjects = new RenderObjectMap(); - private final RenderingBlackboard blackboard = new RenderingBlackboard(); private FrameGraph frameGraph; private Camera prevCam = null; private Material forcedMaterial = null; @@ -135,10 +133,6 @@ public RenderObjectMap getRenderObjectsMap() { return renderObjects; } - public RenderingBlackboard getBlackboard() { - return blackboard; - } - /** * Sets the GeometryRenderHandler used to render geometry. *

      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 index 6ec288ea83..fc3bbef356 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java @@ -4,11 +4,18 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import java.io.IOException; + /** * * @author codex */ -public class DepthRange { +public class DepthRange implements Savable { public static final DepthRange IDENTITY = new DepthRange(); public static final DepthRange FRONT = new DepthRange(0, 0); @@ -40,6 +47,18 @@ public final DepthRange set(DepthRange range) { return this; } + public final DepthRange setStart(float start) { + validateRange(start, end); + this.start = start; + return this; + } + + public final DepthRange setEnd(float end) { + validateRange(start, end); + this.end = end; + return this; + } + public float getStart() { return start; } @@ -81,10 +100,21 @@ public int hashCode() { hash = 79 * hash + Float.floatToIntBits(this.end); return hash; } - @Override public String toString() { return "DepthRange["+start+" -> "+end+"]"; } + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(start, "start", 0); + out.write(end, "end", 1); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + start = in.readFloat("start", 0); + end = in.readFloat("end", 1); + } } 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 4f71ca9435..8f3e72228d 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 @@ -149,9 +149,6 @@ public RenderQueue getRenderQueue() { public FullScreenQuad getScreen() { return screen; } - public RenderingBlackboard getBlackboard() { - return renderManager.getBlackboard(); - } public float getTpf() { return tpf; } 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 11a2a020b7..0b485cc8c0 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 @@ -6,7 +6,15 @@ import com.jme3.renderer.framegraph.passes.RenderPass; import com.jme3.asset.AssetManager; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.renderer.RenderManager; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -15,7 +23,7 @@ * * @author codex */ -public class FrameGraph { +public class FrameGraph implements Savable { private static int nextId = 0; @@ -49,7 +57,7 @@ public void execute() { // execute passes context.pushRenderSettings(); for (RenderPass p : passes) { - if (p.isReferenced()) { + if (p.isUsed()) { p.executeRender(context); context.popRenderSettings(); } @@ -174,5 +182,17 @@ public RenderManager getRenderManager() { public boolean isDebug() { return debug; } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(passes.toArray(RenderPass[]::new), "passes", new RenderPass[0]); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + RenderPass[] array = (RenderPass[])in.readSavableArray("passes", new RenderPass[0]); + passes.addAll(Arrays.asList(array)); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphTarget.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphTarget.java new file mode 100644 index 0000000000..c33eda559b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphTarget.java @@ -0,0 +1,19 @@ +/* + * 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 com.jme3.renderer.ViewPort; + +/** + * Receives values from a FrameGraph. + * + * @author codex + * @param + */ +public interface GraphTarget { + + public void setGraphValue(ViewPort viewPort, T value); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java index 593012e8c8..02b34b7bbd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java @@ -19,9 +19,9 @@ public class RenderObject { private static final Consumer DEFAULT = object -> {}; private static final Consumer NATIVE = object -> object.dispose(); - private static int nextId = 0; + private static long nextId = 0; - private final int id; + private final long id; private final T object; private final BitSet reservations = new BitSet(); private int timeoutDuration; @@ -48,14 +48,7 @@ else if (object instanceof NativeObject) { this.disposer = DEFAULT; } } - - public boolean acquire(TimeFrame time, boolean reserved) { - if (acquired || (!reserved && isReserved(time))) { - return false; - } - acquire(); - return true; - } + public void acquire() { timeout = timeoutDuration; acquired = true; @@ -84,7 +77,7 @@ public void setConstant(boolean constant) { this.constant = constant; } - public int getId() { + public long getId() { return id; } public T getObject() { @@ -93,7 +86,10 @@ public T getObject() { public boolean isAcquired() { return acquired; } - public boolean isReserved(TimeFrame frame) { + public boolean isReservedAt(int index) { + return reservations.get(index); + } + public boolean isReservedWithin(TimeFrame frame) { if (frame.getStartIndex() >= reservations.size()) { return false; } @@ -109,7 +105,7 @@ public boolean isConstant() { return constant; } - public static int getNextId() { + public static long getNextId() { return nextId; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index be846bea3c..7ce36425d2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -14,7 +14,7 @@ */ public class RenderObjectMap { - private final HashMap objectMap = new HashMap<>(); + private final HashMap objectMap = new HashMap<>(); private final int timeout = 1; protected RenderObject create(ResourceDef def) { @@ -25,11 +25,13 @@ protected RenderObject create(ResourceDef def, T value) { objectMap.put(obj.getId(), obj); return obj; } - protected boolean applyToResource(RenderResource resource, RenderObject object) { + protected boolean isAvailable(RenderObject object) { + return !object.isAcquired() && !object.isConstant(); + } + protected boolean applyDirectResource(RenderResource resource, RenderObject object) { if (!object.isAcquired() && !object.isConstant()) { - T r = resource.getDefinition().applyResource(object.getObject()); + T r = resource.getDefinition().applyDirectResource(object.getObject()); if (r != null) { - object.acquire(); resource.setObject(object, r); return true; } @@ -42,23 +44,51 @@ public void allocate(RenderResource resource) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); } ResourceDef def = resource.getDefinition(); - int id = resource.getTicket().getObjectId(); + long id = resource.getTicket().getObjectId(); + // allocate reserved object if (id >= 0) { RenderObject obj = objectMap.get(id); - if (obj != null && applyToResource(resource, obj)) { - return; + if (obj != null && isAvailable(obj) && + (obj.isReservedAt(resource.getLifeTime().getStartIndex()) + || !obj.isReservedWithin(resource.getLifeTime()))) { + // reserved object is only applied if it is accepted by the definition + T r = def.applyDirectResource(obj.getObject()); + if (r == null) { + r = def.applyIndirectResource(obj.getObject()); + } + if (r != null) { + resource.setObject(obj, r); + return; + } } } + // find object to allocate + T indirectRes = null; + RenderObject indirectObj = null; for (RenderObject obj : objectMap.values()) { - if (!obj.isReserved(resource.getLifeTime()) && applyToResource(resource, obj)) { - return; + if (isAvailable(obj) && !obj.isReservedWithin(resource.getLifeTime())) { + T r = def.applyDirectResource(obj.getObject()); + if (r != null) { + resource.setObject(obj, r); + return; + } + if (indirectObj == null) { + indirectRes = def.applyIndirectResource(obj.getObject()); + if (indirectRes != null) { + indirectObj = obj; + } + } } } - RenderObject obj = create(def); - obj.acquire(); - resource.setObject(obj, obj.getObject()); + if (indirectObj != null) { + // allocate indirect object + resource.setObject(indirectObj, indirectRes); + } else { + // create new object + resource.setObject(create(def)); + } } - public boolean reserve(int objectId, int index) { + public boolean reserve(long objectId, int index) { RenderObject obj = objectMap.get(objectId); if (obj != null) { obj.reserve(index); @@ -77,7 +107,7 @@ public T extract(RenderResource resource) { return (obj != null ? obj.getObject() : null); } public void dispose(RenderResource resource) { - int id = resource.getTicket().getObjectId(); + long id = resource.getTicket().getObjectId(); if (id >= 0) { RenderObject obj = objectMap.remove(id); if (obj != null) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 467297a298..a6246bb290 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -5,6 +5,7 @@ package com.jme3.renderer.framegraph; import com.jme3.renderer.framegraph.definitions.ResourceDef; +import java.util.Objects; /** * @@ -44,13 +45,21 @@ public boolean tickTimeout() { public void setTimeout(int timeout) { this.timeout = timeout; } + public void setObject(RenderObject object) { + setObject(object, object.getObject()); + } public void setObject(RenderObject object, T resource) { + Objects.requireNonNull(resource, "Object resource cannot be null."); if (undefined) { throw new IllegalStateException("Resource is already undefined."); } + if (object.isAcquired()) { + throw new IllegalStateException("Object is already acquired."); + } this.object = object; this.resource = resource; if (this.object != null) { + this.object.acquire(); ticket.setObjectId(this.object.getId()); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java deleted file mode 100644 index 18971238b3..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderingBlackboard.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.HashMap; - -/** - * - * @author codex - */ -public class RenderingBlackboard { - - private final HashMap parameters = new HashMap<>(); - - public void set(String name, Class type, T value) { - if (type == null) { - throw new NullPointerException("Parameter type cannot be null."); - } - if (name == null) { - return; - } - if (value == null) { - delete(name); - return; - } - Parameter param = parameters.get(name); - if (param != null) { - param.setValue(value); - } else { - parameters.put(name, new Parameter(type, value)); - } - } - public T get(String name, Class type) { - if (name == null) { - return null; - } - Parameter param = parameters.get(name); - if (param == null || !type.isAssignableFrom(param.type)) { - return null; - } - return (T)param.value; - } - - public boolean delete(String name) { - return name != null && parameters.remove(name) != null; - } - public void clear() { - parameters.clear(); - } - - private static class Parameter { - - private final Class type; - private T value; - - public Parameter(Class type, T value) { - this.type = type; - this.value = value; - } - - public void setValue(Object val) { - if (type.isAssignableFrom(val.getClass())) { - value = (T)val; - } else { - throw new IllegalArgumentException("Value of type "+val.getClass()+" replaces " - + "another value of a different type."); - } - } - - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 4f9e3442b9..5c36168505 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -81,10 +81,29 @@ protected RenderResource remove(int index) { return prev; } + /** + * Declares a new resource. + * + * @param + * @param producer + * @param def + * @param store + * @return + */ public ResourceTicket declare(ResourceProducer producer, ResourceDef def, ResourceTicket store) { return create(producer, def).getTicket().copyIndexTo(store); } + /** + * If the ticket contains a valid object ID, that object will be reserved + * at the index. + *

      + * Reserved objects cannot be allocated to another resource before the indexed + * pass occurs, unless that object is also reserved by another resource. + * + * @param passIndex + * @param ticket + */ public void reserve(int passIndex, ResourceTicket ticket) { if (ticket.getObjectId() >= 0) { map.reserve(ticket.getObjectId(), passIndex); @@ -97,6 +116,16 @@ public void reserve(int passIndex, ResourceTicket... tickets) { } } + /** + * References the resource associated with the ticket. + *

      + * The pass index indicates when the resource will be acquired by the entity + * which is referencing the resource, which is important for determining resource + * lifetime. + * + * @param passIndex + * @param ticket + */ public void reference(int passIndex, ResourceTicket ticket) { locate(ticket).reference(passIndex); } @@ -118,6 +147,15 @@ public void referenceOptional(int passIndex, ResourceTicket... tickets) { } } + /** + * Gets the definition of the resource associated with the ticket. + * + * @param + * @param + * @param type + * @param ticket + * @return + */ public > R getDefinition(Class type, ResourceTicket ticket) { ResourceDef def = locate(ticket).getDefinition(); if (type.isAssignableFrom(def.getClass())) { @@ -125,9 +163,27 @@ public > R getDefinition(Class type, ResourceTick } return null; } + + /** + * Marks the resource associated with the ticket as undefined. + *

      + * Undefined resources cannot hold objects. If an undefined resource is acquired acquired (unless with + * {@link #acquireOrElse(com.jme3.renderer.framegraph.ResourceTicket, java.lang.Object) acquireOrElse}), + * an exception will occur. + * + * @param ticket + */ public void setUndefined(ResourceTicket ticket) { locate(ticket).setUndefined(); } + + /** + * Marks the existing object held be the resource associated with the ticket as constant. + *

      + * Constant objects cannot be reallocated until the end of the frame. + * + * @param ticket + */ public void setConstant(ResourceTicket ticket) { RenderObject obj = locate(ticket).getObject(); if (obj != null) { @@ -150,6 +206,16 @@ protected T acquire(RenderResource resource, ResourceTicket ticket) { resource.getTicket().copyObjectTo(ticket); return resource.getResource(); } + /** + * Acquires and returns the value associated with the resource at the ticket. + *

      + * If the resource is virtual (not holding a object), then either an existing + * object will be reallocated to the resource or a new object will be created. + * + * @param + * @param ticket + * @return + */ public T acquire(ResourceTicket ticket) { RenderResource resource = locate(ticket); if (resource.isUndefined()) { @@ -166,6 +232,17 @@ public T acquireOrElse(ResourceTicket ticket, T value) { } return value; } + /** + * Acquires and assigns textures as color targets to the framebuffer. + *

      + * If a texture is already assigned to the framebuffer at the same color target index, + * then nothing will be changed at that index. + *

      + * Existing texture targets beyond the number of tickets passed will be removed. + * + * @param fbo + * @param tickets + */ public void acquireColorTargets(FrameBuffer fbo, ResourceTicket... tickets) { if (tickets.length == 0) { fbo.clearColorTargets(); @@ -186,6 +263,15 @@ public void acquireColorTargets(FrameBuffer fbo, ResourceTicket + * If the texture is already assigned to the framebuffer as the depth target, + * the nothing changes. + * + * @param fbo + * @param ticket + */ public void acquireDepthTarget(FrameBuffer fbo, ResourceTicket ticket) { Texture acquired = acquire((ResourceTicket)ticket); if (fbo.getDepthTarget() != null && acquired == fbo.getDepthTarget().getTexture()) { @@ -201,6 +287,16 @@ protected T extract(RenderResource resource, ResourceTicket ticket) { resource.getTicket().copyObjectTo(ticket); return map.extract(resource); } + /** + * Permanently extracts the object from the object manager. + *

      + * Extracted objects are no longer tracked by the object manager, + * and can therefore not be reallocated for any task. + * + * @param + * @param ticket + * @return + */ public T extract(ResourceTicket ticket) { RenderResource resource = locate(ticket); T object = extract(resource, ticket); @@ -217,6 +313,11 @@ public T extractOrElse(ResourceTicket ticket, T value) { return value; } + /** + * Releases the resource from use. + * + * @param ticket + */ public void release(ResourceTicket ticket) { RenderResource res = locate(ticket); res.release(); @@ -247,6 +348,10 @@ public void releaseOptional(ResourceTicket... tickets) { } } + /** + * Iteratively culls all resources and resource producers found + * to be unused. + */ public void cullUnreferenced() { LinkedList cull = new LinkedList<>(); for (RenderResource r : resources) { @@ -281,6 +386,10 @@ public void cullUnreferenced() { } } } + + /** + * Clears the resource list. + */ public void clear() { // TODO: throw exceptions for unreleased resources. int size = resources.size(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java index 0bade655af..bbd01fd02e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java @@ -15,7 +15,7 @@ public interface ResourceProducer { public int getExecutionIndex(); public boolean dereference(); - public boolean isReferenced(); + public boolean isUsed(); public Collection getInputTickets(); public Collection getOutputTickets(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index 168b6762b6..86423bcd91 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -4,8 +4,6 @@ */ package com.jme3.renderer.framegraph; -import java.util.ArrayList; - /** * References a {@link RenderResource} by either name or index. *

      @@ -18,12 +16,9 @@ */ public class ResourceTicket { - private static long nextId = 0; - - private final long id; private String name; private int localIndex; - private int objectId = -1; + private long objectId = -1; private ResourceTicket source; public ResourceTicket() { @@ -36,7 +31,6 @@ public ResourceTicket(int index) { this(null, index); } public ResourceTicket(String name, int index) { - this.id = nextId++; this.name = name; this.localIndex = index; } @@ -66,13 +60,10 @@ protected ResourceTicket setLocalIndex(int index) { this.localIndex = index; return this; } - public void setObjectId(int objectId) { + public void setObjectId(long objectId) { this.objectId = objectId; } - public long getId() { - return id; - } public String getName() { return name; } @@ -86,16 +77,19 @@ public int getWorldIndex() { public int getLocalIndex() { return localIndex; } - public int getObjectId() { + public long getObjectId() { return objectId; } public ResourceTicket getSource() { return source; } + public boolean hasSource() { + return source != null; + } @Override public String toString() { - return "Ticket[id="+id+", name="+name+", index="+localIndex+"]"; + return "Ticket[name="+name+", index="+localIndex+"]"; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java index b3a8ba9481..02ab274c0b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java @@ -9,8 +9,9 @@ /** * * @author codex + * @param */ -public abstract class AbstractResourceDef implements ResourceDef { +public abstract class AbstractResourceDef implements ResourceDef { private Consumer disposalMethod; private int staticTimeout = -1; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index 65ad268f48..ccb24521fe 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -20,13 +20,25 @@ public interface ResourceDef { */ public T createResource(); + /** + * Repurposes the given resource only if the resource is of + * a certain type. + *

      + * For reallocation, direct resources are preferred over indirect + * resources. Usually because direct resources are more performant. + * + * @param resource + * @return + */ + public T applyDirectResource(Object resource); + /** * Repurposes the given resource. * * @param resource * @return repurposed resource, or null if the given resource is not usable. */ - public T applyResource(Object resource); + public T applyIndirectResource(Object resource); /** * Returns the number of frames which the resource must be diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index d5abfe6b50..5aa1cae9ac 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -6,8 +6,9 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture; -import com.jme3.texture.Texture2D; -import com.jme3.texture.Texture3D; +import com.jme3.texture.image.ColorSpace; +import java.util.Objects; +import java.util.function.Function; /** * @@ -16,73 +17,200 @@ */ public class TextureDef extends AbstractResourceDef { - private int width, height, depth, samples; + private final Class type; + private Function textureBuilder; + private Function imageExtractor; + private int width = 128; + private int height = 128; + private int depth = 0; + private int samples = 1; private Image.Format format; + private ColorSpace colorSpace = ColorSpace.Linear; + private Texture.MagFilter magFilter = Texture.MagFilter.Nearest; + private Texture.MinFilter minFilter = Texture.MinFilter.NearestNearestMipMap; + private Texture.ShadowCompareMode shadowCompare; + private Texture.WrapMode wrapS, wrapT, wrapR; + private boolean formatFlexible = false; + private boolean colorSpaceFlexible = false; - public TextureDef(int width, int height, Image.Format format) { - this(width, height, 0, 1, format); + public TextureDef(Class type, Function textureBuilder) { + this(type, textureBuilder, Image.Format.RGBA8); } - public TextureDef(int width, int height, int depth, int samples, Image.Format format) { - this.width = width; - this.height = height; - this.depth = depth; - this.samples = samples; + public TextureDef(Class type, Function textureBuilder, Image.Format format) { + Objects.requireNonNull(type); + Objects.requireNonNull(textureBuilder); + Objects.requireNonNull(format); + this.type = type; + this.textureBuilder = textureBuilder; this.format = format; } - + @Override - public Texture createResource() { - if (samples != 1) { - return new Texture2D(width, height, samples, format); - } else { - return new Texture2D(width, height, format); + public T createResource() { + return createTexture(new Image(format, width, height, depth, null, colorSpace)); + } + @Override + public T applyDirectResource(Object resource) { + if (type.isAssignableFrom(resource.getClass())) { + T tex = (T)resource; + if (validateImage(tex.getImage())) { + setupTexture(tex); + return tex; + } } + return null; } @Override - public Texture applyResource(Object resource) { + public T applyIndirectResource(Object resource) { Image img; - if (resource instanceof Texture) { + if (imageExtractor != null) { + if ((img = imageExtractor.apply(resource)) == null) { + return null; + } + } else if (resource instanceof Texture) { img = ((Texture)resource).getImage(); } else if (resource instanceof Image) { img = (Image)resource; } else { return null; } - if (img.getWidth() == width && img.getHeight() == height && (img.getDepth() == depth || depth <= 0) - && img.getFormat() == format && img.getMultiSamples() == samples) { - if (depth <= 0) { - return new Texture2D(img); - } else { - return new Texture3D(img); - } + if (validateImage(img)) { + return textureBuilder.apply(img); } return null; } + + private T createTexture(Image img) { + T tex = textureBuilder.apply(img); + tex.getImage().setMultiSamples(samples); + setupTexture(tex); + return tex; + } + private void setupTexture(Texture tex) { + if (magFilter != null) { + tex.setMagFilter(magFilter); + } + if (minFilter != null) { + tex.setMinFilter(minFilter); + } + if (shadowCompare != null) { + tex.setShadowCompareMode(shadowCompare); + } + if (wrapS != null) { + tex.setWrap(Texture.WrapAxis.S, wrapS); + } + if (wrapT != null) { + tex.setWrap(Texture.WrapAxis.T, wrapT); + } + if (wrapR != null) { + tex.setWrap(Texture.WrapAxis.R, wrapR); + } + } + private boolean validateImage(Image img) { + return img.getWidth() == width && img.getHeight() == height && (depth == 0 || img.getDepth() == depth) + && (samples <= 0 || img.getMultiSamples() == samples) + && (img.getFormat() == format || (formatFlexible && img.getFormat().isDepthFormat() == format.isDepthFormat())) + && (colorSpaceFlexible || img.getColorSpace() == colorSpace); + } + public void setTextureBuilder(Function textureBuilder) { + Objects.requireNonNull(textureBuilder); + this.textureBuilder = textureBuilder; + } + public void setImageExtractor(Function imageExtractor) { + this.imageExtractor = imageExtractor; + } public void setWidth(int width) { + if (width <= 0) { + throw new IllegalArgumentException("Width must be greater than zero."); + } this.width = width; } public void setHeight(int height) { + if (height <= 0) { + throw new IllegalArgumentException("Height must be greater than zero."); + } this.height = height; } + public void setDepth(int depth) { + if (depth < 0) { + throw new IllegalArgumentException("Depth cannot be less than zero."); + } + this.depth = depth; + } + public void setSize(int width, int height) { + setWidth(width); + setHeight(height); + } + public void setSize(int width, int height, int depth) { + setWidth(width); + setHeight(height); + setDepth(depth); + } public void setSamples(int samples) { + if (samples <= 0) { + throw new IllegalArgumentException("Image samples must be greater than zero."); + } this.samples = samples; } public void setFormat(Image.Format format) { + Objects.requireNonNull(format); this.format = format; } + public void setFormatFlexible(boolean formatFlexible) { + this.formatFlexible = formatFlexible; + } + public void setColorSpace(ColorSpace colorSpace) { + this.colorSpace = colorSpace; + } + public void setMagFilter(Texture.MagFilter magFilter) { + this.magFilter = magFilter; + } + public void setMinFilter(Texture.MinFilter minFilter) { + this.minFilter = minFilter; + } + public void setColorSpaceFlexible(boolean colorSpaceFlexible) { + this.colorSpaceFlexible = colorSpaceFlexible; + } + public Class getType() { + return type; + } + public Function getTextureBuilder() { + return textureBuilder; + } + public Function getImageExtractor() { + return imageExtractor; + } public int getWidth() { return width; } public int getHeight() { return height; } + public int getDepth() { + return depth; + } public int getSamples() { return samples; } public Image.Format getFormat() { return format; } + public boolean isFormatFlexible() { + return formatFlexible; + } + public ColorSpace getColorSpace() { + return colorSpace; + } + public Texture.MagFilter getMagFilter() { + return magFilter; + } + public Texture.MinFilter getMinFilter() { + return minFilter; + } + public boolean isColorSpaceFlexible() { + return colorSpaceFlexible; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java index 2dc51adb6f..ded9da95cd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java @@ -15,43 +15,47 @@ public class ValueDef extends AbstractResourceDef { private final Class type; - private Function create; - private Consumer reset; + private Function builder; + private Consumer reviser; public ValueDef(Class type, Function create) { this.type = type; - this.create = create; + this.builder = create; } @Override public T createResource() { - return create.apply(null); + return builder.apply(null); } @Override - public T applyResource(Object resource) { - if (reset != null && type.isAssignableFrom(resource.getClass())) { + public T applyDirectResource(Object resource) { + if (reviser != null && type.isAssignableFrom(resource.getClass())) { T res = (T)resource; - reset.accept(res); + reviser.accept(res); return res; } return null; } + @Override + public T applyIndirectResource(Object resource) { + return null; + } - public void setCreate(Function create) { - this.create = create; + public void setBuilder(Function builder) { + this.builder = builder; } - public void setReset(Consumer reset) { - this.reset = reset; + public void setReviser(Consumer reviser) { + this.reviser = reviser; } public Class getType() { return type; } - public Function getCreate() { - return create; + public Function getBuilder() { + return builder; } - public Consumer getReset() { - return reset; + public Consumer getReviser() { + return reviser; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/AttributePass.java similarity index 57% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/AttributePass.java index f074a8950b..72f42b6fac 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/AttributePass.java @@ -9,45 +9,56 @@ import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.ValueDef; import java.util.function.Function; +import com.jme3.renderer.framegraph.GraphTarget; /** * * @author codex * @param */ -public class Attribute extends RenderPass implements Function { +public class AttributePass extends RenderPass implements Function { private final Class paramType; private String paramName; + private ResourceTicket in, out; private T value; - private ResourceTicket ticket; private ValueDef def; + private GraphTarget target; + private GraphSource source; - public Attribute(Class paramType) { + public AttributePass(Class paramType, String paramName) { this.paramType = paramType; + this.paramName = paramName; } @Override protected void initialize(FrameGraph frameGraph) { - ticket = addOutput("Value"); + in = addInput("Value"); + out = addOutput("Value"); def = new ValueDef<>(null, this); def.setDisposeOnRelease(true); def.setUseExisting(false); } @Override protected void prepare(FGRenderContext context) { - declare(def, ticket); + declare(def, out); + referenceOptional(in); } @Override protected void execute(FGRenderContext context) { - if (paramName != null) { - value = context.getBlackboard().get(paramName, paramType); + value = resources.acquireOrElse(in, null); + if (value != null && target != null) { + target.setGraphValue(context.getViewPort(), value); + resources.setConstant(in); + } + if (source != null) { + value = source.getGraphValue(context.getViewPort()); } if (value != null) { - resources.acquire(ticket); - resources.setConstant(ticket); + resources.acquire(out); + resources.setConstant(out); } else { - resources.setUndefined(ticket); + resources.setUndefined(out); } } @Override @@ -55,6 +66,10 @@ protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} @Override + public boolean isUsed() { + return super.isUsed() || in.hasSource(); + } + @Override public T apply(Object t) { return value; } @@ -62,8 +77,11 @@ public T apply(Object t) { public void setParamName(String name) { this.paramName = name; } - public void setValue(T value) { - this.value = value; + public void setTarget(GraphTarget target) { + this.target = target; + } + public void setSource(GraphSource source) { + this.source = source; } public Class getParamType() { @@ -72,8 +90,5 @@ public Class getParamType() { public String getParamName() { return paramName; } - public T getValue() { - return value; - } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 80847ae8a9..9f20af3416 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -4,15 +4,20 @@ */ package com.jme3.renderer.framegraph.passes; -import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; +import java.io.IOException; /** * @@ -21,18 +26,22 @@ public class BucketPass extends RenderPass { private Bucket bucket; - private DepthRange depth; + private final DepthRange depth = new DepthRange(); private int samples = 1; private boolean flush = true; private ResourceTicket inColor, inDepth, outColor, outDepth; + private TextureDef colorDef, depthDef; private Texture2D fTex; + public BucketPass() { + this(Bucket.Opaque, DepthRange.IDENTITY); + } public BucketPass(Bucket bucket) { this(bucket, DepthRange.IDENTITY); } public BucketPass(Bucket bucket, DepthRange depth) { this.bucket = bucket; - this.depth = depth; + this.depth.set(depth); if (this.bucket == Bucket.Inherit) { throw new IllegalArgumentException("Rendered bucket cannot be Inherit."); } @@ -41,17 +50,24 @@ public BucketPass(Bucket bucket, DepthRange depth) { @Override protected void initialize(FrameGraph frameGraph) { fTex = (Texture2D)frameGraph.getAssetManager().loadTexture("Common/Textures/MissingTexture.png"); - inColor = addInput("InColor"); - inDepth = addInput("InDepth"); - outColor = addOutput("OutDepth"); - outDepth = addOutput("OutDepth"); + inColor = addInput("Color"); + inDepth = addInput("Depth"); + outColor = addOutput("Color"); + outDepth = addOutput("Depth"); + colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); + depthDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img), Image.Format.Depth); + colorDef.setFormatFlexible(true); + depthDef.setFormatFlexible(true); } @Override protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - declare(new TextureDef(w, h, samples, Image.Format.RGBA8), outColor); - declare(new TextureDef(w, h, samples, Image.Format.Depth), outDepth); + colorDef.setSize(w, h); + depthDef.setSize(w, h); + declare(colorDef, outColor); + declare(depthDef, outDepth); + reserve(outColor, outDepth); referenceOptional(inColor, inDepth); } @Override @@ -75,9 +91,28 @@ protected void execute(FGRenderContext context) { protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(bucket, "bucket", Bucket.Opaque); + out.write(depth, "depth", DepthRange.IDENTITY); + out.write(samples, "samples", 1); + out.write(flush, "flush", true); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + bucket = in.readEnum("bucket", Bucket.class, Bucket.Opaque); + depth.set(in.readSavable("depth", DepthRange.class, DepthRange.IDENTITY)); + samples = in.readInt("samples", 1); + flush = in.readBoolean("flush", true); + if (samples <= 0) { + throw new IllegalArgumentException("Samples must be greater than zero."); + } + } public void setDepthRange(DepthRange depth) { - this.depth = depth; + this.depth.set(depth); } public DepthRange getDepthRange() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 06f1a1ca93..ae615a0833 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -4,7 +4,6 @@ */ package com.jme3.renderer.framegraph.passes; -import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.material.TechniqueDef; @@ -12,8 +11,8 @@ import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; import com.jme3.texture.Texture2D; /** @@ -24,6 +23,7 @@ public class DeferredPass extends RenderPass { private ResourceTicket depth, diffuse, specular, emissive, normal, outColor; private ResourceTicket lights; + private TextureDef colorDef; private Material material; @Override @@ -34,6 +34,8 @@ protected void initialize(FrameGraph frameGraph) { emissive = addInput("Emissive"); normal = addInput("Normal"); outColor = addOutput("Color"); + colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); + colorDef.setFormatFlexible(true); material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { t.setLogic(new DeferredSinglePassLightingLogic(t)); @@ -41,9 +43,8 @@ protected void initialize(FrameGraph frameGraph) { } @Override protected void prepare(FGRenderContext context) { - int w = context.getWidth(); - int h = context.getHeight(); - declare(new TextureDef(w, h, Image.Format.RGBA8), outColor); + colorDef.setSize(context.getWidth(), context.getHeight()); + declare(colorDef, outColor); reserve(outColor); reference(depth, diffuse, specular, emissive, normal); referenceOptional(lights); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 754388c05f..2f9ddbd3bf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -5,7 +5,6 @@ package com.jme3.renderer.framegraph.passes; import com.jme3.renderer.framegraph.definitions.ValueDef; -import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.light.Light; import com.jme3.light.LightList; import com.jme3.material.Material; @@ -15,12 +14,14 @@ import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; import java.util.LinkedList; +import java.util.function.Function; /** * @@ -30,32 +31,46 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private final static String GBUFFER_PASS = "GBufferPass"; - private ResourceTicket depth, diffuse, specular, emissive, normal; + private ResourceTicket diffuse, specular, emissive, normal, depth; private ResourceTicket lights; - private final ValueDef lightDef = new ValueDef(LightList.class, n -> new LightList(null)); + private TextureDef[] texDefs = new TextureDef[5]; + private ValueDef lightDef ; private final LinkedList accumulatedLights = new LinkedList<>(); private final ColorRGBA mask = new ColorRGBA(); @Override protected void initialize(FrameGraph frameGraph) { - depth = addOutput("Depth"); - diffuse = addOutput("Diffuse"); + diffuse = addOutput("Diffuse"); specular = addOutput("Specular"); emissive = addOutput("Emissive"); - normal = addOutput("normal"); - lightDef.setReset(list -> list.clear()); + normal = addOutput("normal"); + depth = addOutput("Depth"); + Function tex = img -> new Texture2D(img); + texDefs[0] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); + texDefs[1] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); + texDefs[2] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); + texDefs[3] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA32F); + texDefs[4] = new TextureDef<>(Texture2D.class, tex, Image.Format.Depth); + for (TextureDef d : texDefs) { + d.setFormatFlexible(true); + } + lightDef = new ValueDef(LightList.class, n -> new LightList(null)); + lightDef.setReviser(list -> list.clear()); } @Override protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); - declare(new TextureDef(w, h, Image.Format.Depth), depth); - declare(new TextureDef(w, h, Image.Format.RGBA16F), diffuse); - declare(new TextureDef(w, h, Image.Format.RGBA16F), specular); - declare(new TextureDef(w, h, Image.Format.RGBA16F), emissive); - declare(new TextureDef(w, h, Image.Format.RGBA32F), normal); + for (TextureDef d : texDefs) { + d.setSize(w, h); + } + declare(texDefs[0], diffuse); + declare(texDefs[1], specular); + declare(texDefs[2], emissive); + declare(texDefs[3], normal); + declare(texDefs[4], depth); declare(lightDef, lights); - reserve(depth, diffuse, specular, emissive, normal); + reserve(diffuse, specular, emissive, normal, depth); } @Override protected void execute(FGRenderContext context) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GraphSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GraphSource.java new file mode 100644 index 0000000000..9d4e90f243 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GraphSource.java @@ -0,0 +1,18 @@ +/* + * 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.passes; + +import com.jme3.renderer.ViewPort; + +/** + * + * @author codex + * @param + */ +public interface GraphSource { + + public T getGraphValue(ViewPort viewPort); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/JunctionPass.java similarity index 74% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/JunctionPass.java index 364bc99e68..97b6d2b5ea 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/JunctionPass.java @@ -13,11 +13,18 @@ * @author codex * @param */ -public class Junction extends RenderPass { +public class JunctionPass extends RenderPass { - private int length = 2; - private int index = 0; + private int length; private ResourceTicket output; + private GraphSource source; + + public JunctionPass() { + this(2); + } + public JunctionPass(int length) { + this.length = length; + } @Override protected void initialize(FrameGraph frameGraph) { @@ -28,7 +35,7 @@ protected void initialize(FrameGraph frameGraph) { } @Override protected void prepare(FGRenderContext context) { - output.setSource(getInputTickets().get(index)); + output.setSource(getInputTickets().get(source.getGraphValue(context.getViewPort()))); } @Override protected void execute(FGRenderContext context) {} @@ -37,13 +44,10 @@ protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} @Override - public boolean isReferenced() { + public boolean isUsed() { return true; } - - public void setIndex(int index) { - this.index = 0; - } + public void setLength(int length) { this.length = length; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java index 01c4a92580..c60222a4cb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java @@ -48,7 +48,7 @@ protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} @Override - public boolean isReferenced() { + public boolean isUsed() { return true; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java index 738607ae00..962c4abea2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java @@ -43,7 +43,7 @@ protected FrameBuffer createFrameBuffer(FGRenderContext context) { return new FrameBuffer(context.getWidth(), context.getHeight(), 1); } @Override - public boolean isReferenced() { + public boolean isUsed() { return true; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java index 6a1f35e0ea..941ba9a6e2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java @@ -47,7 +47,7 @@ protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} @Override - public boolean isReferenced() { + public boolean isUsed() { return true; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 7fa40bd5c3..26ecbc8fae 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -4,6 +4,11 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.renderer.framegraph.CameraSize; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; @@ -12,14 +17,16 @@ import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; +import java.io.IOException; import java.util.Arrays; import java.util.LinkedList; +import java.util.Objects; /** * * @author codex */ -public abstract class RenderPass implements ResourceProducer { +public abstract class RenderPass implements ResourceProducer, Savable { private static int nextId = 0; @@ -138,6 +145,28 @@ protected ResourceTicket addOutput(String name) { return addOutput(new ResourceTicket<>(name)); } + protected ResourceTicket getInputByName(String name) { + for (ResourceTicket t : inputs) { + if (name.equals(t.getName())) { + return t; + } + } + return null; + } + protected ResourceTicket getOutputByName(String name) { + for (ResourceTicket t : outputs) { + if (name.equals(t.getName())) { + return t; + } + } + return null; + } + + public void makeInput(RenderPass pass, String outTicket, String inTicket) { + ResourceTicket out = Objects.requireNonNull(pass.getOutputByName(outTicket)); + ResourceTicket in = Objects.requireNonNull(getInputByName(inTicket)); + in.setSource(out); + } public void disconnectFrom(RenderPass pass) { for (ResourceTicket in : inputs) { if (pass.getOutputTickets().contains(in.getSource())) { @@ -182,10 +211,10 @@ public int getExecutionIndex() { @Override public boolean dereference() { refs--; - return isReferenced(); + return isUsed(); } @Override - public boolean isReferenced() { + public boolean isUsed() { return refs > 0; } @Override @@ -200,6 +229,18 @@ public LinkedList getOutputTickets() { public String toString() { return getClass().getSimpleName(); } + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(id, "id", -1); + out.write(name, "name", "RenderPass"); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + id = in.readInt("id", -1); + name = in.readString("name", "RenderPass"); + } public static void setNextId(int id) { nextId = id; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index d7c95f2d9a..d170fc4157 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java @@ -14,8 +14,6 @@ import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; /** @@ -27,6 +25,7 @@ public class TileDeferredPass extends RenderPass { private ResourceTicket diffuse, specular, emissive, normal, depth, outColor; private ResourceTicket lights; private ResourceTicket tiles; + private TextureDef colorDef; private Material material; private final TiledRenderGrid tileInfo = new TiledRenderGrid(); @@ -38,6 +37,10 @@ protected void initialize(FrameGraph frameGraph) { normal = addInput("Normal"); depth = addInput("Depth"); outColor = addOutput("Color"); + lights = addInput("Lights"); + tiles = addInput("TileInfo"); + colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); + colorDef.setFormatFlexible(true); material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"); for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("TileBasedDeferredPass")) { t.setLogic(new TileBasedDeferredSinglePassLightingLogic(t, tileInfo)); @@ -45,7 +48,8 @@ protected void initialize(FrameGraph frameGraph) { } @Override protected void prepare(FGRenderContext context) { - declare(new TextureDef(context.getWidth(), context.getHeight(), Image.Format.RGBA8), outColor); + colorDef.setSize(context.getWidth(), context.getHeight()); + declare(colorDef, outColor); reserve(outColor); reference(diffuse, specular, emissive, normal, depth); referenceOptional(lights, tiles); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ValueOutput.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ValueOutput.java deleted file mode 100644 index f03f72035b..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ValueOutput.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.passes; - -import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.FGRenderContext; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.ResourceTicket; - -/** - * - * @author codex - * @param - */ -public class ValueOutput extends RenderPass { - - private final Class type; - private String target; - private ViewPort viewPort; - private ResourceTicket ticket; - - public ValueOutput(Class type, String target) { - this.type = type; - this.target = target; - } - - @Override - protected void initialize(FrameGraph frameGraph) { - ticket = addInput("Value"); - } - @Override - protected void prepare(FGRenderContext context) { - referenceOptional(ticket); - } - @Override - protected void execute(FGRenderContext context) { - if (viewPort == null || context.getViewPort() == viewPort) { - T value = resources.acquireOrElse(ticket, null); - if (value != null) { - context.getBlackboard().set(target, type, value); - resources.setConstant(ticket); - } - } - } - @Override - protected void reset(FGRenderContext context) {} - @Override - protected void cleanup(FrameGraph frameGraph) {} - - public void setTarget(String target) { - this.target = target; - } - public void setViewPort(ViewPort viewPort) { - this.viewPort = viewPort; - } - -} diff --git a/jme3-core/src/plugins/java/com/jme3/render/plugins/J3GLoader.java b/jme3-core/src/plugins/java/com/jme3/render/plugins/J3GLoader.java new file mode 100644 index 0000000000..804b49be0d --- /dev/null +++ b/jme3-core/src/plugins/java/com/jme3/render/plugins/J3GLoader.java @@ -0,0 +1,38 @@ +/* + * 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.render.plugins; + +import com.jme3.asset.AssetInfo; +import com.jme3.asset.AssetLoader; +import com.jme3.asset.AssetManager; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeImporter; +import com.jme3.export.Savable; +import java.io.IOException; + +/** + * + * @author codex + */ +public class J3GLoader implements AssetLoader, JmeImporter { + + public static final int CURRENT_VERSION = 0; + + private AssetManager assetManager; + + @Override + public Object load(AssetInfo assetInfo) throws IOException { + + } + @Override + public InputCapsule getCapsule(Savable id) {} + @Override + public AssetManager getAssetManager() { + return assetManager; + } + @Override + public int getFormatVersion() {} + +} From 4f0f352140d8a5a9a6e309463d37595accb0a4b2 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 17 May 2024 17:26:45 -0400 Subject: [PATCH 061/111] fixed framegraph use on multiple viewports binding textures too often --- .../main/java/com/jme3/post/FilterPass.java | 36 +++++++ .../com/jme3/post/FilterPostProcessor.java | 4 +- .../java/com/jme3/renderer/RenderManager.java | 47 +++++++-- .../jme3/renderer/framegraph/FrameGraph.java | 52 +++++++--- .../renderer/framegraph/RenderResource.java | 7 ++ .../renderer/framegraph/ResourceList.java | 20 +++- .../definitions/AbstractResourceDef.java | 1 + .../framegraph/definitions/TextureDef.java | 18 ++++ .../framegraph/passes/BucketPass.java | 10 +- .../framegraph/passes/DeferredPass.java | 9 +- .../framegraph/passes/RenderPass.java | 96 +++++++++++++------ 11 files changed, 228 insertions(+), 72 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/post/FilterPass.java diff --git a/jme3-core/src/main/java/com/jme3/post/FilterPass.java b/jme3-core/src/main/java/com/jme3/post/FilterPass.java new file mode 100644 index 0000000000..4a5922f059 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/post/FilterPass.java @@ -0,0 +1,36 @@ +/* + * 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.post; + +import com.jme3.asset.AssetManager; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.passes.RenderPass; + +/** + * + * @author codex + */ +public class FilterPass extends RenderPass { + + private Filter filter; + private AssetManager assetManager; + + @Override + protected void initialize(FrameGraph frameGraph) { + assetManager = frameGraph.getAssetManager(); + } + @Override + protected void prepare(FGRenderContext context) { + filter.init(assetManager, context.getRenderManager(), context.getViewPort(), context.getWidth(), context.getHeight()); + } + @Override + protected void execute(FGRenderContext context) {} + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + +} diff --git a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java index 24dbe5df94..c775240c54 100644 --- a/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java +++ b/jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java @@ -261,7 +261,6 @@ private void renderFilterChain(Renderer r, FrameBuffer sceneFb) { boolean msDepth = depthTexture != null && depthTexture.getImage().getMultiSamples() > 1; for (int i = 0; i < filters.size(); i++) { Filter filter = filters.get(i); - System.out.println("render filter: "+filter); if (prof != null) prof.spStep(SpStep.ProcPostFrame, FPP, filter.getName()); if (filter.isEnabled()) { if (filter.getPostRenderPasses() != null) { @@ -659,4 +658,5 @@ private void setupViewPortFrameBuffer() { viewPort.setOutputFrameBuffer(renderFrameBuffer); } } - } + +} 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 324c2b8d7c..b69cd02b45 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -67,6 +67,7 @@ import com.jme3.util.SafeArrayList; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.function.Predicate; @@ -88,6 +89,7 @@ public class RenderManager { private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); private final RenderObjectMap renderObjects = new RenderObjectMap(); + private final LinkedList executedFrameGraphs = new LinkedList<>(); private FrameGraph frameGraph; private Camera prevCam = null; private Material forcedMaterial = null; @@ -120,15 +122,35 @@ public RenderManager(Renderer renderer) { this.renderer = renderer; this.forcedOverrides.add(boundDrawBufferId); } - + + /** + * Gets the default FrameGraph used when a ViewPort does not have a + * FrameGraph already assigned to it. + * + * @return + */ public FrameGraph getFrameGraph() { return frameGraph; } - + + /** + * Sets the default FrameGraph used when a ViewPort does not have a + * FrameGraph already assigned to it. + *

      + * If null, ViewPorts without FrameGraphs will be rendered using the standard + * forward renderer. + * + * @param frameGraph default FrameGraph, or null + */ public void setFrameGraph(FrameGraph frameGraph) { this.frameGraph = frameGraph; } - + + /** + * Gets the map that stores and manages rendering objects used by FrameGraphs. + * + * @return + */ public RenderObjectMap getRenderObjectsMap() { return renderObjects; } @@ -1293,9 +1315,9 @@ public void renderViewPort(ViewPort vp, float tpf) { } if (fg != null) { - - fg.execute(); - + if (fg.execute()) { + executedFrameGraphs.add(fg); + } } else { if (prof != null) { @@ -1387,7 +1409,13 @@ public void render(float tpf, boolean mainFrameBufferActive) { } } - // flushMap unrecycled resources + // call post frames for executed frame graphs only + for (FrameGraph fg : executedFrameGraphs) { + fg.postFrame(); + } + executedFrameGraphs.clear(); + + // flush object map renderObjects.flushMap(); } @@ -1422,7 +1450,7 @@ public void setPassDrawBufferTargetIdToShaders(boolean v) { * Set a render filter. Every geometry will be tested against this filter * before rendering and will only be rendered if the filter returns true. * - * @param filter + * @param filter the render filter */ public void setRenderFilter(Predicate filter) { renderFilter = filter; @@ -1431,8 +1459,7 @@ public void setRenderFilter(Predicate filter) { /** * Returns the render filter that the RenderManager is currently using * - * @param filter - * the render filter + * @return */ public Predicate getRenderFilter() { return renderFilter; 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 0b485cc8c0..12f7cc6a97 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 @@ -34,6 +34,7 @@ public class FrameGraph implements Savable { private final LinkedList passes = new LinkedList<>(); private GraphConstructor constructor; private boolean debug = false; + private boolean viewPortRendered = false; public FrameGraph(AssetManager assetManager, RenderManager renderManager) { this.id = nextId++; @@ -42,7 +43,7 @@ public FrameGraph(AssetManager assetManager, RenderManager renderManager) { this.context = new FGRenderContext(this, renderManager); } - public void execute() { + public boolean execute() { // prepare passes if (constructor != null) { constructor.preparePasses(context); @@ -69,6 +70,17 @@ public void execute() { } // cleanup resources resources.clear(); + boolean vpr = viewPortRendered; + viewPortRendered = true; + return !vpr; + } + public void postFrame() { + // notify passes + for (RenderPass p : passes) { + p.postFrame(this); + } + // reset flags + viewPortRendered = false; } public T add(T pass) { @@ -86,7 +98,7 @@ public T add(T pass, int index) { passes.add(index, pass); pass.initializePass(this, index); for (RenderPass p : passes) { - p.shiftExecutionIndex(index, 1); + p.shiftExecutionIndex(index, true); } return pass; } @@ -115,30 +127,42 @@ public T get(Class type, int id) { return null; } public RenderPass remove(int i) { - RenderPass pass = passes.remove(i); - pass.cleanupPass(this); - for (RenderPass p : passes) { - p.disconnectFrom(pass); - p.shiftExecutionIndex(i, -1); + int j = 0; + RenderPass removed = null; + for (Iterator it = passes.iterator(); it.hasNext();) { + RenderPass p = it.next(); + if (removed != null) { + p.disconnectFrom(removed); + p.shiftExecutionIndex(i, false); + } else if (j++ == i) { + removed = p; + it.remove(); + } } - return pass; + if (removed != null) { + removed.cleanupPass(this); + } + return removed; } public boolean remove(RenderPass pass) { int i = 0; + boolean found = false; for (Iterator it = passes.iterator(); it.hasNext();) { RenderPass p = it.next(); + if (found) { + // shift execution indices down + p.disconnectFrom(pass); + p.shiftExecutionIndex(i, false); + continue; + } if (p == pass) { it.remove(); - break; + found = true; } i++; } - if (i < passes.size()) { + if (found) { pass.cleanupPass(this); - for (RenderPass p : passes) { - p.disconnectFrom(pass); - p.shiftExecutionIndex(i, -1); - } return true; } return false; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index a6246bb290..9607a1e3dd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -22,6 +22,7 @@ public class RenderResource { private T resource; private int refs = 0; private int timeout = 0; + private boolean survivesRefCull = false; private boolean undefined = false; public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { @@ -94,6 +95,9 @@ public int getIndex() { public int getNumReferences() { return refs; } + public void setSurvivesRefCull(boolean survivesRefCull) { + this.survivesRefCull = survivesRefCull; + } public boolean isVirtual() { return object == null && !undefined; @@ -107,6 +111,9 @@ public boolean isUsed() { public boolean isUndefined() { return undefined; } + public boolean isSurvivesRefCull() { + return survivesRefCull; + } @Override public String toString() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 5c36168505..fd845bb926 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -196,6 +196,16 @@ public void setConstantOptional(ResourceTicket ticket) { } } + /** + * Sets the resource at the ticket so that it cannot be culled + * by number of references. + * + * @param ticket + */ + public void setSurvivesReferenceCull(ResourceTicket ticket) { + locate(ticket).setSurvivesRefCull(true); + } + protected T acquire(RenderResource resource, ResourceTicket ticket) { if (!resource.isUsed()) { throw new IllegalStateException(resource+" was unexpectedly acquired."); @@ -349,13 +359,15 @@ public void releaseOptional(ResourceTicket... tickets) { } /** - * Iteratively culls all resources and resource producers found - * to be unused. + * Culls all resources and resource producers found to be unused. + *

      + * This should only be called after producers have fully counted their + * references, and prior to execution. */ public void cullUnreferenced() { LinkedList cull = new LinkedList<>(); for (RenderResource r : resources) { - if (r != null && !r.isReferenced()) { + if (r != null && !r.isReferenced() && !r.isSurvivesRefCull()) { cull.add(r); } } @@ -381,7 +393,7 @@ public void cullUnreferenced() { } // remove all output resources for (ResourceTicket t : producer.getOutputTickets()) { - remove(t.getWorldIndex()); + remove(t.getLocalIndex()); } } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java index 02ab274c0b..c18b0c6257 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java @@ -17,6 +17,7 @@ public abstract class AbstractResourceDef implements ResourceDef { private int staticTimeout = -1; private boolean useExisting = true; private boolean disposeOnRelease = false; + private boolean survivesReferenceCull = false; @Override public int getStaticTimeout() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 5aa1cae9ac..9a3cf74520 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -172,6 +172,16 @@ public void setMinFilter(Texture.MinFilter minFilter) { public void setColorSpaceFlexible(boolean colorSpaceFlexible) { this.colorSpaceFlexible = colorSpaceFlexible; } + public void setWrap(Texture.WrapMode mode) { + wrapS = wrapT = wrapR = mode; + } + public void setWrap(Texture.WrapAxis axis, Texture.WrapMode mode) { + switch (axis) { + case S: wrapS = mode; break; + case T: wrapT = mode; break; + case R: wrapR = mode; break; + } + } public Class getType() { return type; @@ -212,5 +222,13 @@ public Texture.MinFilter getMinFilter() { public boolean isColorSpaceFlexible() { return colorSpaceFlexible; } + public Texture.WrapMode getWrap(Texture.WrapAxis axis) { + switch (axis) { + case S: return wrapS; + case T: return wrapT; + case R: return wrapR; + default: throw new IllegalArgumentException(); + } + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 9f20af3416..d72529861f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -15,6 +15,7 @@ import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; import java.io.IOException; @@ -31,7 +32,6 @@ public class BucketPass extends RenderPass { private boolean flush = true; private ResourceTicket inColor, inDepth, outColor, outDepth; private TextureDef colorDef, depthDef; - private Texture2D fTex; public BucketPass() { this(Bucket.Opaque, DepthRange.IDENTITY); @@ -49,7 +49,6 @@ public BucketPass(Bucket bucket, DepthRange depth) { @Override protected void initialize(FrameGraph frameGraph) { - fTex = (Texture2D)frameGraph.getAssetManager().loadTexture("Common/Textures/MissingTexture.png"); inColor = addInput("Color"); inDepth = addInput("Depth"); outColor = addOutput("Color"); @@ -72,9 +71,10 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { - resources.acquireColorTargets(frameBuffer, outColor); - resources.acquireDepthTarget(frameBuffer, inDepth); - context.getRenderer().setFrameBuffer(frameBuffer); + FrameBuffer fb = getFrameBuffer(context, 1); + resources.acquireColorTargets(fb, outColor); + resources.acquireDepthTarget(fb, inDepth); + context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); context.transferTextures(resources.acquireOrElse(inColor, null), resources.acquireOrElse(inDepth, null)); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index ae615a0833..071644adca 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -51,8 +51,9 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { - resources.acquireColorTargets(frameBuffer, outColor); - context.getRenderer().setFrameBuffer(frameBuffer); + FrameBuffer fb = getFrameBuffer(context, 1); + resources.acquireColorTargets(fb, outColor); + context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); material.setTexture("Context_InGBuff1", resources.acquire(specular)); @@ -72,10 +73,6 @@ protected void execute(FGRenderContext context) { protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} - @Override - protected FrameBuffer createFrameBuffer(FGRenderContext context) { - return new FrameBuffer(context.getWidth(), context.getHeight(), 1); - } public void setDepth(ResourceTicket depth) { this.depth = depth; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 26ecbc8fae..a3ed6768e7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -19,6 +19,7 @@ import com.jme3.texture.FrameBuffer; import java.io.IOException; import java.util.Arrays; +import java.util.Iterator; import java.util.LinkedList; import java.util.Objects; @@ -30,15 +31,14 @@ public abstract class RenderPass implements ResourceProducer, Savable { private static int nextId = 0; - private final LinkedList inputs = new LinkedList<>(); - private final LinkedList outputs = new LinkedList<>(); - private final CameraSize camSize = new CameraSize(); private int id = nextId++; private String name = ""; private int index = -1; private int refs = 0; + private final LinkedList inputs = new LinkedList<>(); + private final LinkedList outputs = new LinkedList<>(); + private final LinkedList frameBuffers = new LinkedList<>(); protected ResourceList resources; - protected FrameBuffer frameBuffer; public void initializePass(FrameGraph frameGraph, int index) { this.index = index; @@ -52,18 +52,23 @@ public void prepareRender(FGRenderContext context) { prepare(context); } public void executeRender(FGRenderContext context) { - if (camSize.update(context.getCameraSize()) || frameBuffer == null) { - if (frameBuffer != null) { - disposeFrameBuffer(frameBuffer); - } - frameBuffer = createFrameBuffer(context); - } execute(context); releaseAll(); } public void resetRender(FGRenderContext context) { reset(context); } + public void postFrame(FrameGraph frameGraph) { + for (Iterator it = frameBuffers.iterator(); it.hasNext();) { + PassFrameBuffer fb = it.next(); + if (!fb.used) { + fb.dispose(); + it.remove(); + } else { + fb.used = false; + } + } + } public void cleanupPass(FrameGraph frameGraph) { cleanup(frameGraph); for (ResourceTicket t : inputs) { @@ -80,16 +85,12 @@ public void cleanupPass(FrameGraph frameGraph) { protected abstract void reset(FGRenderContext context); protected abstract void cleanup(FrameGraph frameGraph); - protected FrameBuffer createFrameBuffer(FGRenderContext context) { - return null; - } - protected void disposeFrameBuffer(FrameBuffer fb) { - fb.dispose(); - } - protected ResourceTicket declare(ResourceDef def, ResourceTicket ticket) { + return resources.declare(this, def, ticket); + } + protected ResourceTicket declareLocal(ResourceDef def, ResourceTicket ticket) { ticket = resources.declare(this, def, ticket); - //addOutput(ticket); + resources.setSurvivesReferenceCull(ticket); return ticket; } protected void reserve(ResourceTicket ticket) { @@ -131,9 +132,6 @@ protected ResourceTicket addInput(ResourceTicket input) { inputs.add(input); return input; } - protected void addInputs(ResourceTicket... inputs) { - this.inputs.addAll(Arrays.asList(inputs)); - } protected ResourceTicket addOutput(ResourceTicket output) { outputs.add(output); return output; @@ -144,7 +142,6 @@ protected ResourceTicket addInput(String name) { protected ResourceTicket addOutput(String name) { return addOutput(new ResourceTicket<>(name)); } - protected ResourceTicket getInputByName(String name) { for (ResourceTicket t : inputs) { if (name.equals(t.getName())) { @@ -162,6 +159,20 @@ protected ResourceTicket getOutputByName(String name) { return null; } + protected FrameBuffer getFrameBuffer(int width, int height, int samples) { + for (PassFrameBuffer fb : frameBuffers) { + if (fb.qualifies(width, height, samples)) { + return fb.use(); + } + } + PassFrameBuffer fb = new PassFrameBuffer(width, height, samples); + frameBuffers.add(fb); + return fb.use(); + } + protected FrameBuffer getFrameBuffer(FGRenderContext context, int samples) { + return getFrameBuffer(context.getWidth(), context.getHeight(), samples); + } + public void makeInput(RenderPass pass, String outTicket, String inTicket) { ResourceTicket out = Objects.requireNonNull(pass.getOutputByName(outTicket)); ResourceTicket in = Objects.requireNonNull(getInputByName(inTicket)); @@ -178,20 +189,18 @@ public void disconnectFrom(RenderPass pass) { public void countReferences() { refs = outputs.size(); } + public void shiftExecutionIndex(int threshold, boolean positive) { + if (index > threshold) { + index += (positive ? 1 : -1); + } + } + public void setName(String name) { this.name = name; } public void setId(int id) { this.id = id; } - public void useNextId() { - id = nextId++; - } - public void shiftExecutionIndex(int base, int amount) { - if (index > base) { - index += amount; - } - } public String getName() { return name; @@ -199,7 +208,6 @@ public String getName() { public int getId() { return id; } - public boolean isAssigned() { return index >= 0; } @@ -246,4 +254,30 @@ public static void setNextId(int id) { nextId = id; } + private static class PassFrameBuffer { + + public final FrameBuffer frameBuffer; + public boolean used = false; + + public PassFrameBuffer(int width, int height, int samples) { + frameBuffer = new FrameBuffer(width, height, samples); + } + + public FrameBuffer use() { + used = true; + return frameBuffer; + } + + public boolean qualifies(int width, int height, int samples) { + return frameBuffer.getWidth() == width + && frameBuffer.getHeight() == height + && frameBuffer.getSamples() == samples; + } + + public void dispose() { + frameBuffer.dispose(); + } + + } + } From 1661dccac044e6b4a2a7a49a944f74bb0869c693 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 20 May 2024 15:59:59 -0400 Subject: [PATCH 062/111] fixed depth texture filtering --- .../main/java/com/jme3/app/BasicProfiler.java | 2 + .../java/com/jme3/app/DetailedProfiler.java | 11 ++ .../java/com/jme3/profile/AppProfiler.java | 18 ++- .../main/java/com/jme3/profile/FgStep.java | 15 ++ .../main/java/com/jme3/profile/VpStep.java | 4 + .../java/com/jme3/renderer/RenderManager.java | 47 ++++--- .../framegraph/DeferredGraphConstructor.java | 29 ++-- .../renderer/framegraph/FGRenderContext.java | 2 +- .../framegraph/ForwardGraphConstructor.java | 21 ++- .../jme3/renderer/framegraph/FrameGraph.java | 72 ++++++---- .../renderer/framegraph/RenderObjectMap.java | 131 +++++++++++++----- .../renderer/framegraph/RenderResource.java | 15 +- .../renderer/framegraph/ResourceList.java | 48 +++++-- .../definitions/AbstractResourceDef.java | 1 - .../framegraph/definitions/TextureDef.java | 23 ++- .../{passes => io}/GraphSource.java | 2 +- .../framegraph/{ => io}/GraphTarget.java | 2 +- .../framegraph/io/MatParamTargetControl.java | 67 +++++++++ .../{AttributePass.java => Attribute.java} | 22 +-- .../framegraph/passes/BucketPass.java | 11 +- .../framegraph/passes/DeferredPass.java | 1 + .../framegraph/passes/GBufferPass.java | 56 ++------ .../{JunctionPass.java => Junction.java} | 25 +++- .../framegraph/passes/OutputBucketPass.java | 24 ++++ .../framegraph/passes/OutputPass.java | 28 ++-- .../framegraph/passes/PostProcessingPass.java | 31 +++++ .../framegraph/passes/RenderPass.java | 79 ++++++----- .../framegraph/passes/TileDeferredPass.java | 9 +- .../renderer/framegraph/passes/Value.java | 13 ++ .../ShadingCommon/TextureTransfer.j3md | 2 - .../com/jme3/render/plugins/J3GLoader.java | 38 ----- .../jme3test/renderpath/TestShadingModel.java | 47 +++++-- 32 files changed, 599 insertions(+), 297 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/profile/FgStep.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{passes => io}/GraphSource.java (89%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{ => io}/GraphTarget.java (91%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/{AttributePass.java => Attribute.java} (79%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/{JunctionPass.java => Junction.java} (63%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Value.java delete mode 100644 jme3-core/src/plugins/java/com/jme3/render/plugins/J3GLoader.java diff --git a/jme3-core/src/main/java/com/jme3/app/BasicProfiler.java b/jme3-core/src/main/java/com/jme3/app/BasicProfiler.java index 1c95730bbc..bbacb524a4 100644 --- a/jme3-core/src/main/java/com/jme3/app/BasicProfiler.java +++ b/jme3-core/src/main/java/com/jme3/app/BasicProfiler.java @@ -35,6 +35,7 @@ import com.jme3.profile.AppProfiler; import com.jme3.profile.AppStep; +import com.jme3.profile.FgStep; import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; import com.jme3.renderer.ViewPort; @@ -204,4 +205,5 @@ public void vpStep(VpStep step, ViewPort vp, Bucket bucket) { @Override public void spStep(SpStep step, String... additionalInfo) { } + } diff --git a/jme3-core/src/main/java/com/jme3/app/DetailedProfiler.java b/jme3-core/src/main/java/com/jme3/app/DetailedProfiler.java index 2936a30072..dad7c538cd 100644 --- a/jme3-core/src/main/java/com/jme3/app/DetailedProfiler.java +++ b/jme3-core/src/main/java/com/jme3/app/DetailedProfiler.java @@ -57,6 +57,7 @@ public class DetailedProfiler implements AppProfiler { private String curAppPath = null; private String curVpPath = null; private String curSpPath = null; + private String curFgPath = null; private VpStep lastVpStep = null; private final StringBuilder path = new StringBuilder(256); @@ -185,6 +186,16 @@ public void spStep(SpStep step, String... additionalInfo) { } } + + @Override + public void fgStep(FgStep step, String... additionalInfo) { + if (data != null) { + curFgPath = getPath("", additionalInfo); + path.setLength(0); + path.append(curAppPath).append("/").append(curVpPath).append(curFgPath); + addStep(path.toString(), System.nanoTime()); + } + } public Map getStats() { if (data != null) { diff --git a/jme3-core/src/main/java/com/jme3/profile/AppProfiler.java b/jme3-core/src/main/java/com/jme3/profile/AppProfiler.java index e3efc8e3af..e761c530d7 100644 --- a/jme3-core/src/main/java/com/jme3/profile/AppProfiler.java +++ b/jme3-core/src/main/java/com/jme3/profile/AppProfiler.java @@ -73,12 +73,28 @@ public interface AppProfiler { /** * Called at the beginning of the specified SpStep (SceneProcessor step). - * For more detailed steps it is possible to provide additional information as strings, like the name of the processor. + *

      + * For more detailed steps it is possible to provide additional information as strings, + * like the name of the processor. * * @param step the SceneProcessor step that's about to begin * @param additionalInfo information about the SceneProcessor step */ public void spStep(SpStep step, String... additionalInfo); + + /** + * Called at the beginning of the specified FgStep (FrameGraph step). + *

      + * For more detailed steps it is possible to provide additional information as strings, + * such as the name of the pass. + * + * @param step + * @param additionalInfo + */ + public default void fgStep(FgStep step, String... additionalInfo) { + // implementation is optional + } + } diff --git a/jme3-core/src/main/java/com/jme3/profile/FgStep.java b/jme3-core/src/main/java/com/jme3/profile/FgStep.java new file mode 100644 index 0000000000..4c698007aa --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/profile/FgStep.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.profile; + +/** + * + * @author codex + */ +public enum FgStep { + Prepare, + Execute, + Reset, +} diff --git a/jme3-core/src/main/java/com/jme3/profile/VpStep.java b/jme3-core/src/main/java/com/jme3/profile/VpStep.java index 9dff853681..fa78f82efe 100644 --- a/jme3-core/src/main/java/com/jme3/profile/VpStep.java +++ b/jme3-core/src/main/java/com/jme3/profile/VpStep.java @@ -48,6 +48,10 @@ public enum VpStep { PostFrame, ProcEndRender, RenderBucket, + FrameGraphSetup, + FrameGraphCull, + FrameGraphExecute, + FrameGraphReset, EndRender } 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 b69cd02b45..b8768ce8f5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -151,7 +151,7 @@ public void setFrameGraph(FrameGraph frameGraph) { * * @return */ - public RenderObjectMap getRenderObjectsMap() { + public RenderObjectMap getRenderObjectMap() { return renderObjects; } @@ -1264,14 +1264,14 @@ public void renderViewPort(ViewPort vp, float tpf) { if (fg == null) { fg = frameGraph; } - if (fg != null) { - fg.getContext().update(vp, prof, tpf); - } - if (processors != null) { - if (prof != null) { - prof.vpStep(VpStep.PreFrame, vp, null); - } + if (prof != null && (fg != null || processors != null)) { + prof.vpStep(VpStep.PreFrame, vp, null); + } + if (fg != null) { + fg.configure(vp, prof, tpf); + fg.preFrame(); + } else if (processors != null) { for (SceneProcessor p : processors.getArray()) { if (!p.isInitialized()) { p.initialize(this, vp); @@ -1301,11 +1301,13 @@ public void renderViewPort(ViewPort vp, float tpf) { 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); - } + + if (prof != null && (fg != null || processors != null)) { + prof.vpStep(VpStep.PostQueue, vp, null); + } + if (fg != null) { + fg.postQueue(); + } else if (processors != null) { for (SceneProcessor p : processors.getArray()) { if (prof != null) { prof.spStep(SpStep.ProcPostQueue, p.getClass().getSimpleName()); @@ -1315,6 +1317,7 @@ public void renderViewPort(ViewPort vp, float tpf) { } if (fg != null) { + // returns true on first execution this frame if (fg.execute()) { executedFrameGraphs.add(fg); } @@ -1339,21 +1342,22 @@ public void renderViewPort(ViewPort vp, float tpf) { prof.vpStep(VpStep.ProcEndRender, vp, null); } } - //renders the translucent objects queue after processors have been rendered + + // render the translucent objects queue after processors have been rendered renderTranslucentQueue(vp); } - // clearMap any remaining spatials that were not rendered. + // clear any remaining spatials that were not rendered. clearQueue(vp); - - if (prof != null) { - prof.vpStep(VpStep.EndRender, vp, null); - } if (fg != null) { renderObjects.clearReservations(); } + + if (prof != null) { + prof.vpStep(VpStep.EndRender, vp, null); + } } @@ -1376,8 +1380,9 @@ public void render(float tpf, boolean mainFrameBufferActive) { if (renderer instanceof NullRenderer) { return; } - + uniformBindingManager.newFrame(); + renderObjects.newFrame(); if (prof != null) { prof.appStep(AppStep.RenderPreviewViewPorts); @@ -1411,7 +1416,7 @@ public void render(float tpf, boolean mainFrameBufferActive) { // call post frames for executed frame graphs only for (FrameGraph fg : executedFrameGraphs) { - fg.postFrame(); + fg.renderingComplete(); } executedFrameGraphs.clear(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java index d5061a0e6a..2667a02db4 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java @@ -4,12 +4,14 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.framegraph.passes.DeferredPass; import com.jme3.renderer.framegraph.passes.GBufferPass; import com.jme3.renderer.framegraph.passes.OutputBucketPass; import com.jme3.renderer.framegraph.passes.OutputPass; import com.jme3.renderer.framegraph.passes.PostProcessingPass; import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.texture.Texture2D; /** * @@ -20,35 +22,42 @@ public class DeferredGraphConstructor implements GraphConstructor { private GBufferPass gbuf; private DeferredPass deferred; private OutputPass defOut; + private Attribute depthAttr; private OutputBucketPass sky, transparent, gui, translucent; private PostProcessingPass post; @Override public void addPasses(FrameGraph frameGraph) { + gbuf = frameGraph.add(new GBufferPass()); deferred = frameGraph.add(new DeferredPass()); defOut = frameGraph.add(new OutputPass()); + depthAttr = frameGraph.add(new Attribute<>()); sky = frameGraph.add(new OutputBucketPass(Bucket.Sky, DepthRange.REAR)); transparent = frameGraph.add(new OutputBucketPass(Bucket.Transparent)); gui = frameGraph.add(new OutputBucketPass(Bucket.Gui, DepthRange.FRONT)); post = frameGraph.add(new PostProcessingPass()); translucent = frameGraph.add(new OutputBucketPass(Bucket.Translucent)); + + deferred.makeInput(gbuf, "Diffuse", "Diffuse"); + deferred.makeInput(gbuf, "Specular", "Specular"); + deferred.makeInput(gbuf, "Emissive", "Emissive"); + deferred.makeInput(gbuf, "Normal", "Normal"); + deferred.makeInput(gbuf, "Depth", "Depth"); + deferred.makeInput(gbuf, "Lights", "Lights"); + + defOut.makeInput(deferred, "Color", "Color"); + defOut.makeInput(gbuf, "Depth", "Depth"); + + depthAttr.makeInput(gbuf, "Depth", "Value"); + depthAttr.setName("DepthDebug"); + } @Override public void preparePasses(FGRenderContext context) { gbuf.prepareRender(context); - - deferred.setDepth(gbuf.getDepth()); - deferred.setDiffuse(gbuf.getDiffuse()); - deferred.setEmissive(gbuf.getEmissive()); - deferred.setNormal(gbuf.getNormal()); - deferred.setLights(gbuf.getLights()); - deferred.setSpecular(gbuf.getSpecular()); deferred.prepareRender(context); - - defOut.setInColor(deferred.getOutColor()); - defOut.setInDepth(gbuf.getDepth()); defOut.prepareRender(context); sky.prepareRender(context); 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 8f3e72228d..7c6200dadc 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 @@ -71,7 +71,7 @@ public FGRenderContext(FrameGraph frameGraph, RenderManager renderManager) { this.screen = new FullScreenQuad(this.frameGraph.getAssetManager()); } - public void update(ViewPort vp, AppProfiler profiler, float tpf) { + public void target(ViewPort vp, AppProfiler profiler, float tpf) { this.viewPort = vp; this.profiler = profiler; this.tpf = tpf; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java index d5609aae89..546a78badb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java @@ -4,8 +4,12 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.passes.Attribute; +import com.jme3.renderer.framegraph.passes.BucketPass; import com.jme3.renderer.framegraph.passes.OutputBucketPass; +import com.jme3.renderer.framegraph.passes.OutputPass; import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.texture.Texture2D; /** * @@ -13,15 +17,28 @@ */ public class ForwardGraphConstructor implements GraphConstructor { - private OutputBucketPass opaque, sky, transparent, gui, translucent; + private BucketPass opaque; + private OutputPass opaqueOut; + private Attribute opaqueAttr; + private OutputBucketPass sky, transparent, gui, translucent; @Override public void addPasses(FrameGraph frameGraph) { - opaque = frameGraph.add(new OutputBucketPass(Bucket.Opaque)); + + opaque = frameGraph.add(new BucketPass(Bucket.Opaque)); + opaqueOut = frameGraph.add(new OutputPass()); sky = frameGraph.add(new OutputBucketPass(Bucket.Sky, DepthRange.REAR)); transparent = frameGraph.add(new OutputBucketPass(Bucket.Transparent)); gui = frameGraph.add(new OutputBucketPass(Bucket.Gui, DepthRange.FRONT)); translucent = frameGraph.add(new OutputBucketPass(Bucket.Translucent)); + opaqueAttr = frameGraph.add(new Attribute<>()); + + opaqueOut.makeInput(opaque, "Color", "Color"); + opaqueOut.makeInput(opaque, "Depth", "Depth"); + + opaqueAttr.makeInput(opaque, "Color", "Value"); + opaqueAttr.setName("OpaqueColor"); + } @Override public void preparePasses(FGRenderContext context) { 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 12f7cc6a97..5e8f93af44 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 @@ -11,10 +11,13 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; +import com.jme3.profile.AppProfiler; +import com.jme3.profile.FgStep; +import com.jme3.profile.VpStep; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; import java.io.IOException; import java.util.Arrays; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -25,62 +28,86 @@ */ public class FrameGraph implements Savable { - private static int nextId = 0; - - private final int id; private final AssetManager assetManager; private final ResourceList resources; private final FGRenderContext context; private final LinkedList passes = new LinkedList<>(); private GraphConstructor constructor; private boolean debug = false; - private boolean viewPortRendered = false; + private boolean rendered = false; public FrameGraph(AssetManager assetManager, RenderManager renderManager) { - this.id = nextId++; this.assetManager = assetManager; - this.resources = new ResourceList(renderManager.getRenderObjectsMap()); + this.resources = new ResourceList(renderManager.getRenderObjectMap()); this.context = new FGRenderContext(this, renderManager); } + public void configure(ViewPort vp, AppProfiler prof, float tpf) { + context.target(vp, prof, tpf); + } + public void preFrame() { + for (RenderPass p : passes) { + p.preFrame(context); + } + } + public void postQueue() { + for (RenderPass p : passes) { + p.postQueue(context); + } + } public boolean execute() { - // prepare passes - if (constructor != null) { - constructor.preparePasses(context); - } else for (RenderPass p : passes) { + // prepare + ViewPort vp = context.getViewPort(); + AppProfiler prof = context.getProfiler(); + if (prof != null) prof.vpStep(VpStep.FrameGraphSetup, vp, null); + if (!rendered) { + resources.beginRenderingSession(); + } + for (RenderPass p : passes) { + if (prof != null) { + prof.fgStep(FgStep.Prepare, p.getProfilerName()); + } p.prepareRender(context); } + // cull resources + if (prof != null) prof.vpStep(VpStep.FrameGraphCull, vp, null); for (RenderPass p : passes) { p.countReferences(); } - // cull resources resources.cullUnreferenced(); - // execute passes + // execute + if (prof != null) prof.vpStep(VpStep.FrameGraphExecute, vp, null); context.pushRenderSettings(); for (RenderPass p : passes) { if (p.isUsed()) { + if (prof != null) { + prof.fgStep(FgStep.Execute, p.getProfilerName()); + } p.executeRender(context); context.popRenderSettings(); } } context.popFrameBuffer(); - // reset passes + // reset + if (prof != null) prof.vpStep(VpStep.FrameGraphReset, vp, null); for (RenderPass p : passes) { + if (prof != null) { + prof.fgStep(FgStep.Reset, p.getProfilerName()); + } p.resetRender(context); } // cleanup resources resources.clear(); - boolean vpr = viewPortRendered; - viewPortRendered = true; - return !vpr; + if (rendered) return false; + else return (rendered = true); } - public void postFrame() { + public void renderingComplete() { // notify passes for (RenderPass p : passes) { - p.postFrame(this); + p.renderingComplete(); } // reset flags - viewPortRendered = false; + rendered = false; } public T add(T pass) { @@ -185,9 +212,6 @@ public void setDebug(boolean debug) { this.debug = debug; } - public int getId() { - return id; - } public AssetManager getAssetManager() { return assetManager; } @@ -195,7 +219,7 @@ public ResourceList getResources() { return resources; } public RenderObjectMap getRecycler() { - return context.getRenderManager().getRenderObjectsMap(); + return context.getRenderManager().getRenderObjectMap(); } public FGRenderContext getContext() { return context; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 7ce36425d2..5ec23e9257 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -7,15 +7,26 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import java.util.HashMap; import java.util.Iterator; +import java.util.logging.Logger; /** * * @author codex */ public class RenderObjectMap { + + private static final Logger LOG = Logger.getLogger(RenderObjectMap.class.getName()); private final HashMap objectMap = new HashMap<>(); private final int timeout = 1; + private int totalAllocations = 0; + private int officialReservations = 0; + private int completedReservations = 0; + private int failedReservations = 0; + private int objectsCreated = 0; + private int objectsReallocated = 0; + private int totalObjects = 0; + private int flushedObjects = 0; protected RenderObject create(ResourceDef def) { return create(def, def.createResource()); @@ -43,55 +54,65 @@ public void allocate(RenderResource resource) { if (resource.isUndefined()) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); } + totalAllocations++; ResourceDef def = resource.getDefinition(); - long id = resource.getTicket().getObjectId(); - // allocate reserved object - if (id >= 0) { - RenderObject obj = objectMap.get(id); - if (obj != null && isAvailable(obj) && - (obj.isReservedAt(resource.getLifeTime().getStartIndex()) - || !obj.isReservedWithin(resource.getLifeTime()))) { - // reserved object is only applied if it is accepted by the definition - T r = def.applyDirectResource(obj.getObject()); - if (r == null) { - r = def.applyIndirectResource(obj.getObject()); - } - if (r != null) { - resource.setObject(obj, r); - return; + if (def.isUseExisting()) { + long id = resource.getTicket().getObjectId(); + // allocate reserved object + if (id >= 0) { + RenderObject obj = objectMap.get(id); + if (obj != null && isAvailable(obj) + && (obj.isReservedAt(resource.getLifeTime().getStartIndex()) + || !obj.isReservedWithin(resource.getLifeTime()))) { + // reserved object is only applied if it is accepted by the definition + T r = def.applyDirectResource(obj.getObject()); + if (r == null) { + r = def.applyIndirectResource(obj.getObject()); + } + if (r != null) { + resource.setObject(obj, r); + completedReservations++; + objectsReallocated++; + return; + } } + failedReservations++; } - } - // find object to allocate - T indirectRes = null; - RenderObject indirectObj = null; - for (RenderObject obj : objectMap.values()) { - if (isAvailable(obj) && !obj.isReservedWithin(resource.getLifeTime())) { - T r = def.applyDirectResource(obj.getObject()); - if (r != null) { - resource.setObject(obj, r); - return; - } - if (indirectObj == null) { - indirectRes = def.applyIndirectResource(obj.getObject()); - if (indirectRes != null) { - indirectObj = obj; + // find object to allocate + T indirectRes = null; + RenderObject indirectObj = null; + for (RenderObject obj : objectMap.values()) { + if (isAvailable(obj) && !obj.isReservedWithin(resource.getLifeTime())) { + T r = def.applyDirectResource(obj.getObject()); + if (r != null) { + resource.setObject(obj, r); + objectsReallocated++; + return; + } + if (indirectObj == null) { + indirectRes = def.applyIndirectResource(obj.getObject()); + if (indirectRes != null) { + indirectObj = obj; + } } } } + if (indirectObj != null) { + // allocate indirect object + resource.setObject(indirectObj, indirectRes); + objectsReallocated++; + return; + } } - if (indirectObj != null) { - // allocate indirect object - resource.setObject(indirectObj, indirectRes); - } else { - // create new object - resource.setObject(create(def)); - } + // create new object + resource.setObject(create(def)); + objectsCreated++; } public boolean reserve(long objectId, int index) { RenderObject obj = objectMap.get(objectId); if (obj != null) { obj.reserve(index); + officialReservations++; return true; } return false; @@ -116,17 +137,28 @@ public void dispose(RenderResource resource) { } } + public void newFrame() { + totalAllocations = 0; + officialReservations = 0; + completedReservations = 0; + failedReservations = 0; + objectsCreated = 0; + objectsReallocated = 0; + flushedObjects = 0; + } public void clearReservations() { for (RenderObject obj : objectMap.values()) { obj.clearReservations(); } } public void flushMap() { + totalObjects = objectMap.size(); for (Iterator it = objectMap.values().iterator(); it.hasNext();) { RenderObject obj = it.next(); if (!obj.tickTimeout()) { obj.dispose(); it.remove(); + flushedObjects++; continue; } obj.setConstant(false); @@ -138,5 +170,30 @@ public void clearMap() { } objectMap.clear(); } + + public int getTotalAllocations() { + return totalAllocations; + } + public int getOfficialReservations() { + return officialReservations; + } + public int getCompletedReservations() { + return completedReservations; + } + public int getFailedReservations() { + return failedReservations; + } + public int getObjectsCreated() { + return objectsCreated; + } + public int getObjectsReallocated() { + return objectsReallocated; + } + public int getTotalObjects() { + return totalObjects; + } + public int getFlushedObjects() { + return flushedObjects; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 9607a1e3dd..2343539276 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -47,9 +47,16 @@ public void setTimeout(int timeout) { this.timeout = timeout; } public void setObject(RenderObject object) { - setObject(object, object.getObject()); + if (object != null) { + setObject(object, object.getObject()); + } else if (this.object != null) { + this.object.release(); + this.object = null; + resource = null; + } } public void setObject(RenderObject object, T resource) { + Objects.requireNonNull(object, "Object cannot be null."); Objects.requireNonNull(resource, "Object resource cannot be null."); if (undefined) { throw new IllegalStateException("Resource is already undefined."); @@ -59,10 +66,8 @@ public void setObject(RenderObject object, T resource) { } this.object = object; this.resource = resource; - if (this.object != null) { - this.object.acquire(); - ticket.setObjectId(this.object.getId()); - } + this.object.acquire(); + ticket.setObjectId(this.object.getId()); } public void setUndefined() { if (object != null) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index fd845bb926..34e1a1fecd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -24,6 +24,7 @@ public class ResourceList { private final RenderObjectMap map; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); private int nextSlot = 0; + private int textureBinds = 0; public ResourceList(RenderObjectMap map) { this.map = map; @@ -39,7 +40,10 @@ protected RenderResource locate(ResourceTicket ticket) { throw new NullPointerException("Ticket cannot be null."); } final int i = ticket.getWorldIndex(); - if (i >= 0 && i < resources.size()) { + if (i < 0) { + throw new NullPointerException(ticket+" does not point to any resource (negative index)."); + } + if (i < resources.size()) { RenderResource res = resources.get(i); if (res != null) { return res; @@ -206,6 +210,13 @@ public void setSurvivesReferenceCull(ResourceTicket ticket) { locate(ticket).setSurvivesRefCull(true); } + public boolean isVirtual(ResourceTicket ticket, boolean optional) { + if (!optional || validate(ticket)) { + return locate(ticket).isVirtual(); + } + return true; + } + protected T acquire(RenderResource resource, ResourceTicket ticket) { if (!resource.isUsed()) { throw new IllegalStateException(resource+" was unexpectedly acquired."); @@ -229,7 +240,7 @@ protected T acquire(RenderResource resource, ResourceTicket ticket) { public T acquire(ResourceTicket ticket) { RenderResource resource = locate(ticket); if (resource.isUndefined()) { - throw new NullPointerException("Resource is undefined."); + throw new NullPointerException("Cannot acquire undefined resource."); } return acquire(resource, ticket); } @@ -267,10 +278,12 @@ public void acquireColorTargets(FrameBuffer fbo, ResourceTicket)tickets[i]); if (acquired != existing) { fbo.setColorTarget(i, FrameBuffer.FrameBufferTarget.newTarget(acquired)); + textureBinds++; } } for (; i < tickets.length; i++) { fbo.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(acquire(tickets[i]))); + textureBinds++; } } /** @@ -279,15 +292,22 @@ public void acquireColorTargets(FrameBuffer fbo, ResourceTicket * @param fbo * @param ticket + * @return */ - public void acquireDepthTarget(FrameBuffer fbo, ResourceTicket ticket) { - Texture acquired = acquire((ResourceTicket)ticket); - if (fbo.getDepthTarget() != null && acquired == fbo.getDepthTarget().getTexture()) { - return; + public T acquireDepthTarget(FrameBuffer fbo, ResourceTicket ticket) { + T acquired = acquire(ticket); + FrameBuffer.RenderBuffer target = fbo.getDepthTarget(); + boolean nullTarget = target == null; + boolean unequalTargets = target != null && acquired != target.getTexture(); + System.out.println("null? "+nullTarget+" unequal? "+unequalTargets); + if (nullTarget || unequalTargets) { + fbo.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(acquired)); + textureBinds++; } - fbo.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(acquired)); + return acquired; } protected T extract(RenderResource resource, ResourceTicket ticket) { @@ -333,8 +353,7 @@ public void release(ResourceTicket ticket) { res.release(); if (!res.isUsed()) { remove(ticket.getWorldIndex()); - res.getObject().release(); - res.setObject(null, null); + res.setObject(null); if (res.getDefinition().isDisposeOnRelease()) { map.dispose(res); } @@ -358,6 +377,13 @@ public void releaseOptional(ResourceTicket... tickets) { } } + /** + * Prepares this for rendering. + */ + public void beginRenderingSession() { + textureBinds = 0; + } + /** * Culls all resources and resource producers found to be unused. *

      @@ -409,4 +435,8 @@ public void clear() { nextSlot = 0; } + public int getTextureBinds() { + return textureBinds; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java index c18b0c6257..02ab274c0b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java @@ -17,7 +17,6 @@ public abstract class AbstractResourceDef implements ResourceDef { private int staticTimeout = -1; private boolean useExisting = true; private boolean disposeOnRelease = false; - private boolean survivesReferenceCull = false; @Override public int getStaticTimeout() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 9a3cf74520..b268a0249b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -7,7 +7,9 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture; import com.jme3.texture.image.ColorSpace; +import java.util.ArrayList; import java.util.Objects; +import java.util.function.Consumer; import java.util.function.Function; /** @@ -15,7 +17,7 @@ * @author codex * @param */ -public class TextureDef extends AbstractResourceDef { +public class TextureDef extends AbstractResourceDef implements Consumer { private final Class type; private Function textureBuilder; @@ -26,8 +28,8 @@ public class TextureDef extends AbstractResourceDef { private int samples = 1; private Image.Format format; private ColorSpace colorSpace = ColorSpace.Linear; - private Texture.MagFilter magFilter = Texture.MagFilter.Nearest; - private Texture.MinFilter minFilter = Texture.MinFilter.NearestNearestMipMap; + private Texture.MagFilter magFilter; + private Texture.MinFilter minFilter; private Texture.ShadowCompareMode shadowCompare; private Texture.WrapMode wrapS, wrapT, wrapR; private boolean formatFlexible = false; @@ -47,7 +49,11 @@ public TextureDef(Class type, Function textureBuilder, Image.Format @Override public T createResource() { - return createTexture(new Image(format, width, height, depth, null, colorSpace)); + if (depth > 0) { + return createTexture(new Image(format, width, height, depth, new ArrayList<>(depth), colorSpace)); + } else { + return createTexture(new Image(format, width, height, null, colorSpace)); + } } @Override public T applyDirectResource(Object resource) { @@ -79,6 +85,15 @@ public T applyIndirectResource(Object resource) { } return null; } + @Override + public Consumer getDisposalMethod() { + return this; + } + @Override + public void accept(T t) { + System.out.println("dispose texture"); + t.getImage().dispose(); + } private T createTexture(Image img) { T tex = textureBuilder.apply(img); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GraphSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java similarity index 89% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GraphSource.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java index 9d4e90f243..da5b12158f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GraphSource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java @@ -2,7 +2,7 @@ * 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.passes; +package com.jme3.renderer.framegraph.io; import com.jme3.renderer.ViewPort; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphTarget.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java similarity index 91% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphTarget.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java index c33eda559b..11b58ccb45 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphTarget.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java @@ -2,7 +2,7 @@ * 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; +package com.jme3.renderer.framegraph.io; import com.jme3.renderer.ViewPort; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java new file mode 100644 index 0000000000..ac2be434bf --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java @@ -0,0 +1,67 @@ +/* + * 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.io; + +import com.jme3.material.Material; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.SceneGraphIterator; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; +import com.jme3.shader.VarType; + +/** + * + * @author codex + * @param + */ +public class MatParamTargetControl extends AbstractControl implements GraphTarget { + + private final String name; + private final VarType type; + private Material material; + private T value; + + public MatParamTargetControl(String name, VarType type) { + this.name = name; + this.type = type; + } + + @Override + protected void controlUpdate(float tpf) { + if (value != null) { + material.setParam(name, type, value); + } + } + @Override + protected void controlRender(RenderManager rm, ViewPort vp) {} + @Override + public void setSpatial(Spatial spat) { + if (spatial == spat) { + return; + } + super.setSpatial(spat); + if (spatial != null) { + for (Spatial s : new SceneGraphIterator(spatial)) { + if (s instanceof Geometry) { + material = ((Geometry)s).getMaterial(); + break; + } + } + } else { + material = null; + } + } + @Override + public void setGraphValue(ViewPort viewPort, T value) { + this.value = value; + } + + public T getValue() { + return value; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/AttributePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java similarity index 79% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/AttributePass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index 72f42b6fac..1fab030901 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/AttributePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -4,32 +4,26 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.renderer.framegraph.io.GraphTarget; +import com.jme3.renderer.framegraph.io.GraphSource; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.ValueDef; import java.util.function.Function; -import com.jme3.renderer.framegraph.GraphTarget; /** * * @author codex * @param */ -public class AttributePass extends RenderPass implements Function { +public class Attribute extends RenderPass implements Function { - private final Class paramType; - private String paramName; private ResourceTicket in, out; private T value; private ValueDef def; private GraphTarget target; private GraphSource source; - - public AttributePass(Class paramType, String paramName) { - this.paramType = paramType; - this.paramName = paramName; - } @Override protected void initialize(FrameGraph frameGraph) { @@ -74,9 +68,6 @@ public T apply(Object t) { return value; } - public void setParamName(String name) { - this.paramName = name; - } public void setTarget(GraphTarget target) { this.target = target; } @@ -84,11 +75,4 @@ public void setSource(GraphSource source) { this.source = source; } - public Class getParamType() { - return paramType; - } - public String getParamName() { - return paramName; - } - } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index d72529861f..6ee07471f3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -8,6 +8,7 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; +import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; @@ -32,6 +33,7 @@ public class BucketPass extends RenderPass { private boolean flush = true; private ResourceTicket inColor, inDepth, outColor, outDepth; private TextureDef colorDef, depthDef; + private Texture2D depthTex; public BucketPass() { this(Bucket.Opaque, DepthRange.IDENTITY); @@ -73,7 +75,8 @@ protected void prepare(FGRenderContext context) { protected void execute(FGRenderContext context) { FrameBuffer fb = getFrameBuffer(context, 1); resources.acquireColorTargets(fb, outColor); - resources.acquireDepthTarget(fb, inDepth); + depthTex = resources.acquireDepthTarget(fb, outDepth); + System.out.println(fb.getDepthTarget()); context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); @@ -92,7 +95,12 @@ protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} @Override + public String getProfilerName() { + return super.getProfilerName()+"["+bucket+"]"; + } + @Override public void write(JmeExporter ex) throws IOException { + super.write(ex); OutputCapsule out = ex.getCapsule(this); out.write(bucket, "bucket", Bucket.Opaque); out.write(depth, "depth", DepthRange.IDENTITY); @@ -101,6 +109,7 @@ public void write(JmeExporter ex) throws IOException { } @Override public void read(JmeImporter im) throws IOException { + super.read(im); InputCapsule in = im.getCapsule(this); bucket = in.readEnum("bucket", Bucket.class, Bucket.Opaque); depth.set(in.readSavable("depth", DepthRange.class, DepthRange.IDENTITY)); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 071644adca..da45720795 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -33,6 +33,7 @@ protected void initialize(FrameGraph frameGraph) { specular = addInput("Specular"); emissive = addInput("Emissive"); normal = addInput("Normal"); + lights = addInput("Lights"); outColor = addOutput("Color"); colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); colorDef.setFormatFlexible(true); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 2f9ddbd3bf..19770f74be 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -34,7 +34,7 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private ResourceTicket diffuse, specular, emissive, normal, depth; private ResourceTicket lights; private TextureDef[] texDefs = new TextureDef[5]; - private ValueDef lightDef ; + private ValueDef lightDef; private final LinkedList accumulatedLights = new LinkedList<>(); private final ColorRGBA mask = new ColorRGBA(); @@ -43,8 +43,9 @@ protected void initialize(FrameGraph frameGraph) { diffuse = addOutput("Diffuse"); specular = addOutput("Specular"); emissive = addOutput("Emissive"); - normal = addOutput("normal"); + normal = addOutput("Normal"); depth = addOutput("Depth"); + lights = addOutput("Lights"); Function tex = img -> new Texture2D(img); texDefs[0] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); texDefs[1] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); @@ -70,39 +71,33 @@ protected void prepare(FGRenderContext context) { declare(texDefs[3], normal); declare(texDefs[4], depth); declare(lightDef, lights); - reserve(diffuse, specular, emissive, normal, depth); + reserve(diffuse, specular, emissive, normal, depth, lights); } @Override protected void execute(FGRenderContext context) { // acquire texture targets - resources.acquireColorTargets(frameBuffer, diffuse, specular, emissive, normal); - resources.acquireDepthTarget(frameBuffer, depth); - context.getRenderer().setFrameBuffer(frameBuffer); + FrameBuffer fb = getFrameBuffer(context, 1); + fb.setMultiTarget(true); + resources.acquireColorTargets(fb, diffuse, specular, emissive, normal); + resources.acquireDepthTarget(fb, depth); + context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); LightList lightList = resources.acquire(lights); // render to gBuffer context.getRenderer().setBackgroundColor(mask.set(context.getViewPort().getBackgroundColor()).setAlpha(0)); context.getRenderManager().setForcedTechnique(GBUFFER_PASS); context.getRenderManager().setGeometryRenderHandler(this); - context.getRenderer().setDepthRange(0, 1); context.renderViewPortQueue(RenderQueue.Bucket.Opaque, true); // add accumulated lights while (!accumulatedLights.isEmpty()) { lightList.add(accumulatedLights.pollFirst()); } - frameBuffer.clearColorTargets(); } @Override protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} @Override - protected FrameBuffer createFrameBuffer(FGRenderContext context) { - FrameBuffer buffer = new FrameBuffer(context.getWidth(), context.getHeight(), 1); - buffer.setMultiTarget(true); - return buffer; - } - @Override public boolean renderGeometry(RenderManager rm, Geometry geom) { Material material = geom.getMaterial(); if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null) { @@ -110,37 +105,16 @@ public boolean renderGeometry(RenderManager rm, Geometry geom) { } rm.renderGeometry(geom); if (material.getActiveTechnique() != null) { - if (material.getMaterialDef().getTechniqueDefs(GBUFFER_PASS) != null) { - LightList lts = geom.getFilterWorldLights(); - for (Light l : lts) { - // todo: checking for containment is very slow - if (!accumulatedLights.contains(l)) { - accumulatedLights.add(l); - } + LightList lts = geom.getFilterWorldLights(); + for (Light l : lts) { + // todo: checking for containment is very slow + if (!accumulatedLights.contains(l)) { + accumulatedLights.add(l); } - return true; } + return true; } return false; } - - public ResourceTicket getDepth() { - return depth; - } - public ResourceTicket getDiffuse() { - return diffuse; - } - public ResourceTicket getSpecular() { - return specular; - } - public ResourceTicket getEmissive() { - return emissive; - } - public ResourceTicket getNormal() { - return normal; - } - public ResourceTicket getLights() { - return lights; - } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/JunctionPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java similarity index 63% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/JunctionPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 97b6d2b5ea..6166342f6f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/JunctionPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -4,25 +4,32 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.framegraph.io.GraphSource; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; +import java.io.IOException; /** * * @author codex * @param */ -public class JunctionPass extends RenderPass { +public class Junction extends RenderPass { private int length; private ResourceTicket output; private GraphSource source; - public JunctionPass() { + public Junction() { this(2); } - public JunctionPass(int length) { + public Junction(int length) { this.length = length; } @@ -47,6 +54,18 @@ protected void cleanup(FrameGraph frameGraph) {} public boolean isUsed() { return true; } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + out.write(length, "length", 2); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + length = in.readInt("length", 2); + } public void setLength(int length) { this.length = length; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java index c60222a4cb..8b075c07cb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java @@ -4,10 +4,15 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.queue.RenderQueue.Bucket; +import java.io.IOException; /** * @@ -24,6 +29,9 @@ public OutputBucketPass(Bucket bucket) { public OutputBucketPass(Bucket bucket, DepthRange depth) { this.bucket = bucket; this.depth = depth; + if (this.bucket == Bucket.Inherit) { + throw new IllegalArgumentException("Rendered bucket cannot be Inherit."); + } } @@ -51,5 +59,21 @@ protected void cleanup(FrameGraph frameGraph) {} public boolean isUsed() { return true; } + @Override + public String getProfilerName() { + return super.getProfilerName()+"["+bucket+"]"; + } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + out.write(depth, "depth", DepthRange.IDENTITY); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + depth = in.readSavable("depth", DepthRange.class, DepthRange.IDENTITY); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java index 962c4abea2..efaffb573d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java @@ -7,8 +7,8 @@ import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; -import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture2D; +import java.util.Objects; /** * @@ -16,43 +16,31 @@ */ public class OutputPass extends RenderPass { - private ResourceTicket inColor, inDepth; - private Texture2D fTex; + private ResourceTicket color, depth; @Override protected void initialize(FrameGraph frameGraph) { - inColor = addInput("Color"); - inDepth = addInput("Depth"); - fTex = (Texture2D)frameGraph.getAssetManager().loadTexture("Common/Textures/MissingTexture.png"); + color = addInput("Color"); + depth = addInput("Depth"); } @Override protected void prepare(FGRenderContext context) { - referenceOptional(inColor, inDepth); + referenceOptional(color, depth); } @Override protected void execute(FGRenderContext context) { context.popFrameBuffer(); - context.transferTextures(resources.acquireOrElse(inColor, null), resources.acquireOrElse(inDepth, null)); + Texture2D colorTex = resources.acquireOrElse(color, null); + Texture2D depthTex = resources.acquireOrElse(depth, null); + context.transferTextures(colorTex, depthTex); } @Override protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} @Override - protected FrameBuffer createFrameBuffer(FGRenderContext context) { - return new FrameBuffer(context.getWidth(), context.getHeight(), 1); - } - @Override public boolean isUsed() { return true; } - - public void setInColor(ResourceTicket inColor) { - this.inColor = inColor; - } - public void setInDepth(ResourceTicket inDepth) { - this.inDepth = inDepth; - } - } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java index 941ba9a6e2..7dcb7dfc24 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java @@ -8,6 +8,7 @@ import com.jme3.profile.AppProfiler; import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; +import com.jme3.renderer.RenderContext; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.util.SafeArrayList; @@ -50,5 +51,35 @@ protected void cleanup(FrameGraph frameGraph) {} public boolean isUsed() { return true; } + @Override + public void preFrame(FGRenderContext context) { + SafeArrayList processors = context.getViewPort().getProcessors(); + if (!processors.isEmpty()) { + AppProfiler prof = context.getProfiler(); + for (SceneProcessor p : processors.getArray()) { + if (!p.isInitialized()) { + p.initialize(context.getRenderManager(), context.getViewPort()); + } + p.setProfiler(prof); + if (prof != null) { + prof.spStep(SpStep.ProcPreFrame, p.getClass().getSimpleName()); + } + p.preFrame(context.getTpf()); + } + } + } + @Override + public void postQueue(FGRenderContext context) { + SafeArrayList processors = context.getViewPort().getProcessors(); + if (!processors.isEmpty()) { + AppProfiler prof = context.getProfiler(); + for (SceneProcessor p : processors.getArray()) { + if (prof != null) { + prof.spStep(SpStep.ProcPostQueue, p.getClass().getSimpleName()); + } + p.postQueue(context.getViewPort().getQueue()); + } + } + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index a3ed6768e7..a3ba1ca299 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -9,7 +9,6 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; -import com.jme3.renderer.framegraph.CameraSize; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceList; @@ -18,7 +17,6 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import java.io.IOException; -import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.Objects; @@ -32,7 +30,7 @@ public abstract class RenderPass implements ResourceProducer, Savable { private static int nextId = 0; private int id = nextId++; - private String name = ""; + private String name; private int index = -1; private int refs = 0; private final LinkedList inputs = new LinkedList<>(); @@ -43,6 +41,9 @@ public abstract class RenderPass implements ResourceProducer, Savable { public void initializePass(FrameGraph frameGraph, int index) { this.index = index; this.resources = frameGraph.getResources(); + if (name == null) { + name = getClass().getSimpleName(); + } initialize(frameGraph); } public void prepareRender(FGRenderContext context) { @@ -58,17 +59,6 @@ public void executeRender(FGRenderContext context) { public void resetRender(FGRenderContext context) { reset(context); } - public void postFrame(FrameGraph frameGraph) { - for (Iterator it = frameBuffers.iterator(); it.hasNext();) { - PassFrameBuffer fb = it.next(); - if (!fb.used) { - fb.dispose(); - it.remove(); - } else { - fb.used = false; - } - } - } public void cleanupPass(FrameGraph frameGraph) { cleanup(frameGraph); for (ResourceTicket t : inputs) { @@ -85,6 +75,30 @@ public void cleanupPass(FrameGraph frameGraph) { protected abstract void reset(FGRenderContext context); protected abstract void cleanup(FrameGraph frameGraph); + public void renderingComplete() { + for (Iterator it = frameBuffers.iterator(); it.hasNext();) { + PassFrameBuffer fb = it.next(); + if (!fb.used) { + fb.dispose(); + it.remove(); + } else { + fb.used = false; + } + } + } + public void preFrame(FGRenderContext context) {} + public void postQueue(FGRenderContext context) {} + + public void setPassProperty(String name, String value) throws Exception { + if (!setProperty(name, value)) switch (name) { + case "id": id = Integer.parseInt(value); break; + case "name": this.name = value; break; + } + } + protected boolean setProperty(String name, String value) throws Exception { + return false; + } + protected ResourceTicket declare(ResourceDef def, ResourceTicket ticket) { return resources.declare(this, def, ticket); } @@ -101,18 +115,12 @@ protected void reserve(ResourceTicket... tickets) { } protected void reference(ResourceTicket ticket) { resources.reference(index, ticket); - //addInput(ticket); } protected void reference(ResourceTicket... tickets) { resources.reference(index, tickets); - //addInputs(tickets); } protected boolean referenceOptional(ResourceTicket ticket) { - if (resources.referenceOptional(index, ticket)) { - //addInput(ticket); - return true; - } - return false; + return resources.referenceOptional(index, ticket); } protected void referenceOptional(ResourceTicket... tickets) { for (ResourceTicket t : tickets) { @@ -158,6 +166,18 @@ protected ResourceTicket getOutputByName(String name) { } return null; } + public void makeInput(RenderPass pass, String outTicket, String inTicket) { + ResourceTicket out = Objects.requireNonNull(pass.getOutputByName(outTicket)); + ResourceTicket in = Objects.requireNonNull(getInputByName(inTicket)); + in.setSource(out); + } + public void disconnectFrom(RenderPass pass) { + for (ResourceTicket in : inputs) { + if (pass.getOutputTickets().contains(in.getSource())) { + in.setSource(null); + } + } + } protected FrameBuffer getFrameBuffer(int width, int height, int samples) { for (PassFrameBuffer fb : frameBuffers) { @@ -173,19 +193,6 @@ protected FrameBuffer getFrameBuffer(FGRenderContext context, int samples) { return getFrameBuffer(context.getWidth(), context.getHeight(), samples); } - public void makeInput(RenderPass pass, String outTicket, String inTicket) { - ResourceTicket out = Objects.requireNonNull(pass.getOutputByName(outTicket)); - ResourceTicket in = Objects.requireNonNull(getInputByName(inTicket)); - in.setSource(out); - } - public void disconnectFrom(RenderPass pass) { - for (ResourceTicket in : inputs) { - if (pass.getOutputTickets().contains(in.getSource())) { - in.setSource(null); - } - } - } - public void countReferences() { refs = outputs.size(); } @@ -194,7 +201,6 @@ public void shiftExecutionIndex(int threshold, boolean positive) { index += (positive ? 1 : -1); } } - public void setName(String name) { this.name = name; } @@ -205,6 +211,9 @@ public void setId(int id) { public String getName() { return name; } + public String getProfilerName() { + return getName(); + } public int getId() { return id; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index d170fc4157..dc1e750a5a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java @@ -56,8 +56,9 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { - resources.acquireColorTargets(frameBuffer, outColor); - context.getRenderer().setFrameBuffer(frameBuffer); + FrameBuffer fb = getFrameBuffer(context, 1); + resources.acquireColorTargets(fb, outColor); + context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); TiledRenderGrid trg = resources.acquireOrElse(tiles, null); if (trg != null) { @@ -81,10 +82,6 @@ protected void execute(FGRenderContext context) { protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} - @Override - protected FrameBuffer createFrameBuffer(FGRenderContext context) { - return new FrameBuffer(context.getWidth(), context.getHeight(), 1); - } public void setDiffuse(ResourceTicket diffuse) { this.diffuse = diffuse; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Value.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Value.java new file mode 100644 index 0000000000..2aa2855592 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Value.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.passes; + +/** + * + * @author codex + */ +public class Value { + +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md index d01aa1ca40..528bafad9c 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md @@ -8,8 +8,6 @@ MaterialDef TextureTransfer { } Technique { - - Pipeline Deferred VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/Screen.vert FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/TextureTransfer.frag diff --git a/jme3-core/src/plugins/java/com/jme3/render/plugins/J3GLoader.java b/jme3-core/src/plugins/java/com/jme3/render/plugins/J3GLoader.java deleted file mode 100644 index 804b49be0d..0000000000 --- a/jme3-core/src/plugins/java/com/jme3/render/plugins/J3GLoader.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.render.plugins; - -import com.jme3.asset.AssetInfo; -import com.jme3.asset.AssetLoader; -import com.jme3.asset.AssetManager; -import com.jme3.export.InputCapsule; -import com.jme3.export.JmeImporter; -import com.jme3.export.Savable; -import java.io.IOException; - -/** - * - * @author codex - */ -public class J3GLoader implements AssetLoader, JmeImporter { - - public static final int CURRENT_VERSION = 0; - - private AssetManager assetManager; - - @Override - public Object load(AssetInfo assetInfo) throws IOException { - - } - @Override - public InputCapsule getCapsule(Savable id) {} - @Override - public AssetManager getAssetManager() { - return assetManager; - } - @Override - public int getFormatVersion() {} - -} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index 7ed16d2e8f..c34f705c4a 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -1,7 +1,7 @@ package jme3test.renderpath; +import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; -import com.jme3.asset.AssetManager; import com.jme3.environment.EnvironmentProbeControl; import com.jme3.light.AmbientLight; import com.jme3.light.DirectionalLight; @@ -9,18 +9,20 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; -import com.jme3.post.Filter; import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.DeferredGraphConstructor; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.RenderObjectMap; +import com.jme3.renderer.framegraph.io.MatParamTargetControl; +import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; +import com.jme3.shader.VarType; import com.jme3.shadow.DirectionalLightShadowRenderer; import com.jme3.system.AppSettings; import com.jme3.texture.plugins.ktx.KTXLoader; @@ -36,7 +38,8 @@ public class TestShadingModel extends SimpleApplication { private DirectionalLight dl; private float roughness = 0.0f; - + + private FrameGraph graph; private Node modelNode; private int frame = 0; private Material pbrMat; @@ -46,17 +49,30 @@ public class TestShadingModel extends SimpleApplication { public static void main(String[] args) { TestShadingModel app = new TestShadingModel(); AppSettings settings = new AppSettings(true); + settings.setWidth(768); + settings.setHeight(768); //settings.setGraphicsDebug(true); //settings.setGraphicsTrace(true); app.setSettings(settings); app.start(); } + + @Override + public void simpleUpdate(float tpf) { + //cam.lookAt(new Vector3f(), Vector3f.UNIT_Y); + RenderObjectMap objects = renderManager.getRenderObjectMap(); + } @Override public void simpleInitApp() { + stateManager.attach(new DetailedProfilerState()); + //flyCam.setEnabled(false); + flyCam.setDragToRotate(true); + inputManager.setCursorVisible(true); + //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - FrameGraph graph = new FrameGraph(assetManager, renderManager); + graph = new FrameGraph(assetManager, renderManager); graph.setConstructor(new DeferredGraphConstructor()); //graph.setConstructor(new ForwardGraphConstructor()); //graph.setConstructor(new TestConstructor()); @@ -68,16 +84,22 @@ public void simpleInitApp() { viewPort.setBackgroundColor(ColorRGBA.Green.mult(0.2f)); //viewPort.setBackgroundColor(ColorRGBA.White); +// FrameBuffer fb = new FrameBuffer(768, 768, 1); +// Texture2D depth = new Texture2D(768, 768, Image.Format.Depth); +// fb.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(depth)); +// viewPort.setOutputFrameBuffer(fb); + Geometry debugView = new Geometry("debug", new Quad(150, 150)); debugView.setLocalTranslation(0, 200, 0); Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); //debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); //debugMat.setTransparent(true); debugView.setMaterial(debugMat); - //MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); - //texParam.enableDebug(); - //graph.bindToOutput(DeferredShadingModule.DEPTH_DEBUG, texParam); - //guiNode.attachChild(debugView); + //debugMat.setTexture("ColorMap", depth); +// MatParamTargetControl texParam = new MatParamTargetControl("ColorMap", VarType.Texture2D); +// graph.get(Attribute.class, "OpaqueColor").setTarget(texParam); +// debugView.addControl(texParam); +// guiNode.attachChild(debugView); // UNLIT Material unlitMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); @@ -92,7 +114,7 @@ public void simpleInitApp() { unlitSphere.setLocalTranslation(-5, 0, 0); unlitSphere.setLocalRotation(new Quaternion(new float[]{(float) Math.toRadians(-90), 0, 0})); unlitSphere.setMaterial(unlitMat); - unlitSphere.setQueueBucket(RenderQueue.Bucket.Opaque); + unlitSphere.setQueueBucket(RenderQueue.Bucket.Transparent); rootNode.attachChild(unlitSphere); // LEGACY_LIGHTING @@ -151,11 +173,6 @@ public void simpleInitApp() { //new RenderPathHelper(this); flyCam.setMoveSpeed(10.0f); } - - @Override - public void simpleUpdate(float tpf) { - cam.lookAt(new Vector3f(), Vector3f.UNIT_Y); - } @Override public void simpleRender(RenderManager rm) { From 02d69d4659f05f87ad3fcf1ae7ef0562f639b122 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 20 May 2024 18:28:06 -0400 Subject: [PATCH 063/111] added export and import methods --- .../framegraph/DeferredGraphConstructor.java | 71 ---------- .../framegraph/ForwardGraphConstructor.java | 54 ------- .../jme3/renderer/framegraph/FrameGraph.java | 133 +++++++++++++++--- .../framegraph/FrameGraphFactory.java | 65 +++++++++ .../renderer/framegraph/GraphConstructor.java | 17 --- .../renderer/framegraph/passes/Junction.java | 1 - .../jme3test/renderpath/TestShadingModel.java | 8 +- 7 files changed, 180 insertions(+), 169 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphConstructor.java diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java deleted file mode 100644 index 2667a02db4..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredGraphConstructor.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.framegraph.passes.Attribute; -import com.jme3.renderer.framegraph.passes.DeferredPass; -import com.jme3.renderer.framegraph.passes.GBufferPass; -import com.jme3.renderer.framegraph.passes.OutputBucketPass; -import com.jme3.renderer.framegraph.passes.OutputPass; -import com.jme3.renderer.framegraph.passes.PostProcessingPass; -import com.jme3.renderer.queue.RenderQueue.Bucket; -import com.jme3.texture.Texture2D; - -/** - * - * @author codex - */ -public class DeferredGraphConstructor implements GraphConstructor { - - private GBufferPass gbuf; - private DeferredPass deferred; - private OutputPass defOut; - private Attribute depthAttr; - private OutputBucketPass sky, transparent, gui, translucent; - private PostProcessingPass post; - - @Override - public void addPasses(FrameGraph frameGraph) { - - gbuf = frameGraph.add(new GBufferPass()); - deferred = frameGraph.add(new DeferredPass()); - defOut = frameGraph.add(new OutputPass()); - depthAttr = frameGraph.add(new Attribute<>()); - sky = frameGraph.add(new OutputBucketPass(Bucket.Sky, DepthRange.REAR)); - transparent = frameGraph.add(new OutputBucketPass(Bucket.Transparent)); - gui = frameGraph.add(new OutputBucketPass(Bucket.Gui, DepthRange.FRONT)); - post = frameGraph.add(new PostProcessingPass()); - translucent = frameGraph.add(new OutputBucketPass(Bucket.Translucent)); - - deferred.makeInput(gbuf, "Diffuse", "Diffuse"); - deferred.makeInput(gbuf, "Specular", "Specular"); - deferred.makeInput(gbuf, "Emissive", "Emissive"); - deferred.makeInput(gbuf, "Normal", "Normal"); - deferred.makeInput(gbuf, "Depth", "Depth"); - deferred.makeInput(gbuf, "Lights", "Lights"); - - defOut.makeInput(deferred, "Color", "Color"); - defOut.makeInput(gbuf, "Depth", "Depth"); - - depthAttr.makeInput(gbuf, "Depth", "Value"); - depthAttr.setName("DepthDebug"); - - } - @Override - public void preparePasses(FGRenderContext context) { - - gbuf.prepareRender(context); - deferred.prepareRender(context); - defOut.prepareRender(context); - - sky.prepareRender(context); - transparent.prepareRender(context); - gui.prepareRender(context); - post.prepareRender(context); - translucent.prepareRender(context); - - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java deleted file mode 100644 index 546a78badb..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ForwardGraphConstructor.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.framegraph.passes.Attribute; -import com.jme3.renderer.framegraph.passes.BucketPass; -import com.jme3.renderer.framegraph.passes.OutputBucketPass; -import com.jme3.renderer.framegraph.passes.OutputPass; -import com.jme3.renderer.queue.RenderQueue.Bucket; -import com.jme3.texture.Texture2D; - -/** - * - * @author codex - */ -public class ForwardGraphConstructor implements GraphConstructor { - - private BucketPass opaque; - private OutputPass opaqueOut; - private Attribute opaqueAttr; - private OutputBucketPass sky, transparent, gui, translucent; - - @Override - public void addPasses(FrameGraph frameGraph) { - - opaque = frameGraph.add(new BucketPass(Bucket.Opaque)); - opaqueOut = frameGraph.add(new OutputPass()); - sky = frameGraph.add(new OutputBucketPass(Bucket.Sky, DepthRange.REAR)); - transparent = frameGraph.add(new OutputBucketPass(Bucket.Transparent)); - gui = frameGraph.add(new OutputBucketPass(Bucket.Gui, DepthRange.FRONT)); - translucent = frameGraph.add(new OutputBucketPass(Bucket.Translucent)); - opaqueAttr = frameGraph.add(new Attribute<>()); - - opaqueOut.makeInput(opaque, "Color", "Color"); - opaqueOut.makeInput(opaque, "Depth", "Depth"); - - opaqueAttr.makeInput(opaque, "Color", "Value"); - opaqueAttr.setName("OpaqueColor"); - - } - @Override - public void preparePasses(FGRenderContext context) { - - opaque.prepareRender(context); - sky.prepareRender(context); - transparent.prepareRender(context); - gui.prepareRender(context); - translucent.prepareRender(context); - - } - -} 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 5e8f93af44..61ea4bf346 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,8 +32,6 @@ public class FrameGraph implements Savable { private final ResourceList resources; private final FGRenderContext context; private final LinkedList passes = new LinkedList<>(); - private GraphConstructor constructor; - private boolean debug = false; private boolean rendered = false; public FrameGraph(AssetManager assetManager, RenderManager renderManager) { @@ -42,19 +40,45 @@ public FrameGraph(AssetManager assetManager, RenderManager renderManager) { this.context = new FGRenderContext(this, renderManager); } + /** + * Configures the framegraph rendering context. + * + * @param vp viewport to render (not null) + * @param prof profiler (may be null) + * @param tpf time per frame + */ public void configure(ViewPort vp, AppProfiler prof, float tpf) { context.target(vp, prof, tpf); } + /** + * Pre-frame operations. + */ public void preFrame() { for (RenderPass p : passes) { p.preFrame(context); } } + /** + * Post-queue operations. + */ public void postQueue() { for (RenderPass p : passes) { p.postQueue(context); } } + /** + * Executes this framegraph. + *

      + * The overall execution step occurs in 4 stages: + *

        + *
      1. Preparation.
      2. + *
      3. Culling.
      4. + *
      5. Rendering (execution).
      6. + *
      7. Clean (reset).
      8. + *
      + * + * @return true if this is the first execution this frame + */ public boolean execute() { // prepare ViewPort vp = context.getViewPort(); @@ -69,7 +93,7 @@ public boolean execute() { } p.prepareRender(context); } - // cull resources + // cull passes and resources if (prof != null) prof.vpStep(VpStep.FrameGraphCull, vp, null); for (RenderPass p : passes) { p.countReferences(); @@ -101,6 +125,9 @@ public boolean execute() { if (rendered) return false; else return (rendered = true); } + /** + * Should be called only when all rendering for the frame is complete. + */ public void renderingComplete() { // notify passes for (RenderPass p : passes) { @@ -110,11 +137,30 @@ public void renderingComplete() { rendered = false; } + /** + * Adds the pass to end of the pass queue. + * + * @param + * @param pass + * @return given pass + */ public T add(T pass) { passes.addLast(pass); pass.initializePass(this, passes.size()-1); return pass; } + /** + * Adds the pass at the index in the pass queue. + *

      + * If the index is >= the current queue size, the pass will + * be added to the end of the queue. Passes above the added pass + * will have their indexes shifted. + * + * @param + * @param pass + * @param index + * @return + */ public T add(T pass, int index) { if (index < 0) { throw new IndexOutOfBoundsException("Index cannot be negative."); @@ -129,6 +175,13 @@ public T add(T pass, int index) { } return pass; } + /** + * Gets the first pass that is of or a subclass of the given class. + * + * @param + * @param type + * @return first qualifying pass, or null + */ public T get(Class type) { for (RenderPass p : passes) { if (type.isAssignableFrom(p.getClass())) { @@ -137,6 +190,14 @@ public T get(Class type) { } return null; } + /** + * Gets the first pass of the given class that is named as given. + * + * @param + * @param type + * @param name + * @return first qualifying pass, or null + */ public T get(Class type, String name) { for (RenderPass p : passes) { if (name.equals(p.getName()) && type.isAssignableFrom(p.getClass())) { @@ -145,6 +206,14 @@ public T get(Class type, String name) { } return null; } + /** + * Gets the pass that holds the given id number. + * + * @param + * @param type + * @param id + * @return pass of the id, or null + */ public T get(Class type, int id) { for (RenderPass p : passes) { if (id == p.getId() && type.isAssignableFrom(p.getClass())) { @@ -153,7 +222,19 @@ public T get(Class type, int id) { } return null; } + /** + * Removes the pass at the index in the queue. + *

      + * Passes above the removed pass will have their indexes shifted. + * + * @param i + * @return removed pass + * @throws IndexOutOfBoundsException if the index is less than zero or >= the queue size + */ public RenderPass remove(int i) { + if (i < 0 || i >= passes.size()) { + throw new IndexOutOfBoundsException("Index "+i+" is out of bounds for size "+passes.size()); + } int j = 0; RenderPass removed = null; for (Iterator it = passes.iterator(); it.hasNext();) { @@ -171,6 +252,14 @@ public RenderPass remove(int i) { } return removed; } + /** + * Removes the given pass from the queue. + *

      + * Passes above the removed pass will have their indexes shifted. + * + * @param pass + * @return true if the pass was removed from the queue + */ public boolean remove(RenderPass pass) { int i = 0; boolean found = false; @@ -194,6 +283,9 @@ public boolean remove(RenderPass pass) { } return false; } + /** + * Clears all passes from the pass queue. + */ public void clear() { for (RenderPass p : passes) { p.cleanupPass(this); @@ -201,35 +293,36 @@ public void clear() { passes.clear(); } - public void setConstructor(GraphConstructor constructor) { - if (this.constructor != null || constructor == null) { - throw new IllegalStateException(); - } - this.constructor = constructor; - this.constructor.addPasses(this); - } - public void setDebug(boolean debug) { - this.debug = debug; - } - + /** + * + * @return + */ public AssetManager getAssetManager() { return assetManager; } + /** + * Gets the ResourceList that manages resources for this framegraph. + * + * @return + */ public ResourceList getResources() { return resources; } - public RenderObjectMap getRecycler() { - return context.getRenderManager().getRenderObjectMap(); - } + /** + * Gets the framegraph rendering context. + * + * @return + */ public FGRenderContext getContext() { return context; } + /** + * + * @return + */ public RenderManager getRenderManager() { return context.getRenderManager(); } - public boolean isDebug() { - return debug; - } @Override public void write(JmeExporter ex) throws IOException { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java new file mode 100644 index 0000000000..080b946ca2 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -0,0 +1,65 @@ +/* + * 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.asset.AssetManager; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.passes.DeferredPass; +import com.jme3.renderer.framegraph.passes.GBufferPass; +import com.jme3.renderer.framegraph.passes.OutputBucketPass; +import com.jme3.renderer.framegraph.passes.OutputPass; +import com.jme3.renderer.framegraph.passes.PostProcessingPass; +import com.jme3.renderer.framegraph.passes.RenderPass; +import com.jme3.renderer.framegraph.passes.TileDeferredPass; +import com.jme3.renderer.queue.RenderQueue; + +/** + * + * @author codex + */ +public class FrameGraphFactory { + + public static FrameGraph forward(AssetManager assetManager, RenderManager renderManager) { + FrameGraph fg = new FrameGraph(assetManager, renderManager); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Opaque)); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); + fg.add(new PostProcessingPass()); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); + return fg; + } + + public static FrameGraph deferred(AssetManager assetManager, RenderManager renderManager, boolean tiled) { + FrameGraph fg = new FrameGraph(assetManager, renderManager); + GBufferPass gbuf = fg.add(new GBufferPass()); + RenderPass deferred; + if (!tiled) { + deferred = fg.add(new DeferredPass()); + } else { + deferred = fg.add(new TileDeferredPass()); + } + OutputPass defOut = fg.add(new OutputPass()); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); + fg.add(new PostProcessingPass()); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); + + deferred.makeInput(gbuf, "Diffuse", "Diffuse"); + deferred.makeInput(gbuf, "Specular", "Specular"); + deferred.makeInput(gbuf, "Emissive", "Emissive"); + deferred.makeInput(gbuf, "Normal", "Normal"); + deferred.makeInput(gbuf, "Depth", "Depth"); + deferred.makeInput(gbuf, "Lights", "Lights"); + + defOut.makeInput(deferred, "Color", "Color"); + defOut.makeInput(gbuf, "Depth", "Depth"); + + return fg; + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphConstructor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphConstructor.java deleted file mode 100644 index 850ef4d632..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphConstructor.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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 interface GraphConstructor { - - public void addPasses(FrameGraph frameGraph); - - public void preparePasses(FGRenderContext context); - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 6166342f6f..1cbc1d6757 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -8,7 +8,6 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.io.GraphSource; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index c34f705c4a..9f51adc84e 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -11,18 +11,15 @@ import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.DeferredGraphConstructor; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.renderer.framegraph.RenderObjectMap; -import com.jme3.renderer.framegraph.io.MatParamTargetControl; -import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; -import com.jme3.shader.VarType; import com.jme3.shadow.DirectionalLightShadowRenderer; import com.jme3.system.AppSettings; import com.jme3.texture.plugins.ktx.KTXLoader; @@ -72,8 +69,7 @@ public void simpleInitApp() { inputManager.setCursorVisible(true); //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - graph = new FrameGraph(assetManager, renderManager); - graph.setConstructor(new DeferredGraphConstructor()); + graph = FrameGraphFactory.deferred(assetManager, renderManager, true); //graph.setConstructor(new ForwardGraphConstructor()); //graph.setConstructor(new TestConstructor()); //MyFrameGraph graph = RenderPipelineFactory.createBackroundScreenTest(assetManager, renderManager); From 9966f852abcd03dbd5d2fc04e7ab92717ad2e714 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 20 May 2024 21:22:15 -0400 Subject: [PATCH 064/111] javadoc for new classes --- .../jme3/renderer/framegraph/CameraSize.java | 45 ----- .../jme3/renderer/framegraph/DepthRange.java | 60 +++++- .../renderer/framegraph/FGRenderContext.java | 94 +++++++++- .../jme3/renderer/framegraph/FrameGraph.java | 40 +++- .../framegraph/FrameGraphFactory.java | 18 +- .../renderer/framegraph/FullScreenQuad.java | 29 ++- .../renderer/framegraph/RenderObject.java | 79 +++++++- .../renderer/framegraph/RenderObjectMap.java | 103 ++++++++++- .../renderer/framegraph/RenderResource.java | 111 ++++++++++- .../renderer/framegraph/ResourceList.java | 101 +++++++++- .../renderer/framegraph/ResourceProducer.java | 28 ++- .../renderer/framegraph/ResourceTicket.java | 95 +++++++++- .../jme3/renderer/framegraph/TimeFrame.java | 53 +++++- .../definitions/AbstractResourceDef.java | 31 +++- .../framegraph/definitions/ResourceDef.java | 4 +- .../framegraph/definitions/TextureDef.java | 172 +++++++++++++++++- .../framegraph/definitions/ValueDef.java | 30 ++- .../renderer/framegraph/io/GraphSource.java | 9 +- .../renderer/framegraph/io/GraphTarget.java | 6 + .../framegraph/io/MatParamTargetControl.java | 3 +- .../renderer/framegraph/passes/Attribute.java | 48 ++++- .../framegraph/passes/BucketPass.java | 13 +- .../framegraph/passes/DeferredPass.java | 26 +-- .../framegraph/passes/GBufferPass.java | 8 +- .../renderer/framegraph/passes/Junction.java | 6 +- .../framegraph/passes/OutputBucketPass.java | 3 +- .../framegraph/passes/OutputPass.java | 5 +- .../framegraph/passes/PostProcessingPass.java | 6 +- .../framegraph/passes/RenderPass.java | 3 +- .../framegraph/passes/TileDeferredPass.java | 29 +-- .../renderer/framegraph/passes/Value.java | 13 -- 31 files changed, 1095 insertions(+), 176 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/CameraSize.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Value.java diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/CameraSize.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/CameraSize.java deleted file mode 100644 index fa2eb83db6..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/CameraSize.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.Camera; - -/** - * - * @author codex - */ -public class CameraSize { - - private int width, height; - - public CameraSize() {} - - public boolean needsUpdate(Camera cam) { - return width != cam.getWidth() || height != cam.getHeight(); - } - public boolean needsUpdate(CameraSize camSize) { - return width != camSize.width || height != camSize.height; - } - public boolean update(Camera cam) { - boolean changed = needsUpdate(cam); - width = cam.getWidth(); - height = cam.getHeight(); - return changed; - } - public boolean update(CameraSize camSize) { - boolean changed = needsUpdate(camSize); - width = camSize.width; - height = camSize.height; - return changed; - } - - public int getWidth() { - return width; - } - public int getHeight() { - return height; - } - -} 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 index fc3bbef356..a7d55eb027 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java @@ -12,27 +12,57 @@ import java.io.IOException; /** - * + * Defines the range between 0 and 1 at values written to depth buffers + * are clamped to. + * * @author codex */ public class DepthRange implements Savable { + /** + * Range between 0 and 1. + */ public static final DepthRange IDENTITY = new DepthRange(); + /** + * Range that clamps to zero. + */ public static final DepthRange FRONT = new DepthRange(0, 0); + /** + * Range that clamps to one. + */ public static final DepthRange REAR = new DepthRange(1, 1); private float start, end; + /** + * Creates a new range between 0 and 1. + */ public DepthRange() { set(0, 1); } + /** + * + * @param start + * @param end + */ public DepthRange(float start, float end) { set(start, end); } + /** + * + * @param range + */ public DepthRange(DepthRange range) { set(range); } + /** + * Sets the range. + * + * @param start lower bound + * @param end upper bound + * @return this instance + */ public final DepthRange set(float start, float end) { validateRange(start, end); this.start = start; @@ -40,6 +70,12 @@ public final DepthRange set(float start, float end) { return this; } + /** + * Sets the range. + * + * @param range + * @return this instance + */ public final DepthRange set(DepthRange range) { // no need to validate range here start = range.start; @@ -47,22 +83,44 @@ public final DepthRange set(DepthRange range) { return this; } + /** + * Sets the start (lower) bound. + * + * @param start + * @return this instance + */ public final DepthRange setStart(float start) { validateRange(start, end); this.start = start; return this; } + /** + * Sets the end (upper) bound. + * + * @param end + * @return + */ public final DepthRange setEnd(float end) { validateRange(start, end); this.end = end; return this; } + /** + * Gets the start (lower) bound. + * + * @return + */ public float getStart() { return start; } + /** + * Gets the end (upper) bound. + * + * @return + */ public float getEnd() { return end; } 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 7c6200dadc..9f4f49a569 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 @@ -45,8 +45,11 @@ import java.util.function.Predicate; /** - * 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 + * Contains necessary context for framegraph rendering. + *

      + * Also manages renderer states, to ensure settings do no leak between passes. + * + * @author codex */ public class FGRenderContext { @@ -54,7 +57,6 @@ public class FGRenderContext { private final RenderManager renderManager; private ViewPort viewPort; private AppProfiler profiler; - private final CameraSize camSize = new CameraSize(); private float tpf; private final FullScreenQuad screen; @@ -71,6 +73,13 @@ public FGRenderContext(FrameGraph frameGraph, RenderManager renderManager) { this.screen = new FullScreenQuad(this.frameGraph.getAssetManager()); } + /** + * Targets this context to the viewport. + * + * @param vp + * @param profiler + * @param tpf + */ public void target(ViewPort vp, AppProfiler profiler, float tpf) { this.viewPort = vp; this.profiler = profiler; @@ -78,7 +87,6 @@ public void target(ViewPort vp, AppProfiler profiler, float tpf) { if (viewPort == null) { throw new NullPointerException("ViewPort cannot be null."); } - camSize.update(viewPort.getCamera()); } /** @@ -114,31 +122,74 @@ public void popFrameBuffer() { renderManager.getRenderer().setFrameBuffer(frameBuffer); } + /** + * Renders the specified queue bucket. + * + * @param bucket queue bucket to render (not null and not {@link RenderQueue.Bucket#Inherit}) + * @param clear true to flush the bucket + */ public void renderViewPortQueue(RenderQueue.Bucket bucket, boolean clear) { viewPort.getQueue().renderQueue(bucket, renderManager, viewPort.getCamera(), clear); } + /** + * Renders the material on a fullscreen quad. + * + * @param mat + */ public void renderFullscreen(Material mat) { screen.render(renderManager, mat); } + /** + * Renders the color and depth textures on a fullscreen quad, where + * the color texture informs the color, and the depth texture informs + * the depth. + *

      + * If both color and depth are null, no rendering will be performed + * + * @param color color texture, or null + * @param depth depth texture, or null + */ public void transferTextures(Texture2D color, Texture2D depth) { screen.render(renderManager, color, depth); } + /** + * Gets the render manager. + * + * @return + */ public RenderManager getRenderManager() { return renderManager; } + /** + * Gets the viewport currently being rendered. + * + * @return + */ public ViewPort getViewPort() { return viewPort; } + /** + * Gets the profiler. + * + * @return app profiler, or null + */ public AppProfiler getProfiler() { return profiler; } - public CameraSize getCameraSize() { - return camSize; - } + /** + * Gets the renderer held by the render manager. + * + * @return + */ public Renderer getRenderer() { return renderManager.getRenderer(); } + /** + * Gets the render queue held by the viewport. + * + * @return + */ public RenderQueue getRenderQueue() { if (viewPort != null) { return viewPort.getQueue(); @@ -146,19 +197,44 @@ public RenderQueue getRenderQueue() { return null; } } + /** + * Gets the fullscreen quad used for fullscreen renders. + * + * @return + */ public FullScreenQuad getScreen() { return screen; } + /** + * Gets the time per frame. + * + * @return + */ public float getTpf() { return tpf; } + /** + * Gets the camera width. + * + * @return + */ public int getWidth() { - return camSize.getWidth(); + return viewPort.getCamera().getWidth(); } + /** + * Gets the camera height. + * + * @return + */ public int getHeight() { - return camSize.getHeight(); + return viewPort.getCamera().getHeight(); } + /** + * Returns true if the app profiler is not null. + * + * @return + */ public boolean isProfilerAvailable() { return profiler != null; } 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 61ea4bf346..593cf03a98 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 @@ -23,6 +23,39 @@ /** * Manages render passes, dependencies, and resources in a node-based parameter system. + *

      + * Rendering is a complicated task, involving many parameters and resources. The framegraph + * aims to simplify rendering from the user's perspective, and limit the creation, binding, + * and destruction of resources wherever possible. + *

      + * Passes are expected to declare and describe beforehand the resources they plan on using + * during execution. Passes can also reference resources declared by other passes. The resource + * manager can determine from these "promises" which passes can be culled, as their contributions + * would ultimately go unused. + *

      + * During execution, passes expected ask the resource manager for the resource the declared or referenced + * earlier. If the resource does not already exist (is virtual) the manager will either create a new + * resource or allocate an existing, unused resource that qualifies based on the description provided + * on declaration. Reallocation is usually preferred to reduce memory footprint. + *

      + * FrameGraph execution occurs in four steps: + *

        + *
      1. Preparation. Passes declare, reserve, and reference resources + * during this step.
      2. + *
      3. Culling. The resource manager determines which resources and + * passes are unused, and culls them. This can often save loads of resources, as many + * passes may not used for large parts of the application.
      4. + *
      5. Execution. Passes that were not culled acquire the resources + * they need, and perform rendering operations. All passes are expected to release + * all resources they declared or referenced in the first step, however, this is done + * automatically by {@link RenderPass}.
      6. + *
      7. Reset. Passes perform whatever post-rendering cleanup is necessary.
      8. + *
      + *

      + * Each step begins only after every qualifying pass has completed the previous step. + *

      + * Passes are executed in the order they appear in the queue. This can sometimes lead + * to unintended consequences, as a pass may use resources generated by a later queue. * * @author codex */ @@ -33,7 +66,12 @@ public class FrameGraph implements Savable { private final FGRenderContext context; private final LinkedList passes = new LinkedList<>(); private boolean rendered = false; - + + /** + * + * @param assetManager asset manager (not null) + * @param renderManager render manager (not null) + */ public FrameGraph(AssetManager assetManager, RenderManager renderManager) { this.assetManager = assetManager; this.resources = new ResourceList(renderManager.getRenderObjectMap()); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 080b946ca2..a5beee8507 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -16,11 +16,19 @@ import com.jme3.renderer.queue.RenderQueue; /** - * + * Utility class for constructing common framegraphs. + * * @author codex */ public class FrameGraphFactory { + /** + * Constructs a standard forward framegraph, with no controllable features. + * + * @param assetManager + * @param renderManager + * @return forward framegraph + */ public static FrameGraph forward(AssetManager assetManager, RenderManager renderManager) { FrameGraph fg = new FrameGraph(assetManager, renderManager); fg.add(new OutputBucketPass(RenderQueue.Bucket.Opaque)); @@ -32,6 +40,14 @@ public static FrameGraph forward(AssetManager assetManager, RenderManager render return fg; } + /** + * Constructs a deferred or tiled deferred framegraph. + * + * @param assetManager + * @param renderManager + * @param tiled true to construct advanced tiled deferred + * @return deferred framegraph + */ public static FrameGraph deferred(AssetManager assetManager, RenderManager renderManager, boolean tiled) { FrameGraph fg = new FrameGraph(assetManager, renderManager); GBufferPass gbuf = fg.add(new GBufferPass()); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java index 4aebbf4168..acaed31998 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java @@ -7,7 +7,6 @@ import com.jme3.asset.AssetManager; import com.jme3.light.LightList; import com.jme3.material.Material; -import com.jme3.material.RenderState.BlendMode; import com.jme3.renderer.RenderManager; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -16,7 +15,8 @@ import com.jme3.util.BufferUtils; /** - * + * A quad specifically for rendering fullscreen. + * * @author codex */ public class FullScreenQuad { @@ -24,6 +24,10 @@ public class FullScreenQuad { private final Geometry geometry; private final Material transferMat; + /** + * + * @param assetManager + */ public FullScreenQuad(AssetManager assetManager) { Mesh mesh = new Mesh(); mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer( @@ -43,16 +47,37 @@ public FullScreenQuad(AssetManager assetManager) { transferMat = new Material(assetManager, "Common/MatDefs/ShadingCommon/TextureTransfer.j3md"); } + /** + * Renders the material on the quad. + * + * @param rm + * @param material + */ public void render(RenderManager rm, Material material) { geometry.setMaterial(material); geometry.updateGeometricState(); rm.renderGeometry(geometry); } + /** + * Renders the material with the light list on the quad. + * + * @param rm + * @param material + * @param lights + */ public void render(RenderManager rm, Material material, LightList lights) { geometry.setMaterial(material); geometry.updateGeometricState(); rm.renderGeometry(geometry, lights); } + /** + * Renders the color and depth textures on the quad, where the depth texture + * informs the depth value. + * + * @param rm + * @param color color texture, or null + * @param depth depth texture, or null + */ public void render(RenderManager rm, Texture2D color, Texture2D depth) { boolean writeDepth = depth != null; if (color != null || writeDepth) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java index 02b34b7bbd..1a328f052e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java @@ -10,7 +10,8 @@ import java.util.function.Consumer; /** - * + * Stores an object used for rendering. + * * @author codex * @param */ @@ -29,7 +30,13 @@ public class RenderObject { private boolean acquired = false; private boolean constant = true; private Consumer disposer; - + + /** + * + * @param def + * @param object + * @param timeout + */ public RenderObject(ResourceDef def, T object, int timeout) { this.id = nextId++; if (object == null) { @@ -49,46 +56,104 @@ else if (object instanceof NativeObject) { } } + /** + * Acquires this render object for use. + */ public void acquire() { + if (acquired) { + throw new IllegalStateException("Already acquired."); + } timeout = timeoutDuration; acquired = true; } + /** + * Releases this render object from use. + */ public void release() { if (!acquired) { throw new IllegalStateException("Already released."); } acquired = false; } + /** + * Reserves this render object for use at the specified render pass index. + * + * @param index + */ public void reserve(int index) { reservations.set(index); } + /** + * Disposes the internal object. + */ public void dispose() { disposer.accept(object); } + /** + * Clears all reservations. + */ public void clearReservations() { reservations.clear(); } + /** + * Ticks down the timer tracking frames since last use. + * + * @return true if the timer has not expired + */ public boolean tickTimeout() { return timeout-- > 0; } + /** + * Sets this render object as constant, so that this cannot be reallocated. + * + * @param constant + */ public void setConstant(boolean constant) { this.constant = constant; } + /** + * Gets the id of this render object. + * + * @return + */ public long getId() { return id; } + /** + * Gets the internal object. + * + * @return + */ public T getObject() { return object; } + /** + * Returns true if this render object is acquired (and not yet released). + * + * @return + */ public boolean isAcquired() { return acquired; } + /** + * Returns true if this render object is reserved at the given + * render pass index. + * + * @param index + * @return + */ public boolean isReservedAt(int index) { return reservations.get(index); } + /** + * Returns true if this render object is reserved within the time frame. + * + * @param frame + * @return + */ public boolean isReservedWithin(TimeFrame frame) { if (frame.getStartIndex() >= reservations.size()) { return false; @@ -101,10 +166,20 @@ public boolean isReservedWithin(TimeFrame frame) { } return false; } + /** + * Returns true if this render object is constant. + * + * @return + */ public boolean isConstant() { return constant; } + /** + * Gets the next id. + * + * @return + */ public static long getNextId() { return nextId; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 5ec23e9257..eeecabef1d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -10,12 +10,11 @@ import java.util.logging.Logger; /** - * + * Manages creation, reallocation, and disposal of {@link RenderObject}s. + * * @author codex */ public class RenderObjectMap { - - private static final Logger LOG = Logger.getLogger(RenderObjectMap.class.getName()); private final HashMap objectMap = new HashMap<>(); private final int timeout = 1; @@ -50,6 +49,17 @@ protected boolean applyDirectResource(RenderResource resource, RenderObje return false; } + /** + * Allocates a render object to the resource. + *

      + * First, if this resource holds an object id, the corresponding render object, + * if it still exists, will be tried for reallocation. Then, each render object + * will be tried for reallocation. Finally, if all else fails, a new render object + * will be created and allocated to the resource. + * + * @param + * @param resource + */ public void allocate(RenderResource resource) { if (resource.isUndefined()) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); @@ -108,6 +118,15 @@ public void allocate(RenderResource resource) { resource.setObject(create(def)); objectsCreated++; } + /** + * Makes a reservation of render object holding the specified id at the render + * pass index so that no other resource may (without a reservation) use that + * render object at that time. + * + * @param objectId + * @param index + * @return + */ public boolean reserve(long objectId, int index) { RenderObject obj = objectMap.get(objectId); if (obj != null) { @@ -117,6 +136,16 @@ public boolean reserve(long objectId, int index) { } return false; } + /** + * Untracks the render object held by the resource. + *

      + * If the resource is virtual, a new resource will be allocated then + * immediately untracked. + * + * @param + * @param resource + * @return + */ public T extract(RenderResource resource) { if (resource.isUndefined()) { return null; @@ -127,6 +156,11 @@ public T extract(RenderResource resource) { RenderObject obj = objectMap.remove(resource.getTicket().getObjectId()); return (obj != null ? obj.getObject() : null); } + /** + * Disposes the render object pointed to by the resource. + * + * @param resource + */ public void dispose(RenderResource resource) { long id = resource.getTicket().getObjectId(); if (id >= 0) { @@ -137,6 +171,9 @@ public void dispose(RenderResource resource) { } } + /** + * Should be called only when a new rendering frame begins (before rendering). + */ public void newFrame() { totalAllocations = 0; officialReservations = 0; @@ -146,11 +183,19 @@ public void newFrame() { objectsReallocated = 0; flushedObjects = 0; } + /** + * Clears reservations of all tracked render objects. + */ public void clearReservations() { for (RenderObject obj : objectMap.values()) { obj.clearReservations(); } } + /** + * Flushes the map. + *

      + * Any render objects that have not been used for a number of frames are disposed. + */ public void flushMap() { totalObjects = objectMap.size(); for (Iterator it = objectMap.values().iterator(); it.hasNext();) { @@ -164,6 +209,11 @@ public void flushMap() { obj.setConstant(false); } } + /** + * Clears the map. + *

      + * All tracked render objects are disposed. + */ public void clearMap() { for (RenderObject obj : objectMap.values()) { obj.dispose(); @@ -171,27 +221,74 @@ public void clearMap() { objectMap.clear(); } + /** + * Get the total number of allocations that occured during the last render frame. + * + * @return + */ public int getTotalAllocations() { return totalAllocations; } + /** + * Gets the number of official reservations that occured during the last + * render frame. + *

      + * An official reservation is one made using {@link #reserve(long, int)}. + * + * @return + */ public int getOfficialReservations() { return officialReservations; } + /** + * Gets the number of completed reservations that occured during the + * last render frame. + *

      + * A completed reservation is declared and allocated. + * + * @return + */ public int getCompletedReservations() { return completedReservations; } + /** + * Gets the number of incomplete or failed reservations that occured + * during the last render frame. + * + * @return + */ public int getFailedReservations() { return failedReservations; } + /** + * Gets the number of render objects created during the last render frame. + * + * @return + */ public int getObjectsCreated() { return objectsCreated; } + /** + * Gets the number of reallocations that occured during the last render frame. + * + * @return + */ public int getObjectsReallocated() { return objectsReallocated; } + /** + * Gets the number of render objects present before flushing. + * + * @return + */ public int getTotalObjects() { return totalObjects; } + /** + * Gets the number of render objects disposed during flushing. + * + * @return + */ public int getFlushedObjects() { return flushedObjects; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 2343539276..811c69be87 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -8,7 +8,8 @@ import java.util.Objects; /** - * + * Represents an existing or future resource used for rendering. + * * @author codex * @param */ @@ -21,10 +22,15 @@ public class RenderResource { private RenderObject object; private T resource; private int refs = 0; - private int timeout = 0; private boolean survivesRefCull = false; private boolean undefined = false; + /** + * + * @param producer + * @param def + * @param ticket + */ public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { this.producer = producer; this.def = def; @@ -32,20 +38,27 @@ public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTic this.lifetime = new TimeFrame(this.producer.getExecutionIndex(), 0); } + /** + * Reference this resource from the specified render pass index. + * + * @param index + */ public void reference(int index) { lifetime.extendTo(index); refs++; } + /** + * Releases this resource from one user. + */ public void release() { refs--; } - public boolean tickTimeout() { - return timeout-- > 0; - } - public void setTimeout(int timeout) { - this.timeout = timeout; - } + /** + * Sets the render object held by this resource. + * + * @param object + */ public void setObject(RenderObject object) { if (object != null) { setObject(object, object.getObject()); @@ -55,6 +68,12 @@ public void setObject(RenderObject object) { resource = null; } } + /** + * Sets the render object and concrete resource held by this render resource. + * + * @param object + * @param resource + */ public void setObject(RenderObject object, T resource) { Objects.requireNonNull(object, "Object cannot be null."); Objects.requireNonNull(resource, "Object resource cannot be null."); @@ -69,6 +88,9 @@ public void setObject(RenderObject object, T resource) { this.object.acquire(); ticket.setObjectId(this.object.getId()); } + /** + * Marks this resource as undefined. + */ public void setUndefined() { if (object != null) { throw new IllegalArgumentException("Resource is already defined."); @@ -76,46 +98,119 @@ public void setUndefined() { undefined = true; } + /** + * Gets this resource's producer. + * + * @return + */ public ResourceProducer getProducer() { return producer; } + /** + * Gets the resource definition. + * + * @return + */ public ResourceDef getDefinition() { return def; } + /** + * Gets the resource ticket. + * + * @return + */ public ResourceTicket getTicket() { return ticket; } + /** + * Gets the lifetime of this resource in render pass indices. + * + * @return + */ public TimeFrame getLifeTime() { return lifetime; } + /** + * Gets the render object. + * + * @return + */ public RenderObject getObject() { return object; } + /** + * Gets the concrete resource. + * + * @return + */ public T getResource() { return resource; } + /** + * Gets the index of this resource. + * + * @return + */ public int getIndex() { return ticket.getWorldIndex(); } + /** + * Gets the number of references to this resource. + * + * @return + */ public int getNumReferences() { return refs; } + /** + * Returns true if this resource always survives cull by reference. + * + * @param survivesRefCull + */ public void setSurvivesRefCull(boolean survivesRefCull) { this.survivesRefCull = survivesRefCull; } + /** + * Returns true if this resource is virtual. + *

      + * A resource is virtual when it does not hold a concrete resource + * and is not set as undefined. + * + * @return + */ public boolean isVirtual() { return object == null && !undefined; } + /** + * Returns true if this resource is referenced by users other than the + * producer. + * + * @return + */ public boolean isReferenced() { return refs > 0; } + /** + * Returns true if this resource is used (including the producer). + * + * @return + */ public boolean isUsed() { return refs >= 0; } + /** + * Returns true if this resource is marked as undefined. + * + * @return + */ public boolean isUndefined() { return undefined; } + /** + * + * @return + */ public boolean isSurvivesRefCull() { return survivesRefCull; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 34e1a1fecd..68fcd47135 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -7,14 +7,12 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture; -import java.nio.Buffer; import java.util.ArrayList; import java.util.LinkedList; -import java.util.List; -import java.util.logging.Logger; /** - * + * Manages render resource declarations, references, and releases for a framegraph. + * * @author codex */ public class ResourceList { @@ -99,7 +97,7 @@ public ResourceTicket declare(ResourceProducer producer, ResourceDef d } /** - * If the ticket contains a valid object ID, that object will be reserved + * If the ticket contains a valid object ID, that render object will be reserved * at the index. *

      * Reserved objects cannot be allocated to another resource before the indexed @@ -114,6 +112,12 @@ public void reserve(int passIndex, ResourceTicket ticket) { ticket.copyObjectTo(locate(ticket).getTicket()); } } + /** + * Makes reservations for each given ticket. + * + * @param passIndex + * @param tickets + */ public void reserve(int passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { reserve(passIndex, t); @@ -127,24 +131,44 @@ public void reserve(int passIndex, ResourceTicket... tickets) { * which is referencing the resource, which is important for determining resource * lifetime. * - * @param passIndex + * @param passIndex render pass index * @param ticket */ public void reference(int passIndex, ResourceTicket ticket) { locate(ticket).reference(passIndex); } + /** + * References the resource associated with the ticket if the ticket + * is not null and does not have a negative world index. + * + * @param passIndex render pass index + * @param ticket + * @return + */ public boolean referenceOptional(int passIndex, ResourceTicket ticket) { - if (ticket != null && ticket.getWorldIndex() >= 0) { + if (validate(ticket)) { reference(passIndex, ticket); return true; } return false; } + /** + * References resources associated with the tickets. + * + * @param passIndex render pass index + * @param tickets + */ public void reference(int passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { reference(passIndex, t); } } + /** + * Optionally references resources associated with the tickets. + * + * @param passIndex render pass index + * @param tickets + */ public void referenceOptional(int passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { referenceOptional(passIndex, t); @@ -194,6 +218,12 @@ public void setConstant(ResourceTicket ticket) { obj.setConstant(true); } } + /** + * Marks the resource associated with the ticket if the ticket is not + * null and does not have a negative world index. + * + * @param ticket + */ public void setConstantOptional(ResourceTicket ticket) { if (validate(ticket)) { setConstant(ticket); @@ -210,6 +240,16 @@ public void setSurvivesReferenceCull(ResourceTicket ticket) { locate(ticket).setSurvivesRefCull(true); } + /** + * Returns true if the resource associated with the ticket is virtual. + *

      + * A resource is virtual if it does not contain a concrete object and is + * not marked as undefined. + * + * @param ticket + * @param optional + * @return + */ public boolean isVirtual(ResourceTicket ticket, boolean optional) { if (!optional || validate(ticket)) { return locate(ticket).isVirtual(); @@ -244,6 +284,17 @@ public T acquire(ResourceTicket ticket) { } return acquire(resource, ticket); } + /** + * If the ticket is not null and has a positive or zero world index, an object + * will be acquired for the resource and returned. + *

      + * Otherwise, the given default value will be returned. + * + * @param + * @param ticket + * @param value default value + * @return + */ public T acquireOrElse(ResourceTicket ticket, T value) { if (validate(ticket)) { RenderResource resource = locate(ticket); @@ -335,6 +386,17 @@ public T extract(ResourceTicket ticket) { } return object; } + /** + * If the ticket is not null and has a positive or zero world index, an object + * will be extracted by the resource and returned. + *

      + * Otherwise, the given default value will be returned. + * + * @param + * @param ticket + * @param value + * @return + */ public T extractOrElse(ResourceTicket ticket, T value) { if (ticket != null && ticket.getWorldIndex() >= 0) { T object = extract(locate(ticket), ticket); @@ -359,6 +421,13 @@ public void release(ResourceTicket ticket) { } } } + /** + * Releases the ticket if the ticket is not null and contains a non-negative + * world index. + * + * @param ticket + * @return + */ public boolean releaseOptional(ResourceTicket ticket) { if (ticket != null && ticket.getWorldIndex() >= 0) { release(ticket); @@ -366,11 +435,21 @@ public boolean releaseOptional(ResourceTicket ticket) { } return false; } + /** + * Releases the resources obtained by the tickets from use. + * + * @param tickets + */ public void release(ResourceTicket... tickets) { for (ResourceTicket t : tickets) { release(t); } } + /** + * Optionally releases the resources obtained by the tickets from use. + * + * @param tickets + */ public void releaseOptional(ResourceTicket... tickets) { for (ResourceTicket t : tickets) { releaseOptional(t); @@ -379,6 +458,8 @@ public void releaseOptional(ResourceTicket... tickets) { /** * Prepares this for rendering. + *

      + * This should only be called once per frame. */ public void beginRenderingSession() { textureBinds = 0; @@ -435,6 +516,12 @@ public void clear() { nextSlot = 0; } + /** + * Gets the number of known texture binds that occured during + * the last render frame. + * + * @return + */ public int getTextureBinds() { return textureBinds; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java index bbd01fd02e..693e30b9e9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java @@ -7,17 +7,43 @@ import java.util.Collection; /** - * + * Interface for objects that use and produce resources. + * * @author codex */ public interface ResourceProducer { + /** + * Gets the index of execution. + * + * @return + */ public int getExecutionIndex(); + /** + * Dereferences this producer. + * + * @return + */ public boolean dereference(); + /** + * Returns true if this producer is used. + * + * @return + */ public boolean isUsed(); + /** + * Gets a collection of all input tickets. + * + * @return + */ public Collection getInputTickets(); + /** + * Gets a collection of all output tickets. + * + * @return + */ public Collection getOutputTickets(); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index 86423bcd91..5921c064ba 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -5,11 +5,13 @@ package com.jme3.renderer.framegraph; /** - * References a {@link RenderResource} by either name or index. + * References a {@link RenderResource} by index. *

      - If a resource is referenced by name, the index of the resource - will be assigned to the ticket, in order to make future references - faster. + * A ticket can be set as another tickets source, in which case the former inherits + * the resource index of the latter. + *

      + * Tickets can also vaguely point to the last known render object, which is used + * to prioritize that render object, especially for reservations. * * @author codex * @param @@ -21,26 +23,57 @@ public class ResourceTicket { private long objectId = -1; private ResourceTicket source; + /** + * Creates a blank ticket with a negative local index. + */ public ResourceTicket() { this(null, -1); } + /** + * Creates a ticket with the name and a negative local index. + * + * @param name + */ public ResourceTicket(String name) { this(name, -1); } + /** + * Creates a ticket with the local index. + * + * @param index + */ public ResourceTicket(int index) { this(null, index); } + /** + * Creates a ticket with the name and local index. + * + * @param name + * @param index + */ public ResourceTicket(String name, int index) { this.name = name; this.localIndex = index; } + /** + * Copies this ticket's resource index to the target ticket. + * + * @param target + * @return + */ public ResourceTicket copyIndexTo(ResourceTicket target) { if (target == null) { target = new ResourceTicket(); } return target.setLocalIndex(localIndex); } + /** + * Copies this ticket's object ID to the target ticket. + * + * @param target + * @return + */ public ResourceTicket copyObjectTo(ResourceTicket target) { if (target == null) { target = new ResourceTicket(); @@ -49,24 +82,61 @@ public ResourceTicket copyObjectTo(ResourceTicket target) { return target; } + /** + * Sets the source ticket. + * + * @param source + */ public void setSource(ResourceTicket source) { this.source = source; } + /** + * Sets the name of this ticket. + * + * @param name + * @return + */ public ResourceTicket setName(String name) { this.name = name; return this; } + /** + * Sets the local index. + *

      + * The local index is overriden if the source ticket is not null and + * the source's world index is not negative. + * + * @param index + * @return + */ protected ResourceTicket setLocalIndex(int index) { this.localIndex = index; return this; } + /** + * Sets the object ID. + * + * @param objectId + */ public void setObjectId(long objectId) { this.objectId = objectId; } + /** + * + * @return + */ public String getName() { return name; } + /** + * Gets the world index. + *

      + * If the source ticket is null or its world index is negative, this ticket's + * local index will be returned. + * + * @return + */ public int getWorldIndex() { if (source != null) { int i = source.getWorldIndex(); @@ -74,15 +144,32 @@ public int getWorldIndex() { } return localIndex; } + /** + * + * @return + */ public int getLocalIndex() { return localIndex; } + /** + * + * @return + */ public long getObjectId() { return objectId; } + /** + * + * @return + */ public ResourceTicket getSource() { return source; } + /** + * Returns true if this source ticket is not null. + * + * @return + */ public boolean hasSource() { return source != null; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java index 1d833fe619..f1cf9e0723 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java @@ -5,14 +5,24 @@ package com.jme3.renderer.framegraph; /** - * + * Represents a period of time starting at the start of the indexed pass, and + * lasting for the duration of a number of following passes. + * * @author codex */ public class TimeFrame { private int index, length; + /** + * + */ private TimeFrame() {} + /** + * + * @param passIndex + * @param length + */ public TimeFrame(int passIndex, int length) { this.index = passIndex; this.length = length; @@ -24,9 +34,21 @@ public TimeFrame(int passIndex, int length) { } } + /** + * Extends, but does not retract, the length so that this time frame + * includes the given index. + * + * @param passIndex + */ public void extendTo(int passIndex) { length = Math.max(length, passIndex-this.index); } + /** + * Copies this to the target time frame. + * + * @param target + * @return + */ public TimeFrame copyTo(TimeFrame target) { if (target == null) { target = new TimeFrame(); @@ -36,20 +58,47 @@ public TimeFrame copyTo(TimeFrame target) { return target; } + /** + * Gets index of the first pass this time frame includes. + * + * @return + */ public int getStartIndex() { return index; } + /** + * Gets the length. + * + * @return + */ public int getLength() { return length; } + /** + * Gets index of the last pass this time frame includes. + * + * @return + */ public int getEndIndex() { return index+length; } + /** + * Returns true if this time frame overlaps the given time frame. + * + * @param time + * @return + */ public boolean overlaps(TimeFrame time) { return index <= time.index+time.length && index+length >= time.index; } - public boolean contains(int index) { + /** + * Returns true if this time frame includes the given index. + * + * @param index + * @return + */ + public boolean includes(int index) { return index <= index && index+length >= index; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java index 02ab274c0b..8fd92c5e71 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java @@ -34,16 +34,45 @@ public boolean isUseExisting() { public boolean isDisposeOnRelease() { return disposeOnRelease; } - + + /** + * Sets the consumer responsible for disposing the resource. + *

      + * default=null + * + * @param disposalMethod disposal consumer, or null to use defaults + */ public void setDisposalMethod(Consumer disposalMethod) { this.disposalMethod = disposalMethod; } + /** + * Sets the number of frames the resource can be static before being + * disposed. + *

      + * If less than zero, the default value will be used instead. + * + * @param staticTimout + */ public void setStaticTimeout(int staticTimout) { this.staticTimeout = staticTimout; } + /** + * Sets this definition to allow for use of reallocated objects. + *

      + * default=true + * + * @param useExisting + */ public void setUseExisting(boolean useExisting) { this.useExisting = useExisting; } + /** + * Sets the resource to be disposed when it is unused. + *

      + * default=false + * + * @param disposeOnRelease + */ public void setDisposeOnRelease(boolean disposeOnRelease) { this.disposeOnRelease = disposeOnRelease; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index ccb24521fe..9a3f7a126b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -7,7 +7,9 @@ import java.util.function.Consumer; /** - * + * Creates and reallocates objects for a resource and defines how that resource + * will behaves. + * * @author codex * @param */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index b268a0249b..462adec559 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -6,6 +6,7 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; import com.jme3.texture.image.ColorSpace; import java.util.ArrayList; import java.util.Objects; @@ -13,7 +14,11 @@ import java.util.function.Function; /** - * + * General resource definition for textures. + *

      + * Other textures and objects only apply for reallocation if a contained + * image meets the parameters of this definition. + * * @author codex * @param */ @@ -35,9 +40,20 @@ public class TextureDef extends AbstractResourceDef imple private boolean formatFlexible = false; private boolean colorSpaceFlexible = false; + /** + * + * @param type + * @param textureBuilder + */ public TextureDef(Class type, Function textureBuilder) { this(type, textureBuilder, Image.Format.RGBA8); } + /** + * + * @param type + * @param textureBuilder + * @param format + */ public TextureDef(Class type, Function textureBuilder, Image.Format format) { Objects.requireNonNull(type); Objects.requireNonNull(textureBuilder); @@ -45,6 +61,9 @@ public TextureDef(Class type, Function textureBuilder, Image.Format this.type = type; this.textureBuilder = textureBuilder; this.format = format; + if (!Texture2D.class.isAssignableFrom(type)) { + depth = 1; + } } @Override @@ -128,68 +147,158 @@ private boolean validateImage(Image img) { && (colorSpaceFlexible || img.getColorSpace() == colorSpace); } + /** + * Sets the function that constructs a texture from an image. + * + * @param textureBuilder + */ public void setTextureBuilder(Function textureBuilder) { Objects.requireNonNull(textureBuilder); this.textureBuilder = textureBuilder; } + /** + * Sets the function that extracts an Image from and object. + * + * @param imageExtractor + */ public void setImageExtractor(Function imageExtractor) { this.imageExtractor = imageExtractor; } + /** + * Sets the texture width. + * + * @param width texture width greater than zero + */ public void setWidth(int width) { if (width <= 0) { throw new IllegalArgumentException("Width must be greater than zero."); } this.width = width; } + /** + * Sets the texture height. + * + * @param height texture height greater than zero + */ public void setHeight(int height) { if (height <= 0) { throw new IllegalArgumentException("Height must be greater than zero."); } this.height = height; } + /** + * Sets the texture depth. + *

      + * Values less than or equal to zero indicate a 2D texture. + * + * @param depth texture depth (or less or equal to than zero) + */ public void setDepth(int depth) { if (depth < 0) { throw new IllegalArgumentException("Depth cannot be less than zero."); } this.depth = depth; } + /** + * Sets the width and height of the texture. + * + * @param width + * @param height + */ public void setSize(int width, int height) { setWidth(width); setHeight(height); } + /** + * Sets the width, height, and depth of the texture. + * + * @param width + * @param height + * @param depth + */ public void setSize(int width, int height, int depth) { setWidth(width); setHeight(height); setDepth(depth); } + /** + * Sets the number of samples of the texture's image. + * + * @param samples + */ public void setSamples(int samples) { if (samples <= 0) { throw new IllegalArgumentException("Image samples must be greater than zero."); } this.samples = samples; } + /** + * Sets the format of the image. + * + * @param format + */ public void setFormat(Image.Format format) { Objects.requireNonNull(format); this.format = format; } + /** + * Sets reallocation so that the target image does not need the exact + * format of the definition. + *

      + * default=false + * + * @param formatFlexible + */ public void setFormatFlexible(boolean formatFlexible) { this.formatFlexible = formatFlexible; } + /** + * Sets the color space of the texture. + * + * @param colorSpace + */ public void setColorSpace(ColorSpace colorSpace) { this.colorSpace = colorSpace; } + /** + * Sets the magnification filter of the texture. + * + * @param magFilter mag filter, or null to use default + */ public void setMagFilter(Texture.MagFilter magFilter) { this.magFilter = magFilter; } + /** + * Sets the minification filter of the texture. + * + * @param minFilter min filter, or null to use default + */ public void setMinFilter(Texture.MinFilter minFilter) { this.minFilter = minFilter; } + /** + * Sets reallocation so that the target image does not need the exact + * format of the definition. + * + * @param colorSpaceFlexible + */ public void setColorSpaceFlexible(boolean colorSpaceFlexible) { this.colorSpaceFlexible = colorSpaceFlexible; } + /** + * Sets the wrap mode on all axis. + * + * @param mode + */ public void setWrap(Texture.WrapMode mode) { wrapS = wrapT = wrapR = mode; } + /** + * Sets the wrap mode on the specified axis. + * + * @param axis + * @param mode + */ public void setWrap(Texture.WrapAxis axis, Texture.WrapMode mode) { switch (axis) { case S: wrapS = mode; break; @@ -197,46 +306,105 @@ public void setWrap(Texture.WrapAxis axis, Texture.WrapMode mode) { case R: wrapR = mode; break; } } - + + /** + * Gets the texture type handled by this definition. + * + * @return + */ public Class getType() { return type; } + /** + * + * @return + */ public Function getTextureBuilder() { return textureBuilder; } + /** + * + * @return + */ public Function getImageExtractor() { return imageExtractor; } + /** + * + * @return + */ public int getWidth() { return width; } + /** + * + * @return + */ public int getHeight() { return height; } + /** + * + * @return + */ public int getDepth() { return depth; } + /** + * + * @return + */ public int getSamples() { return samples; } + /** + * + * @return + */ public Image.Format getFormat() { return format; } + /** + * + * @return + */ public boolean isFormatFlexible() { return formatFlexible; } + /** + * + * @return + */ public ColorSpace getColorSpace() { return colorSpace; } + /** + * + * @return + */ public Texture.MagFilter getMagFilter() { return magFilter; } + /** + * + * @return + */ public Texture.MinFilter getMinFilter() { return minFilter; } + /** + * + * @return + */ public boolean isColorSpaceFlexible() { return colorSpaceFlexible; } + /** + * Gets the wrap mode on the specified axis. + * + * @param axis + * @return + */ public Texture.WrapMode getWrap(Texture.WrapAxis axis) { switch (axis) { case S: return wrapS; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java index ded9da95cd..0ac0945014 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java @@ -8,7 +8,8 @@ import java.util.function.Function; /** - * + * General resource definition implementation. + * * @author codex * @param */ @@ -40,20 +41,43 @@ public T applyDirectResource(Object resource) { public T applyIndirectResource(Object resource) { return null; } - + + /** + * Sets the builder function that constructs new objects. + * + * @param builder + */ public void setBuilder(Function builder) { this.builder = builder; } + /** + * Sets the consumer that alters objects for reallocation. + * + * @param reviser + */ public void setReviser(Consumer reviser) { this.reviser = reviser; } - + + /** + * Gets the object type handled by this definition. + * + * @return + */ public Class getType() { return type; } + /** + * + * @return + */ public Function getBuilder() { return builder; } + /** + * + * @return + */ public Consumer getReviser() { return reviser; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java index da5b12158f..96f6abff17 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java @@ -7,12 +7,19 @@ import com.jme3.renderer.ViewPort; /** - * + * Provides values to a framegraph from game logic. + * * @author codex * @param */ public interface GraphSource { + /** + * Gets the value provided to the framegraph. + * + * @param viewPort viewport currently being rendered + * @return value (may be null in some circumstances) + */ public T getGraphValue(ViewPort viewPort); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java index 11b58ccb45..7ee56ead85 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java @@ -14,6 +14,12 @@ */ public interface GraphTarget { + /** + * Sets the value recieved from the framegraph. + * + * @param viewPort viewport currently being rendered + * @param value value from framegraph + */ public void setGraphValue(ViewPort viewPort, T value); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java index ac2be434bf..0485226d83 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java @@ -14,7 +14,8 @@ import com.jme3.shader.VarType; /** - * + * Controls a material parameter based on values provided by a framegraph. + * * @author codex * @param */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index 1fab030901..105a0ca6c8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -10,10 +10,18 @@ import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.ValueDef; +import java.util.LinkedList; import java.util.function.Function; /** - * + * Interface pass between the framegraph and game logic, allowing them to communicate. + *

      + * Game logic can listen to framegraph parameters via {@link GraphTarget}s, and/or game logic + * can communicate parameters to the framegraph via a {@link GraphSource}. + *

      + * Objects handled by this pass are automatically marked as constant, so that future changes + * do not taint the game logic's resource view. + * * @author codex * @param */ @@ -22,7 +30,7 @@ public class Attribute extends RenderPass implements Function { private ResourceTicket in, out; private T value; private ValueDef def; - private GraphTarget target; + private LinkedList> targets; private GraphSource source; @Override @@ -41,8 +49,10 @@ protected void prepare(FGRenderContext context) { @Override protected void execute(FGRenderContext context) { value = resources.acquireOrElse(in, null); - if (value != null && target != null) { - target.setGraphValue(context.getViewPort(), value); + if (value != null && !targets.isEmpty()) { + for (GraphTarget t : targets) { + t.setGraphValue(context.getViewPort(), value); + } resources.setConstant(in); } if (source != null) { @@ -58,7 +68,10 @@ protected void execute(FGRenderContext context) { @Override protected void reset(FGRenderContext context) {} @Override - protected void cleanup(FrameGraph frameGraph) {} + protected void cleanup(FrameGraph frameGraph) { + targets.clear(); + source = null; + } @Override public boolean isUsed() { return super.isUsed() || in.hasSource(); @@ -68,9 +81,30 @@ public T apply(Object t) { return value; } - public void setTarget(GraphTarget target) { - this.target = target; + /** + * Adds the graph target. + *

      + * If any targets are recieving from this Attribute, the incoming + * object will be marked as constant. + * + * @param target target to add (not null) + */ + public void addTarget(GraphTarget target) { + targets.add(target); + } + /** + * Removes the graph target. + * + * @param target target to remove (not null) + */ + public void removeTarget(GraphTarget target) { + targets.remove(target); } + /** + * Sets the graph source. + * + * @param source + */ public void setSource(GraphSource source) { this.source = source; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 6ee07471f3..9ed77e6134 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -22,7 +22,8 @@ import java.io.IOException; /** - * + * Renders a queue bucket to a set of color and depth textures. + * * @author codex */ public class BucketPass extends RenderPass { @@ -120,10 +121,20 @@ public void read(JmeImporter im) throws IOException { } } + /** + * Sets the depth range objects are rendered within. + * + * @param depth depth range (not null, unaffected) + */ public void setDepthRange(DepthRange depth) { this.depth.set(depth); } + /** + * Gets the depth range objects are rendered within. + * + * @return + */ public DepthRange getDepthRange() { return depth; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index da45720795..0a2d03788e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -16,7 +16,8 @@ import com.jme3.texture.Texture2D; /** - * + * Renders GBuffer information using deferred lighting to a color texture. + * * @author codex */ public class DeferredPass extends RenderPass { @@ -74,28 +75,5 @@ protected void execute(FGRenderContext context) { protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} - - public void setDepth(ResourceTicket depth) { - this.depth = depth; - } - public void setDiffuse(ResourceTicket diffuse) { - this.diffuse = diffuse; - } - public void setSpecular(ResourceTicket specular) { - this.specular = specular; - } - public void setEmissive(ResourceTicket emissive) { - this.emissive = emissive; - } - public void setNormal(ResourceTicket normal) { - this.normal = normal; - } - public void setLights(ResourceTicket lights) { - this.lights = lights; - } - - public ResourceTicket getOutColor() { - return outColor; - } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 19770f74be..e5607e52de 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -24,7 +24,11 @@ import java.util.function.Function; /** - * + * Renders diffuse, specular, emissive, normal, and depth information to a set of + * textures. + *

      + * Lights from rendered geometries are accumulated and exported. + * * @author codex */ public class GBufferPass extends RenderPass implements GeometryRenderHandler { @@ -33,8 +37,8 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private ResourceTicket diffuse, specular, emissive, normal, depth; private ResourceTicket lights; - private TextureDef[] texDefs = new TextureDef[5]; private ValueDef lightDef; + private final TextureDef[] texDefs = new TextureDef[5]; private final LinkedList accumulatedLights = new LinkedList<>(); private final ColorRGBA mask = new ColorRGBA(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 1cbc1d6757..2a6f2c6421 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -15,7 +15,11 @@ import java.io.IOException; /** - * + * Merges several inputs into one output by choosing one input to connect to + * the output using a controllable index. + *

      + * This pass does no rendering and cannot be culled. + * * @author codex * @param */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java index 8b075c07cb..7b2749b3ae 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java @@ -15,7 +15,8 @@ import java.io.IOException; /** - * + * Renders a queue bucket to the viewport's output framebuffer. + * * @author codex */ public class OutputBucketPass extends RenderPass { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java index efaffb573d..19e17fff2a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java @@ -8,10 +8,11 @@ import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.texture.Texture2D; -import java.util.Objects; /** - * + * Renders a set of color and depth textures on a fullscreen quad to the + * viewport's output framebuffer. + * * @author codex */ public class OutputPass extends RenderPass { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java index 7dcb7dfc24..004dd79c7d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java @@ -8,13 +8,15 @@ import com.jme3.profile.AppProfiler; import com.jme3.profile.SpStep; import com.jme3.profile.VpStep; -import com.jme3.renderer.RenderContext; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.util.SafeArrayList; /** - * + * Runs viewport post-processors. + *

      + * FilterPostProcessor is rendered to the viewport's output framebuffer. + * * @author codex */ public class PostProcessingPass extends RenderPass { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index a3ba1ca299..cb027ad692 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -22,7 +22,8 @@ import java.util.Objects; /** - * + * Performs rendering operations. + * * @author codex */ public abstract class RenderPass implements ResourceProducer, Savable { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index dc1e750a5a..bfb84b965f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java @@ -17,7 +17,8 @@ import com.jme3.texture.Texture2D; /** - * + * Renders GBuffer information using tiled deferred lighting to a color texture. + * * @author codex */ public class TileDeferredPass extends RenderPass { @@ -82,31 +83,5 @@ protected void execute(FGRenderContext context) { protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} - - public void setDiffuse(ResourceTicket diffuse) { - this.diffuse = diffuse; - } - public void setSpecular(ResourceTicket specular) { - this.specular = specular; - } - public void setEmissive(ResourceTicket emissive) { - this.emissive = emissive; - } - public void setNormal(ResourceTicket normal) { - this.normal = normal; - } - public void setDepth(ResourceTicket depth) { - this.depth = depth; - } - public void setLights(ResourceTicket lights) { - this.lights = lights; - } - public void setTiles(ResourceTicket tiles) { - this.tiles = tiles; - } - - public ResourceTicket getOutColor() { - return outColor; - } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Value.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Value.java deleted file mode 100644 index 2aa2855592..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Value.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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.passes; - -/** - * - * @author codex - */ -public class Value { - -} From 5505ab4bf9ae01ce5b5e15076ecb8e11ca27abe4 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 20 May 2024 21:26:59 -0400 Subject: [PATCH 065/111] licenses --- .../java/com/jme3/renderer/RenderManager.java | 2 +- .../jme3/renderer/framegraph/DepthRange.java | 31 ++++++++++++++++-- .../renderer/framegraph/FGRenderContext.java | 2 +- .../jme3/renderer/framegraph/FrameGraph.java | 31 ++++++++++++++++-- .../framegraph/FrameGraphFactory.java | 31 ++++++++++++++++-- .../renderer/framegraph/FullScreenQuad.java | 31 ++++++++++++++++-- .../renderer/framegraph/RenderObject.java | 31 ++++++++++++++++-- .../renderer/framegraph/RenderObjectMap.java | 32 +++++++++++++++++-- .../renderer/framegraph/RenderResource.java | 31 ++++++++++++++++-- .../renderer/framegraph/ResourceList.java | 31 ++++++++++++++++-- .../renderer/framegraph/ResourceProducer.java | 31 ++++++++++++++++-- .../renderer/framegraph/ResourceTicket.java | 31 ++++++++++++++++-- .../jme3/renderer/framegraph/TimeFrame.java | 31 ++++++++++++++++-- .../definitions/AbstractResourceDef.java | 31 ++++++++++++++++-- .../framegraph/definitions/ResourceDef.java | 31 ++++++++++++++++-- .../framegraph/definitions/TextureDef.java | 31 ++++++++++++++++-- .../framegraph/definitions/ValueDef.java | 31 ++++++++++++++++-- .../renderer/framegraph/io/GraphSource.java | 31 ++++++++++++++++-- .../renderer/framegraph/io/GraphTarget.java | 31 ++++++++++++++++-- .../framegraph/io/MatParamTargetControl.java | 31 ++++++++++++++++-- .../renderer/framegraph/passes/Attribute.java | 31 ++++++++++++++++-- .../framegraph/passes/BucketPass.java | 31 ++++++++++++++++-- .../framegraph/passes/DeferredPass.java | 31 ++++++++++++++++-- .../framegraph/passes/GBufferPass.java | 31 ++++++++++++++++-- .../renderer/framegraph/passes/Junction.java | 31 ++++++++++++++++-- .../framegraph/passes/OutputBucketPass.java | 31 ++++++++++++++++-- .../framegraph/passes/OutputPass.java | 31 ++++++++++++++++-- .../framegraph/passes/PostProcessingPass.java | 31 ++++++++++++++++-- .../framegraph/passes/RenderPass.java | 31 ++++++++++++++++-- .../framegraph/passes/TileDeferredPass.java | 31 ++++++++++++++++-- 30 files changed, 814 insertions(+), 59 deletions(-) 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 b8768ce8f5..f715aa8727 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2021 jMonkeyEngine + * Copyright (c) 2024 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without 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 index a7d55eb027..8536f509dc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.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) 2024 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 9f4f49a569..03e305e8f1 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,5 +1,5 @@ /* - * Copyright (c) 2009-2023 jMonkeyEngine + * Copyright (c) 2024 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without 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 593cf03a98..fb17d376d9 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,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) 2024 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/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index a5beee8507..c07df43a6d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.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) 2024 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/FullScreenQuad.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java index acaed31998..90e6d339bf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.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) 2024 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/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java index 1a328f052e..a6e87135da 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.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) 2024 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/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index eeecabef1d..bf2d6d3a93 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -1,13 +1,39 @@ /* - * 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) 2024 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.framegraph.definitions.ResourceDef; import java.util.HashMap; import java.util.Iterator; -import java.util.logging.Logger; /** * Manages creation, reallocation, and disposal of {@link RenderObject}s. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 811c69be87..20394aebba 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.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) 2024 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/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 68fcd47135..db5b29d471 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.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) 2024 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/ResourceProducer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java index 693e30b9e9..d9ffb49938 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java @@ -1,6 +1,33 @@ /* - * 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 + * Copyright (c) 2024 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/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index 5921c064ba..fc8047d504 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.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) 2024 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/TimeFrame.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java index f1cf9e0723..206b1a34bc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.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) 2024 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/definitions/AbstractResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java index 8fd92c5e71..863a162018 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.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) 2024 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.definitions; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index 9a3f7a126b..43712233af 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.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) 2024 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.definitions; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 462adec559..e061653384 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.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) 2024 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.definitions; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java index 0ac0945014..b75b10b825 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ValueDef.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) 2024 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.definitions; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java index 96f6abff17..cbf6cd46fa 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.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) 2024 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.io; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java index 7ee56ead85..9b8d0fa6ed 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java @@ -1,6 +1,33 @@ /* - * 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 + * Copyright (c) 2024 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.io; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java index 0485226d83..42221501d8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.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) 2024 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.io; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index 105a0ca6c8..d12a7d1a0d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.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) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 9ed77e6134..8e7a72c89e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.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) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 0a2d03788e..06988147d1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.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) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index e5607e52de..4a4ea1bd34 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.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) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 2a6f2c6421..a3a77dce2a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.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) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java index 7b2749b3ae..c34a32ef32 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.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) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java index 19e17fff2a..1b6b7fe851 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.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) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java index 004dd79c7d..3475a2e847 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.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) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index cb027ad692..e97c44b672 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -1,6 +1,33 @@ /* - * 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 + * Copyright (c) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index bfb84b965f..71b4a6f511 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.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) 2024 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.passes; From 1952784021e1d7be69608cd7dc1d26caf69d0b87 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 20 May 2024 21:59:40 -0400 Subject: [PATCH 066/111] pass tests --- .../renderer/framegraph/ResourceList.java | 1 - .../framegraph/definitions/TextureDef.java | 1 - .../renderpath/TestDeferredPBRShading.java | 4 +- .../renderpath/TestDeferredShading.java | 7 +- .../TestDeferredShadingPathShadow.java | 34 +----- .../TestPBRTerrainAdvancedRenderPath.java | 6 +- .../renderpath/TestPBRTerrainRenderPath.java | 12 +- .../renderpath/TestRenderPathChanged.java | 110 ------------------ ...thPointDirectionalAndSpotLightShadows.java | 7 +- .../jme3test/renderpath/TestShadingModel.java | 2 +- .../TestSimpleDeferredLighting.java | 55 ++++----- .../TestTileBasedDeferredShading.java | 6 +- .../MatDefs/Terrain/AdvancedPBRTerrain.j3md | 5 +- .../Common/MatDefs/Terrain/PBRTerrain.j3md | 4 +- .../Common/MatDefs/Terrain/Terrain.j3md | 6 +- 15 files changed, 58 insertions(+), 202 deletions(-) delete mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index db5b29d471..9698f7438f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -380,7 +380,6 @@ public T acquireDepthTarget(FrameBuffer fbo, ResourceTicket< FrameBuffer.RenderBuffer target = fbo.getDepthTarget(); boolean nullTarget = target == null; boolean unequalTargets = target != null && acquired != target.getTexture(); - System.out.println("null? "+nullTarget+" unequal? "+unequalTargets); if (nullTarget || unequalTargets) { fbo.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(acquired)); textureBinds++; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index e061653384..69ef0370a5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -137,7 +137,6 @@ public Consumer getDisposalMethod() { } @Override public void accept(T t) { - System.out.println("dispose texture"); t.getImage().dispose(); } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java index 7319da19df..995253a382 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java @@ -18,7 +18,7 @@ import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; -import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; @@ -39,6 +39,8 @@ public class TestDeferredPBRShading extends SimpleApplication { @Override public void simpleInitApp() { + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, false)); + roughness = 1.0f; assetManager.registerLoader(KTXLoader.class, "ktx"); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java index a87cc65396..3636b859b5 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java @@ -9,7 +9,7 @@ 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.renderer.framegraph.FrameGraphFactory; import com.jme3.scene.Geometry; import com.jme3.scene.instancing.InstancedNode; import com.jme3.scene.shape.Quad; @@ -23,7 +23,10 @@ public class TestDeferredShading extends SimpleApplication { private Material material; @Override public void simpleInitApp() { - // Test Forward↓ + + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, false)); + + // Test Forward // renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); // renderManager.setSinglePassLightBatchSize(30); // renderManager.setRenderPath(RenderManager.RenderPath.Forward); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java index 0543744315..e79451103b 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java @@ -11,7 +11,7 @@ import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.RenderPipelineFactory; +import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; @@ -23,22 +23,12 @@ * @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() { - renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Forward)); + //renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Forward)); + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, true)); Material boxMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); @@ -89,10 +79,6 @@ public void simpleInitApp() { inputManager.addListener(this, "toggleRenderPath"); inputManager.addMapping("toggleRenderPath", new KeyTrigger(KeyInput.KEY_SPACE)); - currentRenderPath = RenderManager.RenderPath.Forward; - //renderManager.setRenderPath(currentRenderPath); - makeHudText(); - flyCam.setMoveSpeed(20.0f); } @@ -103,18 +89,6 @@ public static void main(String[] args) { @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/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java index cef7e99f9b..7714f86422 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java @@ -43,8 +43,7 @@ import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.RenderPipelineFactory; +import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.shader.VarType; import com.jme3.terrain.geomipmap.TerrainLodControl; import com.jme3.terrain.geomipmap.TerrainQuad; @@ -196,7 +195,8 @@ public void onAction(String name, boolean pressed, float tpf) { @Override public void simpleInitApp() { - renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, true)); + //renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); //renderManager.setRenderPath(RenderManager.RenderPath.TiledDeferred); setupKeys(); setUpTerrain(); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java index d2f2cd73e4..6eb1846fb3 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java @@ -48,9 +48,7 @@ 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.renderer.framegraph.FrameGraphFactory; import com.jme3.system.AppSettings; import com.jme3.terrain.geomipmap.TerrainLodControl; import com.jme3.terrain.geomipmap.TerrainQuad; @@ -132,8 +130,8 @@ public static void main(String[] args) { 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.setWidth(768); + appSettings.setHeight(768); appSettings.setVSync(false); app.setSettings(appSettings); app.showSettings = false; @@ -197,6 +195,10 @@ else if(name.equals("addPointLight") && !pressed){ @Override public void simpleInitApp() { + + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, true)); + flyCam.setDragToRotate(true); + // For this scene, use a tileSize=64 configuration (at 1600*900 resolution) //renderManager.setForceTileSize(64);// 1600 * 900 resolution config setupKeys(); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java deleted file mode 100644 index 0eb7876387..0000000000 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java +++ /dev/null @@ -1,110 +0,0 @@ -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/TestRenderPathPointDirectionalAndSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java index 393ba498a3..05e6fb9a70 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java @@ -41,8 +41,8 @@ import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; -import com.jme3.renderer.framegraph.DeferredGraphConstructor; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Node; @@ -67,8 +67,9 @@ public static void main(String[] args) { @Override public void simpleInitApp() { - FrameGraph graph = new FrameGraph(assetManager, renderManager); - graph.setConstructor(new DeferredGraphConstructor()); + //FrameGraph graph = new FrameGraph(assetManager, renderManager); + //graph.setConstructor(new DeferredGraphConstructor()); + FrameGraph graph = FrameGraphFactory.deferred(assetManager, renderManager, false); viewPort.setFrameGraph(graph); //renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index 9f51adc84e..876b32b1b6 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -69,7 +69,7 @@ public void simpleInitApp() { inputManager.setCursorVisible(true); //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - graph = FrameGraphFactory.deferred(assetManager, renderManager, true); + graph = FrameGraphFactory.deferred(assetManager, renderManager, false); //graph.setConstructor(new ForwardGraphConstructor()); //graph.setConstructor(new TestConstructor()); //MyFrameGraph graph = RenderPipelineFactory.createBackroundScreenTest(assetManager, renderManager); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 41ed76856b..9ea91533ad 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -33,6 +33,7 @@ package jme3test.renderpath; import com.jme3.app.ChaseCameraAppState; +import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; import com.jme3.asset.TextureKey; import com.jme3.environment.EnvironmentCamera; @@ -48,15 +49,12 @@ import com.jme3.input.controls.KeyTrigger; import com.jme3.light.*; import com.jme3.material.Material; -import com.jme3.material.RenderState; import com.jme3.math.*; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.parameters.MatRenderParam; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.RenderPipelineFactory; -import com.jme3.renderer.framegraph.pass.GBufferModule; +import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -65,7 +63,6 @@ import com.jme3.scene.instancing.InstancedGeometry; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; -import com.jme3.shader.VarType; import com.jme3.shadow.DirectionalLightShadowFilter; import com.jme3.system.AppSettings; import com.jme3.texture.Texture; @@ -75,7 +72,7 @@ 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; @@ -106,7 +103,9 @@ public class TestSimpleDeferredLighting extends SimpleApplication implements Act public static void main(String[] args){ TestSimpleDeferredLighting app = new TestSimpleDeferredLighting(); AppSettings appSettings = new AppSettings(true); - appSettings.setRenderer(AppSettings.LWJGL_OPENGL40); + //appSettings.setRenderer(AppSettings.LWJGL_OPENGL40); + appSettings.setWidth(768); + appSettings.setHeight(768); app.setSettings(appSettings); app.start(); } @@ -655,8 +654,13 @@ private void testScene11(){ @Override public void simpleInitApp() { - FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - renderManager.setFrameGraph(graph); + + stateManager.attach(new DetailedProfilerState()); + + //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); + FrameGraph graph = FrameGraphFactory.deferred(assetManager, renderManager, true); + //FrameGraph graph = FrameGraphFactory.forward(assetManager, renderManager); + viewPort.setFrameGraph(graph); Geometry debugView = new Geometry("debug", new Quad(200, 200)); debugView.setLocalTranslation(0, 200, 0); @@ -664,17 +668,16 @@ public void simpleInitApp() { //debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); //debugMat.setTransparent(true); debugView.setMaterial(debugMat); - MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); + //MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); //texParam.enableDebug(); - graph.bindToOutput(GBufferModule.RENDER_TARGETS[1], texParam); - guiNode.attachChild(debugView); + //graph.bindToOutput(GBufferModule.RENDER_TARGETS[1], texParam); + //guiNode.attachChild(debugView); - currentRenderPath = RenderManager.RenderPath.ForwardPlus; //renderManager.setRenderPath(currentRenderPath); - testScene7(); + testScene10(); // cam.setFrustumPerspective(45.0f, 4.0f / 3.0f, 0.01f, 100.0f); flyCam.setMoveSpeed(10.0f); - // deferred下闪烁 + // deferred // testScene7(); @@ -684,20 +687,12 @@ public void simpleInitApp() { setPauseOnLostFocus(false); flyCam.setDragToRotate(true); flyCam.setMoveSpeed(50.0f); + + viewPort.setBackgroundColor(ColorRGBA.DarkGray); - 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"); @@ -762,18 +757,8 @@ public void onAction(String name, boolean isPressed, float tpf) { //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){ diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java index f51ead680b..e77fedf9a0 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java @@ -3,14 +3,13 @@ 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.BloomFilter; import com.jme3.post.filters.ToneMapFilter; -import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.scene.Geometry; import com.jme3.scene.instancing.InstancedNode; import com.jme3.scene.shape.Quad; @@ -25,6 +24,9 @@ public class TestTileBasedDeferredShading extends SimpleApplication { private Material material; @Override public void simpleInitApp() { + + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, true)); + // 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); 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 78d2f837c3..04f37b4daf 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md @@ -350,10 +350,11 @@ MaterialDef Advanced PBR Terrain { } } - Technique GBufferPass{ - Pipeline Deferred + Technique GBufferPass { + VertexShader GLSL300 GLSL150 : Common/MatDefs/Terrain/PBRTerrain.vert FragmentShader GLSL300 GLSL150 : Common/MatDefs/Terrain/GBufferPack/AdvancedPBRTerrainGBufferPack.frag + WorldParameters { WorldViewProjectionMatrix CameraPosition 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 43fe8755fb..fb1197fcdf 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.j3md +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.j3md @@ -328,9 +328,7 @@ MaterialDef PBR Terrain { } } - Technique GBufferPass{ - - Pipeline Deferred + Technique GBufferPass { VertexShader GLSL300 GLSL150 GLSL130 GLSL100: Common/MatDefs/Terrain/PBRTerrain.vert FragmentShader GLSL300 GLSL150 GLSL130 GLSL100: Common/MatDefs/Terrain/GBufferPack/PBRTerrainGBufferPack.frag 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 4841cd8105..d4696cd1e1 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/Terrain.j3md +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/Terrain.j3md @@ -36,8 +36,8 @@ MaterialDef Terrain { } } - Technique GBufferPass{ - Pipeline Deferred + Technique GBufferPass { + VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/Terrain.vert FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/GBufferPack/TerrainGBufferPack.frag @@ -66,4 +66,4 @@ MaterialDef Terrain { Technique { } -} \ No newline at end of file +} From 5e6fe7ab40c8066897ed288bcb337deb986c9207 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 21 May 2024 07:44:50 -0400 Subject: [PATCH 067/111] added framegraph opt-out for viewports --- .../java/com/jme3/app/LegacyApplication.java | 3 +- .../java/com/jme3/renderer/RenderManager.java | 9 ++-- .../main/java/com/jme3/renderer/ViewPort.java | 42 ++++++++++++++++++- .../renderer/framegraph/RenderObjectMap.java | 33 ++++++++++----- .../renderer/framegraph/ResourceList.java | 37 ++++++++++++++++ 5 files changed, 109 insertions(+), 15 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java b/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java index ef2a550ee9..3ad319052e 100644 --- a/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java +++ b/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2022 jMonkeyEngine + * Copyright (c) 2024 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -336,6 +336,7 @@ private void initCamera() { Camera guiCam = new Camera(settings.getWidth(), settings.getHeight()); guiViewPort = renderManager.createPostView("Gui Default", guiCam); guiViewPort.setClearFlags(false, false, false); + guiViewPort.setUseFrameGraphs(false); } /** 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 f715aa8727..812504a368 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -1260,9 +1260,12 @@ public void renderViewPort(ViewPort vp, float tpf) { processors = null; } - FrameGraph fg = vp.getFrameGraph(); - if (fg == null) { - fg = frameGraph; + FrameGraph fg = null; + if (vp.isUseFrameGraphs()) { + fg = vp.getFrameGraph(); + if (fg == null) { + fg = frameGraph; + } } if (prof != null && (fg != null || processors != null)) { 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 4fdc167357..dbb2bb6bb2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java +++ b/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2021 jMonkeyEngine + * Copyright (c) 2024 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -111,6 +111,7 @@ public class ViewPort { */ protected boolean clearStencil = false; private boolean enabled = true; + private boolean useFrameGraphs = true; /** * Creates a new viewport. User code should generally use these methods instead:
      @@ -430,12 +431,51 @@ public boolean isEnabled() { return enabled; } + /** + * Sets the framegraph used by this viewport for rendering. + *

      + * If null, the render manager's default framegraph, if not null, will be + * used to render this viewport. If all else fails, the default forward + * renderer will be used. + *

      + * default=null + * + * @param framegraph framegraph, or null + */ public void setFrameGraph(FrameGraph framegraph) { this.framegraph = framegraph; } + /** + * Gets the framegraph used by this viewport for rendering. + * + * @return + */ public FrameGraph getFrameGraph() { return framegraph; } + + /** + * Enables this viewport to use framegraphs when rendering. + *

      + * If false, the default forward renderer will always be used to + * render this viewport. + *

      + * default=true + * + * @param useFrameGraphs + */ + public void setUseFrameGraphs(boolean useFrameGraphs) { + this.useFrameGraphs = useFrameGraphs; + } + + /** + * Returns true if framegraphs can be used to render this viewport. + * + * @return + */ + public boolean isUseFrameGraphs() { + return useFrameGraphs; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index bf2d6d3a93..b7738650f1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -53,27 +53,40 @@ public class RenderObjectMap { private int totalObjects = 0; private int flushedObjects = 0; + public RenderObjectMap() {} + + /** + * Creates a new render object with a new internal object. + * + * @param + * @param def + * @return + */ protected RenderObject create(ResourceDef def) { return create(def, def.createResource()); } + /** + * Creates a new render object with the given internal object. + * + * @param + * @param def + * @param value internal object + * @return + */ protected RenderObject create(ResourceDef def, T value) { RenderObject obj = new RenderObject(def, value, timeout); objectMap.put(obj.getId(), obj); return obj; } + /** + * Returns true if the render object is available for reallocation. + * + * @param object + * @return + */ protected boolean isAvailable(RenderObject object) { return !object.isAcquired() && !object.isConstant(); } - protected boolean applyDirectResource(RenderResource resource, RenderObject object) { - if (!object.isAcquired() && !object.isConstant()) { - T r = resource.getDefinition().applyDirectResource(object.getObject()); - if (r != null) { - resource.setObject(object, r); - return true; - } - } - return false; - } /** * Allocates a render object to the resource. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 9698f7438f..2eb3eda5a3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -55,11 +55,30 @@ public ResourceList(RenderObjectMap map) { this.map = map; } + /** + * Creates and adds a new render resource. + * + * @param + * @param producer + * @param def + * @return new render resource + */ protected RenderResource create(ResourceProducer producer, ResourceDef def) { RenderResource res = new RenderResource<>(producer, def, new ResourceTicket<>()); res.getTicket().setLocalIndex(add(res)); return res; } + /** + * Locates the resource associated with the ticket. + * + * @param + * @param ticket ticket to locate with (not null) + * @return located resource + * @throws NullPointerException if ticket is null + * @throws NullPointerException if ticket's world index is negative + * @throws NullPointerException if ticket points to a null resource + * @throws IndexOutOfBoundsException if ticket's world index is >= size + */ protected RenderResource locate(ResourceTicket ticket) { if (ticket == null) { throw new NullPointerException("Ticket cannot be null."); @@ -77,9 +96,21 @@ protected RenderResource locate(ResourceTicket ticket) { } throw new IndexOutOfBoundsException(ticket+" is out of bounds for size "+resources.size()); } + /** + * Returns true if the ticket can be used to locate a resource. + * + * @param ticket + * @return + */ protected boolean validate(ResourceTicket ticket) { return ticket != null && ticket.getWorldIndex() >= 0; } + /** + * Adds the resource to the first available slot. + * + * @param res + * @return + */ protected int add(RenderResource res) { assert res != null; if (nextSlot >= resources.size()) { @@ -101,6 +132,12 @@ protected int add(RenderResource res) { return i; } } + /** + * Removes the resource at the index. + * + * @param index + * @return + */ protected RenderResource remove(int index) { RenderResource prev = resources.set(index, null); if (prev != null && prev.isReferenced()) { From f16977aafda558da13958c976f06e56021950d83 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 21 May 2024 11:58:50 -0400 Subject: [PATCH 068/111] added .j3g --- .../java/com/jme3/asset/AssetManager.java | 19 ++ .../com/jme3/asset/DesktopAssetManager.java | 11 + .../java/com/jme3/asset/FrameGraphKey.java | 28 ++ .../jme3/renderer/framegraph/FrameGraph.java | 104 ++++-- .../renderer/framegraph/FrameGraphData.java | 166 ++++++++++ .../renderer/framegraph/ResourceTicket.java | 16 + .../framegraph/SavablePassConnection.java | 153 +++++++++ .../framegraph/passes/OutputBucketPass.java | 5 + .../framegraph/passes/RenderPass.java | 300 +++++++++++++++++- .../resources/Common/FrameGraphs/Deferred.j3g | Bin 0 -> 1451 bytes .../resources/Common/FrameGraphs/Forward.j3g | Bin 0 -> 707 bytes .../Common/FrameGraphs/TiledDeferred.j3g | Bin 0 -> 1459 bytes .../main/resources/com/jme3/asset/General.cfg | 1 + .../TestFrameGraphImportExport.java | 112 +++++++ .../jme3test/renderpath/TestShadingModel.java | 36 ++- 15 files changed, 917 insertions(+), 34 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java create mode 100644 jme3-core/src/main/resources/Common/FrameGraphs/Deferred.j3g create mode 100644 jme3-core/src/main/resources/Common/FrameGraphs/Forward.j3g create mode 100644 jme3-core/src/main/resources/Common/FrameGraphs/TiledDeferred.j3g create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java diff --git a/jme3-core/src/main/java/com/jme3/asset/AssetManager.java b/jme3-core/src/main/java/com/jme3/asset/AssetManager.java index 73762a1234..58e488e132 100644 --- a/jme3-core/src/main/java/com/jme3/asset/AssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/AssetManager.java @@ -39,6 +39,7 @@ import com.jme3.material.Material; import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.Caps; +import com.jme3.renderer.framegraph.FrameGraphData; import com.jme3.scene.Spatial; import com.jme3.scene.plugins.OBJLoader; import com.jme3.shader.ShaderGenerator; @@ -364,6 +365,24 @@ public default List getClassLoaders() { */ public FilterPostProcessor loadFilter(String name); + /** + * Loads a framegraph *.j3g file with a FrameGraphKey. + * + * @param key asset key of the framegraph file to load + * @return loaded framegraph + * @see #loadAsset(com.jme3.asset.AssetKey) + */ + public FrameGraphData loadFrameGraph(FrameGraphKey key); + + /** + * Loads a framegraph *.j3g file with a FrameGraphKey. + * + * @param name asset name of the framegraph file to load + * @return loaded framegraph + * @see #loadAsset(com.jme3.asset.AssetKey) + */ + public FrameGraphData loadFrameGraph(String name); + /** * Sets the shaderGenerator to generate shaders based on shaderNodes. * @param generator the shaderGenerator diff --git a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java index a8ff73f2c4..fa508daffe 100644 --- a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java @@ -38,6 +38,7 @@ import com.jme3.material.Material; import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.Caps; +import com.jme3.renderer.framegraph.FrameGraphData; import com.jme3.scene.Spatial; import com.jme3.shader.Glsl100ShaderGenerator; import com.jme3.shader.Glsl150ShaderGenerator; @@ -455,6 +456,16 @@ public FilterPostProcessor loadFilter(FilterKey key) { public FilterPostProcessor loadFilter(String name) { return loadFilter(new FilterKey(name)); } + + @Override + public FrameGraphData loadFrameGraph(FrameGraphKey key) { + return loadAsset(key); + } + + @Override + public FrameGraphData loadFrameGraph(String name) { + return loadAsset(new FrameGraphKey(name)); + } /** * {@inheritDoc} diff --git a/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java b/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java new file mode 100644 index 0000000000..41c5cfbe7d --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.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.asset; + +import com.jme3.asset.cache.AssetCache; +import com.jme3.renderer.framegraph.FrameGraphData; + +/** + * + * @author codex + */ +public class FrameGraphKey extends AssetKey { + + public FrameGraphKey(String name) { + super(name); + } + public FrameGraphKey() { + super(); + } + + @Override + public Class getCacheType() { + return null; + } + +} 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 fb17d376d9..da0ad73557 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 @@ -33,18 +33,12 @@ import com.jme3.renderer.framegraph.passes.RenderPass; import com.jme3.asset.AssetManager; -import com.jme3.export.InputCapsule; -import com.jme3.export.JmeExporter; -import com.jme3.export.JmeImporter; -import com.jme3.export.OutputCapsule; -import com.jme3.export.Savable; +import com.jme3.asset.FrameGraphKey; import com.jme3.profile.AppProfiler; import com.jme3.profile.FgStep; import com.jme3.profile.VpStep; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; -import java.io.IOException; -import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; @@ -86,15 +80,17 @@ * * @author codex */ -public class FrameGraph implements Savable { +public class FrameGraph { private final AssetManager assetManager; private final ResourceList resources; private final FGRenderContext context; private final LinkedList passes = new LinkedList<>(); + private String name = "FrameGraph"; private boolean rendered = false; /** + * Creates a new blank framegraph. * * @param assetManager asset manager (not null) * @param renderManager render manager (not null) @@ -104,6 +100,37 @@ public FrameGraph(AssetManager assetManager, RenderManager renderManager) { this.resources = new ResourceList(renderManager.getRenderObjectMap()); this.context = new FGRenderContext(this, renderManager); } + /** + * Creates a new framegraph from the given data. + * + * @param assetManager + * @param renderManager + * @param data + */ + public FrameGraph(AssetManager assetManager, RenderManager renderManager, FrameGraphData data) { + this(assetManager, renderManager); + applyData(data); + } + /** + * Creates a new framegraph from data obtained by the given asset key. + * + * @param assetManager + * @param renderManager + * @param key + */ + public FrameGraph(AssetManager assetManager, RenderManager renderManager, FrameGraphKey key) { + this(assetManager, renderManager, assetManager.loadFrameGraph(key)); + } + /** + * Creates a new framegraph from data obtained by the given asset name. + * + * @param assetManager + * @param renderManager + * @param dataAsset + */ + public FrameGraph(AssetManager assetManager, RenderManager renderManager, String dataAsset) { + this(assetManager, renderManager, assetManager.loadFrameGraph(dataAsset)); + } /** * Configures the framegraph rendering context. @@ -358,6 +385,15 @@ public void clear() { passes.clear(); } + /** + * Sets the name of this framegraph. + * + * @param name + */ + public void setName(String name) { + this.name = name; + } + /** * * @return @@ -388,17 +424,49 @@ public FGRenderContext getContext() { public RenderManager getRenderManager() { return context.getRenderManager(); } - - @Override - public void write(JmeExporter ex) throws IOException { - OutputCapsule out = ex.getCapsule(this); - out.write(passes.toArray(RenderPass[]::new), "passes", new RenderPass[0]); + /** + * Gets the name of this framegraph. + * + * @return + */ + public String getName() { + return name; + } + + /** + * Applies the framegraph data to this framegraph. + * + * @param data + * @return this instance + */ + public final FrameGraph applyData(FrameGraphData data) { + data.apply(this); + return this; } - @Override - public void read(JmeImporter im) throws IOException { - InputCapsule in = im.getCapsule(this); - RenderPass[] array = (RenderPass[])in.readSavableArray("passes", new RenderPass[0]); - passes.addAll(Arrays.asList(array)); + /** + * Applies the framegraph data to this framegraph. + * + * @param data + * @return this instance + * @throws ClassCastException + * @throws NullPointerException + */ + public FrameGraph applyData(Object data) { + if (data != null && data instanceof FrameGraphData) { + return FrameGraph.this.applyData((FrameGraphData)data); + } else if (data != null) { + throw new ClassCastException(data.getClass()+" cannot be cast to "+FrameGraphData.class); + } else { + throw new NullPointerException("Proxy cannot be null"); + } + } + /** + * Creates exportable framegraph data. + * + * @return + */ + public FrameGraphData createData() { + return new FrameGraphData(this, passes); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java new file mode 100644 index 0000000000..7d06f936ab --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2024 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.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.renderer.framegraph.passes.RenderPass; +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; + +/** + * Holds framegraph data ready for import or export. + *

      + * Each individual data instance should only be affiliated with one framegraph. + * + * @author codex + */ +public class FrameGraphData implements Savable { + + private final boolean export; + private String name; + private RenderPass[] passes; + private SavablePassConnection[] connections; + + public FrameGraphData() { + export = false; + } + public FrameGraphData(FrameGraph fg, Collection passes) { + this.name = fg.getName(); + this.passes = passes.toArray(RenderPass[]::new); + export = true; + } + + @Override + public void write(JmeExporter ex) throws IOException { + if (!export) { + throw new IllegalStateException("Data is import only."); + } + if (passes == null) { + throw new IllegalStateException("Data is already consumed."); + } + final HashMap idMap = new HashMap<>(); + final LinkedList list = new LinkedList<>(); + int nextId = 0; + // remap ids + for (RenderPass p : passes) { + p.setExportId(nextId++); + idMap.put(p.getId(), p.getExportId()); + } + // extract connections + for (RenderPass p : passes) for (ResourceTicket t : p.getInputTickets()) { + if (t.hasSource()) { + int outId = idMap.get(t.getSource().getPassId()); + list.add(new SavablePassConnection(p.getExportId(), outId, t.getName(), t.getSource().getName())); + } + } + OutputCapsule out = ex.getCapsule(this); + out.write(name, "name", "FrameGraph"); + out.write(passes, "passes", new RenderPass[0]); + out.write(list.toArray(SavablePassConnection[]::new), "connections", new SavablePassConnection[0]); + // reset export ids + for (RenderPass p : passes) { + p.setExportId(-1); + } + idMap.clear(); + list.clear(); + passes = null; + } + @Override + public void read(JmeImporter im) throws IOException { + if (export) { + throw new IllegalStateException("Data is export only."); + } + InputCapsule in = im.getCapsule(this); + name = in.readString("name", "FrameGraph"); + int baseId = RenderPass.getNextId(); + Savable[] array = in.readSavableArray("passes", new RenderPass[0]); + passes = new RenderPass[array.length]; + for (int i = 0; i < array.length; i++) { + RenderPass p = passes[i] = (RenderPass)array[i]; + p.shiftId(baseId); + } + array = in.readSavableArray("connections", new SavablePassConnection[0]); + connections = new SavablePassConnection[array.length]; + for (int i = 0; i < array.length; i++) { + SavablePassConnection c = connections[i] = (SavablePassConnection)array[i]; + c.shiftIds(baseId); + } + } + + /** + * Applies internal data to the framegraph. + *

      + * This operation consumes the data. + * + * @param fg + */ + public void apply(FrameGraph fg) { + if (export) { + throw new IllegalStateException("Data is export only."); + } + if (passes == null) { + throw new IllegalStateException("Data has already been consumed."); + } + fg.setName(name); + for (RenderPass p : passes) { + fg.add(p); + } + // cache passes by id + HashMap cache = new HashMap<>(); + for (RenderPass p : passes) { + cache.put(p.getId(), p); + } + // read connections + for (SavablePassConnection c : connections) { + RenderPass input = cache.get(c.getInputId()); + RenderPass output = cache.get(c.getOutputId()); + input.makeInput(output, c.getOutputTicket(), c.getInputTicket()); + } + cache.clear(); + passes = null; + connections = null; + } + + public boolean isExportOnly() { + return export; + } + public boolean isConsumed() { + return passes == null; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index fc8047d504..0148f52f29 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -46,6 +46,7 @@ public class ResourceTicket { private String name; + private int passId = -1; private int localIndex; private long objectId = -1; private ResourceTicket source; @@ -127,6 +128,14 @@ public ResourceTicket setName(String name) { this.name = name; return this; } + /** + * Sets the id of this pass this ticket belongs to. + * + * @param passId + */ + public void setPassId(int passId) { + this.passId = passId; + } /** * Sets the local index. *

      @@ -156,6 +165,13 @@ public void setObjectId(long objectId) { public String getName() { return name; } + /** + * + * @return + */ + public int getPassId() { + return passId; + } /** * Gets the world index. *

      diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java new file mode 100644 index 0000000000..ba6ec2b958 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2024 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.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import java.io.IOException; + +/** + * Represents an abstract connection between render passes. + * + * @author codex + */ +public class SavablePassConnection implements Savable { + + private int inputId, outputId; + private String inputTicket, outputTicket; + + /** + * + */ + public SavablePassConnection() {} + /** + * + * @param inputId + * @param outputId + * @param inputTicket + * @param outputTicket + */ + public SavablePassConnection(int inputId, int outputId, String inputTicket, String outputTicket) { + this.inputId = inputId; + this.outputId = outputId; + this.inputTicket = inputTicket; + this.outputTicket = outputTicket; + } + + /** + * + * @param shift + */ + public void shiftIds(long shift) { + inputId += shift; + outputId += shift; + } + + /** + * + * @param inputId + */ + public void setInputId(int inputId) { + this.inputId = inputId; + } + /** + * + * @param outputId + */ + public void setOutputId(int outputId) { + this.outputId = outputId; + } + /** + * + * @param inputTicket + */ + public void setInputTicket(String inputTicket) { + this.inputTicket = inputTicket; + } + /** + * + * @param outputTicket + */ + public void setOutputTicket(String outputTicket) { + this.outputTicket = outputTicket; + } + + /** + * + * @return + */ + public int getInputId() { + return inputId; + } + /** + * + * @return + */ + public int getOutputId() { + return outputId; + } + /** + * + * @return + */ + public String getInputTicket() { + return inputTicket; + } + /** + * + * @return + */ + public String getOutputTicket() { + return outputTicket; + } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(inputId, "inputId", -1); + out.write(outputId, "outputId", -1); + out.write(inputTicket, "inputTicket", ""); + out.write(outputTicket, "outputTicket", ""); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + inputId = in.readInt("inputId", -1); + outputId = in.readInt("outputId", -1); + inputTicket = in.readString("inputTicket", ""); + outputTicket = in.readString("outputTicket", ""); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java index c34a32ef32..b08a7ea421 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java @@ -51,6 +51,9 @@ public class OutputBucketPass extends RenderPass { private Bucket bucket; private DepthRange depth; + public OutputBucketPass() { + this(Bucket.Opaque, DepthRange.IDENTITY); + } public OutputBucketPass(Bucket bucket) { this(bucket, DepthRange.IDENTITY); } @@ -95,12 +98,14 @@ public String getProfilerName() { public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule out = ex.getCapsule(this); + out.write(bucket, "bucket", Bucket.Opaque); out.write(depth, "depth", DepthRange.IDENTITY); } @Override public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule in = im.getCapsule(this); + bucket = in.readEnum("bucket", Bucket.class, Bucket.Opaque); depth = in.readSavable("depth", DepthRange.class, DepthRange.IDENTITY); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index e97c44b672..7bcefa7934 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -49,7 +49,7 @@ import java.util.Objects; /** - * Performs rendering operations. + * Performs rendering operations for a framegraph. * * @author codex */ @@ -58,6 +58,7 @@ public abstract class RenderPass implements ResourceProducer, Savable { private static int nextId = 0; private int id = nextId++; + private int exportId = -1; private String name; private int index = -1; private int refs = 0; @@ -66,6 +67,12 @@ public abstract class RenderPass implements ResourceProducer, Savable { private final LinkedList frameBuffers = new LinkedList<>(); protected ResourceList resources; + /** + * Initializes the pass to the framegraph. + * + * @param frameGraph + * @param index execution index + */ public void initializePass(FrameGraph frameGraph, int index) { this.index = index; this.resources = frameGraph.getResources(); @@ -74,35 +81,95 @@ public void initializePass(FrameGraph frameGraph, int index) { } initialize(frameGraph); } + /** + * Prepares the pass for rendering. + * + * @param context + */ public void prepareRender(FGRenderContext context) { if (index < 0) { throw new IllegalStateException("Pass is not properly initialized for rendering."); } prepare(context); } + /** + * Executes the pass. + * + * @param context + */ public void executeRender(FGRenderContext context) { execute(context); releaseAll(); } + /** + * Resets the pass from rendering. + * + * @param context + */ public void resetRender(FGRenderContext context) { reset(context); } + /** + * Cleans up the pass's participation in the framegraph. + * + * @param frameGraph + */ public void cleanupPass(FrameGraph frameGraph) { cleanup(frameGraph); for (ResourceTicket t : inputs) { t.setSource(null); + t.setPassId(-1); + } + for (ResourceTicket t : outputs) { + t.setPassId(-1); } inputs.clear(); outputs.clear(); index = -1; } + /** + * Initializes the pass. + *

      + * Tickets should be created add registered here. + * + * @param frameGraph + */ protected abstract void initialize(FrameGraph frameGraph); + /** + * Prepares the pass. + *

      + * Resource should be declared, referenced, and reserved here. + * + * @param context + */ protected abstract void prepare(FGRenderContext context); + /** + * Executes the pass. + *

      + * All declared and referenced resources should be acquired here. Resources + * must also be released, but that occurs automatically. + * + * @param context + */ protected abstract void execute(FGRenderContext context); + /** + * Resets the pass. + * + * @param context + */ protected abstract void reset(FGRenderContext context); + /** + * Cleans up the pass. + * + * @param frameGraph + */ protected abstract void cleanup(FrameGraph frameGraph); + /** + * Called when all rendering is complete in a rendering frame this pass + * participated in. + */ public void renderingComplete() { for (Iterator it = frameBuffers.iterator(); it.hasNext();) { PassFrameBuffer fb = it.next(); @@ -114,47 +181,100 @@ public void renderingComplete() { } } } + /** + * Called on the pre-rendering step. + * + * @param context + */ public void preFrame(FGRenderContext context) {} + /** + * Called after render queues have been assembled. + * + * @param context + */ public void postQueue(FGRenderContext context) {} - public void setPassProperty(String name, String value) throws Exception { - if (!setProperty(name, value)) switch (name) { - case "id": id = Integer.parseInt(value); break; - case "name": this.name = value; break; - } - } - protected boolean setProperty(String name, String value) throws Exception { - return false; - } - + /** + * Declares a new resource. + * + * @param + * @param def + * @param ticket ticket to store resulting index + * @return given ticket + */ protected ResourceTicket declare(ResourceDef def, ResourceTicket ticket) { return resources.declare(this, def, ticket); } + /** + * Declares a new resource that is locally used only. + * + * @param + * @param def + * @param ticket + * @return + */ protected ResourceTicket declareLocal(ResourceDef def, ResourceTicket ticket) { ticket = resources.declare(this, def, ticket); resources.setSurvivesReferenceCull(ticket); return ticket; } + /** + * Reserves the resource associated with the ticket. + * + * @param ticket + */ protected void reserve(ResourceTicket ticket) { resources.reserve(index, ticket); } + /** + * Reserves each resource associated with the tickets. + * + * @param tickets + */ protected void reserve(ResourceTicket... tickets) { resources.reserve(index, tickets); } + /** + * References the resource associated with the ticket. + * + * @param ticket + */ protected void reference(ResourceTicket ticket) { resources.reference(index, ticket); } + /** + * References each resource associated with the tickets. + * + * @param tickets + */ protected void reference(ResourceTicket... tickets) { resources.reference(index, tickets); } + /** + * References the resource associated with the ticket if the ticket is not + * null and contains a non-negative world index. + * + * @param ticket + * @return + */ protected boolean referenceOptional(ResourceTicket ticket) { return resources.referenceOptional(index, ticket); } + /** + * Optionally references each resource associated with the tickets. + * + * @param tickets + */ protected void referenceOptional(ResourceTicket... tickets) { for (ResourceTicket t : tickets) { referenceOptional(t); } } + /** + * Releases all reasources associated with any registered ticket. + *

      + * Called automatically. + */ protected void releaseAll() { for (ResourceTicket t : inputs) { resources.releaseOptional(t); @@ -164,20 +284,56 @@ protected void releaseAll() { } } + /** + * Adds the ticket as input. + * + * @param + * @param input + * @return given ticket + */ protected ResourceTicket addInput(ResourceTicket input) { inputs.add(input); + input.setPassId(id); return input; } + /** + * Adds the ticket as output. + * + * @param + * @param output + * @return given ticket + */ protected ResourceTicket addOutput(ResourceTicket output) { outputs.add(output); + output.setPassId(id); return output; } + /** + * Creates and registers a new ticket as input. + * + * @param + * @param name + * @return created ticket + */ protected ResourceTicket addInput(String name) { return addInput(new ResourceTicket<>(name)); } + /** + * Creates and registers a new ticket as output. + * + * @param + * @param name + * @return created ticket + */ protected ResourceTicket addOutput(String name) { return addOutput(new ResourceTicket<>(name)); } + /** + * Gets the named input ticket, or null if none exists. + * + * @param name + * @return + */ protected ResourceTicket getInputByName(String name) { for (ResourceTicket t : inputs) { if (name.equals(t.getName())) { @@ -186,6 +342,12 @@ protected ResourceTicket getInputByName(String name) { } return null; } + /** + * Gets the named output ticket, or null if none exists. + * + * @param name + * @return + */ protected ResourceTicket getOutputByName(String name) { for (ResourceTicket t : outputs) { if (name.equals(t.getName())) { @@ -194,11 +356,24 @@ protected ResourceTicket getOutputByName(String name) { } return null; } + /** + * Makes the named output ticket belonging to the given pass the source of + * the named input ticket belonging to this pass. + * + * @param pass + * @param outTicket + * @param inTicket + */ public void makeInput(RenderPass pass, String outTicket, String inTicket) { ResourceTicket out = Objects.requireNonNull(pass.getOutputByName(outTicket)); ResourceTicket in = Objects.requireNonNull(getInputByName(inTicket)); in.setSource(out); } + /** + * Nullifies all sources belonging to the given pass. + * + * @param pass + */ public void disconnectFrom(RenderPass pass) { for (ResourceTicket in : inputs) { if (pass.getOutputTickets().contains(in.getSource())) { @@ -207,6 +382,17 @@ public void disconnectFrom(RenderPass pass) { } } + /** + * Gets an existing framebuffer that matches the given properties. + *

      + * If no existing framebuffer matches, a new framebuffer will be created + * and returned. + * + * @param width + * @param height + * @param samples + * @return + */ protected FrameBuffer getFrameBuffer(int width, int height, int samples) { for (PassFrameBuffer fb : frameBuffers) { if (fb.qualifies(width, height, samples)) { @@ -217,34 +403,115 @@ protected FrameBuffer getFrameBuffer(int width, int height, int samples) { frameBuffers.add(fb); return fb.use(); } + /** + * Gets an existing framebuffer that matches the context. + *

      + * If no existing framebuffer matches, a new framebuffer will be created + * and returned. + * + * @param context + * @param samples + * @return + */ protected FrameBuffer getFrameBuffer(FGRenderContext context, int samples) { return getFrameBuffer(context.getWidth(), context.getHeight(), samples); } + /** + * Counts the number of potential references to this pass. + *

      + * Called automatically. Do not use. + */ public void countReferences() { refs = outputs.size(); } + /** + * Shifts the execution index if this pass's index is greater than the + * specified threshold. + *

      + * Called automatically. Do not use. + * + * @param threshold + * @param positive + */ public void shiftExecutionIndex(int threshold, boolean positive) { if (index > threshold) { index += (positive ? 1 : -1); } } + /** + * Shifts the id of this pass. + *

      + * Called automatically. Do not use. + * + * @param shift + */ + public void shiftId(long shift) { + id += shift; + } + /** + * Sets the name of this pass. + * + * @param name + */ public void setName(String name) { this.name = name; } + /** + * Sets the id of this pass. + *

      + * Called automatically. Do not use. + * + * @param id + */ public void setId(int id) { this.id = id; } + /** + * Sets the id used when exporting. + *

      + * Called automatically. Do not use. + * + * @param id + */ + public void setExportId(int id) { + this.exportId = id; + } + /** + * + * @return + */ public String getName() { return name; } + /** + * Gets the name used for profiling. + * + * @return + */ public String getProfilerName() { return getName(); } + /** + * + * @return + */ public int getId() { return id; } + /** + * + * @return + */ + public int getExportId() { + return exportId; + } + /** + * Returns true if this pass is assigned to a framegraph. + * + * @return + */ public boolean isAssigned() { return index >= 0; } @@ -277,7 +544,7 @@ public String toString() { @Override public void write(JmeExporter ex) throws IOException { OutputCapsule out = ex.getCapsule(this); - out.write(id, "id", -1); + out.write((exportId >= 0 ? exportId : id), "id", -1); out.write(name, "name", "RenderPass"); } @Override @@ -287,8 +554,13 @@ public void read(JmeImporter im) throws IOException { name = in.readString("name", "RenderPass"); } - public static void setNextId(int id) { - nextId = id; + /** + * Gets the next generated id. + * + * @return + */ + public static int getNextId() { + return nextId; } private static class PassFrameBuffer { diff --git a/jme3-core/src/main/resources/Common/FrameGraphs/Deferred.j3g b/jme3-core/src/main/resources/Common/FrameGraphs/Deferred.j3g new file mode 100644 index 0000000000000000000000000000000000000000..f3cbfe401942962865dc32b02b200c9d0324e557 GIT binary patch literal 1451 zcma)6$!^n76!o>^p>f)#DWh1hL9nP~5Jj*AwP~XwhCnJI!Rpn1NlYEv@=%E#e*kNK zf{$Ryhp^@kIM+kuk|v6!<8%G)^SP6sU%o!tR}@79EF#?b+H<3s^LZxsokWJ7Ol0DW z6ETyMM8s3)n9Tv3eUS-lSCvn=8?i`JnG)N!8-<~CGd~JbRmDPmJzS|=Dma6Kd_0!P z5PEn|rDNP%A%ZGxe)c`BDfws}$-abOBE99BW>fR&I-0{M&4x+j$~5)E$#P|@ZtLTf zsv~hB&H~9ghx6`n2`(d1Cr@nhGGmRHIQJ&3LipH45mJ^S-OIGPV@$_b0PgZ6S z7Xx(O7QzQPhpMV7b1=?|HSHtxbx+3Gba6DTW;kd4aLe0g)a`q)QmxPVycgj_B0E*N z#yO^$NHStm!*>kY1!_4?bdO!Y3!nvj0CXS#4B$Ip0zUu?_yueLe*o_CU%-as7Ptd` z2Hpg}17nRM@HY4xxC{OX-U0sx_rR=!oQfmDc@-z{zCsqMq*04>GGVvLCQyeqX^Xb0 zOFPt~UCy61$!?q%E~bYyqE7RZ=i0goM5$d)m)p&S-c=BXy8n+H(MRWBG%~mey7K&M z*_L|>a=L1_eVT|cjRk%eStYAqxltSBzD65`Y%vJ#?k$B3qTb?pVkyKluaqid2Dyuv zJe%uWHvSfR@g-;#v*&i@G5h{_oTpNw+G6jW%4>~c>E?k*G@6^2{6{k%C;bAiTeZpl to7MZqn<$xy08J~6OTJhBWSXV$l?MB66!XAL^us8K5Vd4>p%itolz%HKG?@SZ literal 0 HcmV?d00001 diff --git a/jme3-core/src/main/resources/Common/FrameGraphs/Forward.j3g b/jme3-core/src/main/resources/Common/FrameGraphs/Forward.j3g new file mode 100644 index 0000000000000000000000000000000000000000..688493d766461f498d30f186b31fbff2d3169497 GIT binary patch literal 707 zcma))K}*9h6vy+Lw%goAMa7#J!GlnQiC01927)+rCj}vPajSD_Nz#KiZ+;lhei1*B z|JQ9Gt_%zR!4+v~i)F(~dZ9r@1jY^;vFQ7+_%eovkI$3CSRLeqi%dJC~X909Y&!sE0N* z@D>~VpN)dwX5=au!up~QirYe7pKSFy(_=mZL(ArwK6Pz-%Q4d@eULSGOwz9HsRSGOf7rhp_x z=$q6c*bA}C+0DO|bLIevx)jN~>6@gGHx!BUcP>MSLjiUTh}uJ|j4Kr0ieF%5?L^rx fGf9mKTNTfh?hC@h+g`o%g=bWYntQ&MDLj7wS+ANl literal 0 HcmV?d00001 diff --git a/jme3-core/src/main/resources/Common/FrameGraphs/TiledDeferred.j3g b/jme3-core/src/main/resources/Common/FrameGraphs/TiledDeferred.j3g new file mode 100644 index 0000000000000000000000000000000000000000..d345baffdad1d4048199754e660c909c3a3a8a43 GIT binary patch literal 1459 zcma)6%Wl&^6rF3wk0xoGraZ-h4T41_BT>YL1*lCM74e8jHo$6XPZCqdw*08n9UsAl z4S&Hmu;fEnv*%pfiIO&n66yHd%;Vg1?~MKC-N~U4LI-RjJo$IvMib}jL>)Sb3O$vm z#2F@XqDF~~$IdB-T@E`klUS~aFL;`YJQZi-n{BMkr*k$>x4M1iw0%$3s&&}UM;VS3+-c$#drUK#WW=G4JEzZE z+o%%*KTsWoYm+E%wL!@515=xv<$zNHuYnrC_tyYozy!Vn7Vs0Wf#1Lu@E73I`v){2 z*#I2c9&}#lDKS@UbA9G}5U?23d&f)F4ok zwrPiUsYQF#rhWF$n$(zkXSkR<7$a(3ZwlAf5)h_(d2_f^TV z<_z)bTiKdN0=|~5ZVVC`rm@6lBdcVMr3>|L?(4Kw$QFme9lj^XBx>J$S6K= + * The test succeeds if both export and import operations for both xml and binary + * formats functions without error. For importing, the resulting framegraph must + * show up on the detailed profiler gui. + *

      + * The test fails if any errors occur, or the framegraph does not show up on the + * detailed profiler gui after importing. + *

      + * The test application closes after exporting. + * + * @author codex + */ +public class TestFrameGraphImportExport extends SimpleApplication { + + private final String path = System.getProperty("user.home")+"/myGraph"; + private final boolean export = true; + private final boolean xml = false; + + public static void main(String[] args) { + TestFrameGraphImportExport app = new TestFrameGraphImportExport(); + AppSettings as = new AppSettings(true); + as.setWidth(768); + as.setHeight(768); + app.setSettings(as); + app.start(); + } + + @Override + public void simpleInitApp() { + + final File file = new File(path+"."+(xml ? "xml" : "j3g")); + + if (export) { + FrameGraph graph = FrameGraphFactory.deferred(assetManager, renderManager, false); + try { + if (xml) { + XMLExporter.getInstance().save(graph.createData(), file); + } else { + BinaryExporter.getInstance().save(graph.createData(), file); + } + } catch (IOException ex) { + Logger.getLogger(TestFrameGraphImportExport.class.getName()).log(Level.SEVERE, null, ex); + } + stop(); + } else { + stateManager.attach(new DetailedProfilerState()); + flyCam.setDragToRotate(true); + try { + FrameGraph graph = new FrameGraph(assetManager, renderManager); + if (xml) { + graph.applyData(XMLImporter.getInstance().load(file)); + } else { + graph.applyData(BinaryImporter.getInstance().load(file)); + } + viewPort.setFrameGraph(graph); + } catch (IOException ex) { + Logger.getLogger(TestFrameGraphImportExport.class.getName()).log(Level.SEVERE, null, ex); + } + } + + } + +} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index 876b32b1b6..a0a9bca93d 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2024 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.DetailedProfilerState; @@ -12,7 +43,6 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.RenderManager; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.renderer.framegraph.RenderObjectMap; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; @@ -69,7 +99,9 @@ public void simpleInitApp() { inputManager.setCursorVisible(true); //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - graph = FrameGraphFactory.deferred(assetManager, renderManager, false); + //graph = FrameGraphFactory.deferred(assetManager, renderManager, false); + graph = new FrameGraph(assetManager, renderManager); + graph.applyData(assetManager.loadFrameGraph("Common/FrameGraphs/Deferred.j3g")); //graph.setConstructor(new ForwardGraphConstructor()); //graph.setConstructor(new TestConstructor()); //MyFrameGraph graph = RenderPipelineFactory.createBackroundScreenTest(assetManager, renderManager); From 9baebeefeebc674f2b4f807f5cb4e2850dd1f61d Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 21 May 2024 14:36:44 -0400 Subject: [PATCH 069/111] delete unused classes --- .../java/com/jme3/asset/FrameGraphKey.java | 31 +++++++++++++- .../jme3/material/logic/TileInfoProvider.java | 15 ------- .../jme3/material/logic/TiledRenderGrid.java | 31 +++++++++++++- .../main/java/com/jme3/post/FilterPass.java | 36 ---------------- .../main/java/com/jme3/profile/FgStep.java | 34 +++++++++++++-- .../jme3/renderer/GeometryRenderHandler.java | 41 +++++++++++++++++-- 6 files changed, 127 insertions(+), 61 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/material/logic/TileInfoProvider.java delete mode 100644 jme3-core/src/main/java/com/jme3/post/FilterPass.java diff --git a/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java b/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java index 41c5cfbe7d..a2e06b73f8 100644 --- a/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java +++ b/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.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) 2024 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.asset; diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileInfoProvider.java b/jme3-core/src/main/java/com/jme3/material/logic/TileInfoProvider.java deleted file mode 100644 index ba04db5378..0000000000 --- a/jme3-core/src/main/java/com/jme3/material/logic/TileInfoProvider.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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.material.logic; - -/** - * - * @author codex - */ -public interface TileInfoProvider { - - public TiledRenderGrid getTiledRenderGrid(); - -} diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java b/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java index 559742f09b..ebf7862828 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.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) 2024 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; diff --git a/jme3-core/src/main/java/com/jme3/post/FilterPass.java b/jme3-core/src/main/java/com/jme3/post/FilterPass.java deleted file mode 100644 index 4a5922f059..0000000000 --- a/jme3-core/src/main/java/com/jme3/post/FilterPass.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.post; - -import com.jme3.asset.AssetManager; -import com.jme3.renderer.framegraph.FGRenderContext; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.passes.RenderPass; - -/** - * - * @author codex - */ -public class FilterPass extends RenderPass { - - private Filter filter; - private AssetManager assetManager; - - @Override - protected void initialize(FrameGraph frameGraph) { - assetManager = frameGraph.getAssetManager(); - } - @Override - protected void prepare(FGRenderContext context) { - filter.init(assetManager, context.getRenderManager(), context.getViewPort(), context.getWidth(), context.getHeight()); - } - @Override - protected void execute(FGRenderContext context) {} - @Override - protected void reset(FGRenderContext context) {} - @Override - protected void cleanup(FrameGraph frameGraph) {} - -} diff --git a/jme3-core/src/main/java/com/jme3/profile/FgStep.java b/jme3-core/src/main/java/com/jme3/profile/FgStep.java index 4c698007aa..245a518a85 100644 --- a/jme3-core/src/main/java/com/jme3/profile/FgStep.java +++ b/jme3-core/src/main/java/com/jme3/profile/FgStep.java @@ -1,11 +1,39 @@ /* - * 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) 2024 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.profile; /** - * + * Defines steps in executing framegraphs. + * * @author codex */ public enum FgStep { diff --git a/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java b/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java index 40f9eeaa95..157fc370ab 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java +++ b/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java @@ -1,17 +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) 2024 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; import com.jme3.scene.Geometry; /** - * + * Handles rendering of individual geometries. + * * @author codex */ public interface GeometryRenderHandler { + /** + * Renders the given geometry, or returns false. + * + * @param rm render manager + * @param geom geometry to render + * @return true if the geometry was rendered + */ public boolean renderGeometry(RenderManager rm, Geometry geom); } From a2d55f26e30e5fcce35914a49248fbdf13c1c724 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 21 May 2024 21:27:58 -0400 Subject: [PATCH 070/111] fixed background on deferred pipelines --- .../framegraph/passes/GBufferPass.java | 1 + .../renderer/framegraph/passes/Junction.java | 23 +++++++++++++++--- .../ShadingCommon/DeferredShading.frag | 15 +++++------- .../TileBasedDeferredShading.frag | 24 +++++++++---------- .../TestFrameGraphImportExport.java | 2 +- .../TestSimpleDeferredLighting.java | 13 +++++----- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 4a4ea1bd34..d027d42824 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -134,6 +134,7 @@ public boolean renderGeometry(RenderManager rm, Geometry geom) { if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null) { return false; } + System.out.println("render geometry"); rm.renderGeometry(geom); if (material.getActiveTechnique() != null) { LightList lts = geom.getFilterWorldLights(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index a3a77dce2a..8e7b163830 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -60,7 +60,7 @@ public Junction() { this(2); } public Junction(int length) { - this.length = length; + setLength(length); } @Override @@ -72,7 +72,11 @@ protected void initialize(FrameGraph frameGraph) { } @Override protected void prepare(FGRenderContext context) { - output.setSource(getInputTickets().get(source.getGraphValue(context.getViewPort()))); + if (source != null) { + output.setSource(getInputTickets().get(source.getGraphValue(context.getViewPort()))); + } else { + output.setSource(getInputTickets().getFirst()); + } } @Override protected void execute(FGRenderContext context) {} @@ -97,8 +101,21 @@ public void read(JmeImporter im) throws IOException { length = in.readInt("length", 2); } - public void setLength(int length) { + public final void setLength(int length) { + if (length <= 0) { + throw new IllegalArgumentException("Length must be greater than zero."); + } this.length = length; } + public void setIndexSource(GraphSource source) { + this.source = source; + } + + public int getLength() { + return length; + } + public GraphSource getIndexSource() { + return source; + } } 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 8aaa53dcac..4b564e0175 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -45,10 +45,10 @@ void main(){ float depth = texture2D(GBUFFER_DEPTH, texCoord).r; gl_FragDepth = depth; // Perform corresponding pixel shading based on the shading model - if(IS_LIT(shadingModelId)){ + 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){ + if (shadingModelId == LEGACY_LIGHTING) { vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord); vec4 diffuseColor = texture2D(Context_InGBuff0, innerTexCoord); @@ -127,8 +127,7 @@ void main(){ i+=3; #endif } - } - else if(shadingModelId == STANDARD_LIGHTING){ + } else if (shadingModelId == STANDARD_LIGHTING) { // todo: vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff0 = texture2D(Context_InGBuff0, innerTexCoord); @@ -215,14 +214,12 @@ void main(){ else if(shadingModelId == SUBSURFACE_SCATTERING){ // todo: } - } - else if(shadingModelId == UNLIT){ + } else if(shadingModelId == UNLIT) { gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); + } else { + discard; } - //if (innerTexCoord.y > 0.5) { - //discard; - //} //discard; //gl_FragColor.a = 0.5; //gl_FragColor.a = 0.01; 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 8aaaefe847..4cfd74b1cc 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag @@ -54,10 +54,10 @@ void main(){ float depth = texture2D(GBUFFER_DEPTH, texCoord).r; gl_FragDepth = depth; // Perform corresponding pixel shading based on the shading model - if(IS_LIT(shadingModelId)){ + 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){ + if (shadingModelId == LEGACY_LIGHTING) { vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord); vec4 diffuseColor = texture2D(Context_InGBuff0, innerTexCoord); @@ -230,8 +230,7 @@ void main(){ // i+=3; // #endif // } - } - else if(shadingModelId == STANDARD_LIGHTING){ + } else if (shadingModelId == STANDARD_LIGHTING) { // todo: vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff0 = texture2D(Context_InGBuff0, innerTexCoord); @@ -351,11 +350,12 @@ void main(){ // #endif gl_FragColor.rgb += directLighting * spotFallOff; - #if defined(USE_TEXTURE_PACK_MODE) - i++; - #else i++; - #endif + //#if defined(USE_TEXTURE_PACK_MODE) + //i++; + //#else + //i++; + //#endif } } // skyLight and reflectionProbe @@ -363,13 +363,13 @@ void main(){ gl_FragColor.rgb += skyLightAndReflection; gl_FragColor.rgb += emissive; gl_FragColor.a = alpha; - } - else if(shadingModelId == SUBSURFACE_SCATTERING){ + } else if (shadingModelId == SUBSURFACE_SCATTERING) { // todo: } - } - else if(shadingModelId == UNLIT){ + } else if (shadingModelId == UNLIT) { gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); + } else { + discard; } } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java b/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java index b508c0c2ab..b068f5d868 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java @@ -62,7 +62,7 @@ public class TestFrameGraphImportExport extends SimpleApplication { private final String path = System.getProperty("user.home")+"/myGraph"; - private final boolean export = true; + private final boolean export = false; private final boolean xml = false; public static void main(String[] args) { diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 9ea91533ad..0456f4425a 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -37,6 +37,7 @@ import com.jme3.app.SimpleApplication; import com.jme3.asset.TextureKey; import com.jme3.environment.EnvironmentCamera; +import com.jme3.environment.EnvironmentProbeControl; import com.jme3.environment.LightProbeFactory; import com.jme3.environment.generation.JobProgressAdapter; import com.jme3.environment.util.EnvMapUtils; @@ -52,9 +53,7 @@ import com.jme3.math.*; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; -import com.jme3.renderer.RenderManager; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -654,14 +653,16 @@ private void testScene11(){ @Override public void simpleInitApp() { - stateManager.attach(new DetailedProfilerState()); //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - FrameGraph graph = FrameGraphFactory.deferred(assetManager, renderManager, true); + FrameGraph graph = new FrameGraph(assetManager, renderManager); + graph.applyData(assetManager.loadFrameGraph("Common/FrameGraphs/Deferred.j3g")); //FrameGraph graph = FrameGraphFactory.forward(assetManager, renderManager); viewPort.setFrameGraph(graph); + viewPort.setBackgroundColor(ColorRGBA.Green.mult(.1f)); + Geometry debugView = new Geometry("debug", new Quad(200, 200)); debugView.setLocalTranslation(0, 200, 0); Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); @@ -674,7 +675,7 @@ public void simpleInitApp() { //guiNode.attachChild(debugView); //renderManager.setRenderPath(currentRenderPath); - testScene10(); + testScene1(); // cam.setFrustumPerspective(45.0f, 4.0f / 3.0f, 0.01f, 100.0f); flyCam.setMoveSpeed(10.0f); // deferred @@ -688,7 +689,7 @@ public void simpleInitApp() { flyCam.setDragToRotate(true); flyCam.setMoveSpeed(50.0f); - viewPort.setBackgroundColor(ColorRGBA.DarkGray); + rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); registerInput(); } From 9fbd053a98cc07b5164e1be95021b02e97ffc68b Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 22 May 2024 09:56:20 -0400 Subject: [PATCH 071/111] added basic opencl --- .../java/com/jme3/renderer/RenderManager.java | 2 +- .../renderer/framegraph/FGRenderContext.java | 60 +++++++++++++++++-- .../jme3/renderer/framegraph/FrameGraph.java | 52 ++++++++++++---- .../framegraph/FrameGraphFactory.java | 10 ++-- .../renderer/framegraph/ResourceList.java | 12 +++- .../framegraph/definitions/TextureDef.java | 6 +- 6 files changed, 116 insertions(+), 26 deletions(-) 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 812504a368..dc7326d6ff 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -1272,7 +1272,7 @@ public void renderViewPort(ViewPort vp, float tpf) { prof.vpStep(VpStep.PreFrame, vp, null); } if (fg != null) { - fg.configure(vp, prof, tpf); + fg.configure(this, vp, prof, tpf); fg.preFrame(); } else if (processors != null) { for (SceneProcessor p : processors.getArray()) { 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 03e305e8f1..48f7dc668f 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 @@ -33,6 +33,8 @@ import com.jme3.material.Material; import com.jme3.material.RenderState; +import com.jme3.opencl.CommandQueue; +import com.jme3.opencl.Context; import com.jme3.profile.AppProfiler; import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.RenderManager; @@ -54,11 +56,13 @@ public class FGRenderContext { private final FrameGraph frameGraph; - private final RenderManager renderManager; + private RenderManager renderManager; private ViewPort viewPort; private AppProfiler profiler; private float tpf; private final FullScreenQuad screen; + private Context clContext; + private CommandQueue clQueue; private String forcedTechnique; private Material forcedMat; @@ -66,21 +70,26 @@ public class FGRenderContext { private GeometryRenderHandler geomRender; private Predicate geomFilter; private RenderState renderState; - - public FGRenderContext(FrameGraph frameGraph, RenderManager renderManager) { + + public FGRenderContext(FrameGraph frameGraph) { + this(frameGraph, null); + } + public FGRenderContext(FrameGraph frameGraph, Context clContext) { this.frameGraph = frameGraph; - this.renderManager = renderManager; + this.clContext = clContext; this.screen = new FullScreenQuad(this.frameGraph.getAssetManager()); } /** * Targets this context to the viewport. * + * @param rm * @param vp * @param profiler * @param tpf */ - public void target(ViewPort vp, AppProfiler profiler, float tpf) { + public void target(RenderManager rm, ViewPort vp, AppProfiler profiler, float tpf) { + this.renderManager = rm; this.viewPort = vp; this.profiler = profiler; this.tpf = tpf; @@ -88,6 +97,14 @@ public void target(ViewPort vp, AppProfiler profiler, float tpf) { throw new NullPointerException("ViewPort cannot be null."); } } + /** + * Returns true if the context is ready for rendering. + * + * @return + */ + public boolean isReady() { + return renderManager != null && viewPort != null; + } /** * Saves the current render settings. @@ -153,6 +170,23 @@ public void transferTextures(Texture2D color, Texture2D depth) { screen.render(renderManager, color, depth); } + /** + * Sets the OpenCL context for compute shading. + * + * @param clContext + */ + public void setCLContext(Context clContext) { + this.clContext = clContext; + } + /** + * Sets the OpenCL command queue for compute shading. + * + * @param clQueue + */ + public void setCLQueue(CommandQueue clQueue) { + this.clQueue = clQueue; + } + /** * Gets the render manager. * @@ -205,6 +239,22 @@ public RenderQueue getRenderQueue() { public FullScreenQuad getScreen() { return screen; } + /** + * Gets the OpenCL context for compute shading. + * + * @return + */ + public Context getCLContext() { + return clContext; + } + /** + * Gets the OpenCL command queue assigned to this context. + * + * @return + */ + public CommandQueue getCLQueue() { + return clQueue; + } /** * Gets the time per frame. * 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 da0ad73557..ab87086887 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 @@ -34,6 +34,8 @@ import com.jme3.renderer.framegraph.passes.RenderPass; import com.jme3.asset.AssetManager; import com.jme3.asset.FrameGraphKey; +import com.jme3.opencl.CommandQueue; +import com.jme3.opencl.Context; import com.jme3.profile.AppProfiler; import com.jme3.profile.FgStep; import com.jme3.profile.VpStep; @@ -95,10 +97,10 @@ public class FrameGraph { * @param assetManager asset manager (not null) * @param renderManager render manager (not null) */ - public FrameGraph(AssetManager assetManager, RenderManager renderManager) { + public FrameGraph(AssetManager assetManager) { this.assetManager = assetManager; - this.resources = new ResourceList(renderManager.getRenderObjectMap()); - this.context = new FGRenderContext(this, renderManager); + this.resources = new ResourceList(); + this.context = new FGRenderContext(this); } /** * Creates a new framegraph from the given data. @@ -107,8 +109,8 @@ public FrameGraph(AssetManager assetManager, RenderManager renderManager) { * @param renderManager * @param data */ - public FrameGraph(AssetManager assetManager, RenderManager renderManager, FrameGraphData data) { - this(assetManager, renderManager); + public FrameGraph(AssetManager assetManager, FrameGraphData data) { + this(assetManager); applyData(data); } /** @@ -118,8 +120,8 @@ public FrameGraph(AssetManager assetManager, RenderManager renderManager, FrameG * @param renderManager * @param key */ - public FrameGraph(AssetManager assetManager, RenderManager renderManager, FrameGraphKey key) { - this(assetManager, renderManager, assetManager.loadFrameGraph(key)); + public FrameGraph(AssetManager assetManager, FrameGraphKey key) { + this(assetManager, assetManager.loadFrameGraph(key)); } /** * Creates a new framegraph from data obtained by the given asset name. @@ -128,19 +130,21 @@ public FrameGraph(AssetManager assetManager, RenderManager renderManager, FrameG * @param renderManager * @param dataAsset */ - public FrameGraph(AssetManager assetManager, RenderManager renderManager, String dataAsset) { - this(assetManager, renderManager, assetManager.loadFrameGraph(dataAsset)); + public FrameGraph(AssetManager assetManager, String dataAsset) { + this(assetManager, assetManager.loadFrameGraph(dataAsset)); } /** * Configures the framegraph rendering context. * + * @param rm * @param vp viewport to render (not null) * @param prof profiler (may be null) * @param tpf time per frame */ - public void configure(ViewPort vp, AppProfiler prof, float tpf) { - context.target(vp, prof, tpf); + public void configure(RenderManager rm, ViewPort vp, AppProfiler prof, float tpf) { + resources.setObjectMap(rm.getRenderObjectMap()); + context.target(rm, vp, prof, tpf); } /** * Pre-frame operations. @@ -393,6 +397,24 @@ public void clear() { public void setName(String name) { this.name = name; } + /** + * Sets the OpenCL context for compute shading. + * + * @param clContext + */ + public void setCLContext(Context clContext) { + context.setCLContext(clContext); + } + /** + * Assigns this framegraph to the OpenCL command queue. + *

      + * Passes do not need to use the assigned command queue, but are encouraged to. + * + * @param clQueue + */ + public void setCLQueue(CommandQueue clQueue) { + context.setCLQueue(clQueue); + } /** * @@ -424,6 +446,14 @@ public FGRenderContext getContext() { public RenderManager getRenderManager() { return context.getRenderManager(); } + /** + * Gets the OpenCL context for compute shading. + * + * @return + */ + public Context getCLContext() { + return context.getCLContext(); + } /** * Gets the name of this framegraph. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index c07df43a6d..fe9f486e85 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -53,11 +53,10 @@ public class FrameGraphFactory { * Constructs a standard forward framegraph, with no controllable features. * * @param assetManager - * @param renderManager * @return forward framegraph */ - public static FrameGraph forward(AssetManager assetManager, RenderManager renderManager) { - FrameGraph fg = new FrameGraph(assetManager, renderManager); + public static FrameGraph forward(AssetManager assetManager) { + FrameGraph fg = new FrameGraph(assetManager); fg.add(new OutputBucketPass(RenderQueue.Bucket.Opaque)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); @@ -71,12 +70,11 @@ public static FrameGraph forward(AssetManager assetManager, RenderManager render * Constructs a deferred or tiled deferred framegraph. * * @param assetManager - * @param renderManager * @param tiled true to construct advanced tiled deferred * @return deferred framegraph */ - public static FrameGraph deferred(AssetManager assetManager, RenderManager renderManager, boolean tiled) { - FrameGraph fg = new FrameGraph(assetManager, renderManager); + public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { + FrameGraph fg = new FrameGraph(assetManager); GBufferPass gbuf = fg.add(new GBufferPass()); RenderPass deferred; if (!tiled) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 2eb3eda5a3..a1a56d64d9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -46,11 +46,12 @@ public class ResourceList { private static final int INITIAL_SIZE = 20; - private final RenderObjectMap map; + private RenderObjectMap map; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); private int nextSlot = 0; private int textureBinds = 0; + public ResourceList() {} public ResourceList(RenderObjectMap map) { this.map = map; } @@ -589,4 +590,13 @@ public int getTextureBinds() { return textureBinds; } + /** + * Sets the render object map. + * + * @param map + */ + public void setObjectMap(RenderObjectMap map) { + this.map = map; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 69ef0370a5..ca982189dd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -95,11 +95,13 @@ public TextureDef(Class type, Function textureBuilder, Image.Format @Override public T createResource() { + Image img; if (depth > 0) { - return createTexture(new Image(format, width, height, depth, new ArrayList<>(depth), colorSpace)); + img = new Image(format, width, height, depth, new ArrayList<>(depth), colorSpace); } else { - return createTexture(new Image(format, width, height, null, colorSpace)); + img = new Image(format, width, height, null, colorSpace); } + return createTexture(img); } @Override public T applyDirectResource(Object resource) { From a9d74a1448ff0f7861657f4cc86bb7f289e0c00f Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 22 May 2024 10:26:55 -0400 Subject: [PATCH 072/111] fixed tests --- .../jme3/renderer/framegraph/FrameGraph.java | 20 ++++++++++++++++++- .../renderpath/TestDeferredPBRShading.java | 2 +- .../renderpath/TestDeferredShading.java | 2 +- .../TestDeferredShadingPathShadow.java | 2 +- .../TestFrameGraphImportExport.java | 4 ++-- .../TestPBRTerrainAdvancedRenderPath.java | 2 +- .../renderpath/TestPBRTerrainRenderPath.java | 2 +- ...thPointDirectionalAndSpotLightShadows.java | 2 +- .../jme3test/renderpath/TestShadingModel.java | 2 +- .../TestSimpleDeferredLighting.java | 3 +-- .../TestTileBasedDeferredShading.java | 2 +- 11 files changed, 30 insertions(+), 13 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 ab87086887..325769a89c 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 @@ -483,13 +483,31 @@ public final FrameGraph applyData(FrameGraphData data) { */ public FrameGraph applyData(Object data) { if (data != null && data instanceof FrameGraphData) { - return FrameGraph.this.applyData((FrameGraphData)data); + return applyData((FrameGraphData)data); } else if (data != null) { throw new ClassCastException(data.getClass()+" cannot be cast to "+FrameGraphData.class); } else { throw new NullPointerException("Proxy cannot be null"); } } + /** + * Loads and applies framegraph data from the key. + * + * @param key + * @return + */ + public FrameGraph loadData(FrameGraphKey key) { + return applyData(assetManager.loadFrameGraph(key)); + } + /** + * Loads and applies framegraph data at the specified asset path. + * + * @param assetPath + * @return + */ + public FrameGraph loadData(String assetPath) { + return applyData(assetManager.loadFrameGraph(assetPath)); + } /** * Creates exportable framegraph data. * diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java index 995253a382..645bf880a0 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java @@ -39,7 +39,7 @@ public class TestDeferredPBRShading extends SimpleApplication { @Override public void simpleInitApp() { - viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, false)); + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, false)); roughness = 1.0f; assetManager.registerLoader(KTXLoader.class, "ktx"); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java index 3636b859b5..6ce6e05571 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java @@ -24,7 +24,7 @@ public class TestDeferredShading extends SimpleApplication { @Override public void simpleInitApp() { - viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, false)); + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, false)); // Test Forward // renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java index e79451103b..738e5f9abc 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java @@ -28,7 +28,7 @@ public class TestDeferredShadingPathShadow extends SimpleApplication implements public void simpleInitApp() { //renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Forward)); - viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, true)); + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, true)); Material boxMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml"); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java b/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java index b068f5d868..929611da21 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java @@ -80,7 +80,7 @@ public void simpleInitApp() { final File file = new File(path+"."+(xml ? "xml" : "j3g")); if (export) { - FrameGraph graph = FrameGraphFactory.deferred(assetManager, renderManager, false); + FrameGraph graph = FrameGraphFactory.deferred(assetManager, false); try { if (xml) { XMLExporter.getInstance().save(graph.createData(), file); @@ -95,7 +95,7 @@ public void simpleInitApp() { stateManager.attach(new DetailedProfilerState()); flyCam.setDragToRotate(true); try { - FrameGraph graph = new FrameGraph(assetManager, renderManager); + FrameGraph graph = new FrameGraph(assetManager); if (xml) { graph.applyData(XMLImporter.getInstance().load(file)); } else { diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java index 7714f86422..4fe56f42f9 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java @@ -195,7 +195,7 @@ public void onAction(String name, boolean pressed, float tpf) { @Override public void simpleInitApp() { - viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, true)); + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, true)); //renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); //renderManager.setRenderPath(RenderManager.RenderPath.TiledDeferred); setupKeys(); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java index 6eb1846fb3..01d847c568 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java @@ -196,7 +196,7 @@ else if(name.equals("addPointLight") && !pressed){ @Override public void simpleInitApp() { - viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, true)); + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, true)); flyCam.setDragToRotate(true); // For this scene, use a tileSize=64 configuration (at 1600*900 resolution) diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java index 05e6fb9a70..6efdec4de3 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java @@ -69,7 +69,7 @@ public void simpleInitApp() { //FrameGraph graph = new FrameGraph(assetManager, renderManager); //graph.setConstructor(new DeferredGraphConstructor()); - FrameGraph graph = FrameGraphFactory.deferred(assetManager, renderManager, false); + FrameGraph graph = FrameGraphFactory.deferred(assetManager, false); viewPort.setFrameGraph(graph); //renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index a0a9bca93d..28b6c79324 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -100,7 +100,7 @@ public void simpleInitApp() { //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); //graph = FrameGraphFactory.deferred(assetManager, renderManager, false); - graph = new FrameGraph(assetManager, renderManager); + graph = new FrameGraph(assetManager); graph.applyData(assetManager.loadFrameGraph("Common/FrameGraphs/Deferred.j3g")); //graph.setConstructor(new ForwardGraphConstructor()); //graph.setConstructor(new TestConstructor()); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 0456f4425a..4ed5d97782 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -656,8 +656,7 @@ public void simpleInitApp() { stateManager.attach(new DetailedProfilerState()); //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - FrameGraph graph = new FrameGraph(assetManager, renderManager); - graph.applyData(assetManager.loadFrameGraph("Common/FrameGraphs/Deferred.j3g")); + FrameGraph graph = new FrameGraph(assetManager, "Common/FrameGraphs/Deferred.j3g"); //FrameGraph graph = FrameGraphFactory.forward(assetManager, renderManager); viewPort.setFrameGraph(graph); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java index e77fedf9a0..1dc2aa1f0f 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java @@ -25,7 +25,7 @@ public class TestTileBasedDeferredShading extends SimpleApplication { @Override public void simpleInitApp() { - viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, renderManager, true)); + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, true)); // 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 From 970e73cc67996c0c40b04f785df79c0b384e07f3 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 22 May 2024 10:29:31 -0400 Subject: [PATCH 073/111] verified fix for overlapping viewports --- .../java/jme3test/renderpath/TestSimpleDeferredLighting.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 4ed5d97782..560dc7f8f3 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -658,7 +658,8 @@ public void simpleInitApp() { //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); FrameGraph graph = new FrameGraph(assetManager, "Common/FrameGraphs/Deferred.j3g"); //FrameGraph graph = FrameGraphFactory.forward(assetManager, renderManager); - viewPort.setFrameGraph(graph); + //viewPort.setFrameGraph(graph); + renderManager.setFrameGraph(graph); viewPort.setBackgroundColor(ColorRGBA.Green.mult(.1f)); @@ -674,7 +675,7 @@ public void simpleInitApp() { //guiNode.attachChild(debugView); //renderManager.setRenderPath(currentRenderPath); - testScene1(); + testScene7(); // cam.setFrustumPerspective(45.0f, 4.0f / 3.0f, 0.01f, 100.0f); flyCam.setMoveSpeed(10.0f); // deferred From 06832da4a562f18e3c650f1756f40eea1d8d4a11 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 22 May 2024 11:05:37 -0400 Subject: [PATCH 074/111] added framegraph loading speed test --- .../java/com/jme3/app/LegacyApplication.java | 2 +- .../TestFrameGraphLoadingSpeeds.java | 88 +++++++++++++++++++ .../TestSimpleDeferredLighting.java | 1 + 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java diff --git a/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java b/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java index 3ad319052e..33073b432d 100644 --- a/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java +++ b/jme3-core/src/main/java/com/jme3/app/LegacyApplication.java @@ -336,7 +336,7 @@ private void initCamera() { Camera guiCam = new Camera(settings.getWidth(), settings.getHeight()); guiViewPort = renderManager.createPostView("Gui Default", guiCam); guiViewPort.setClearFlags(false, false, false); - guiViewPort.setUseFrameGraphs(false); + //guiViewPort.setUseFrameGraphs(false); } /** diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java b/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java new file mode 100644 index 0000000000..f541e279ae --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java @@ -0,0 +1,88 @@ +/* + * 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.renderer.framegraph.FrameGraph; + +/** + * Tests framegraph loading speeds. + *

      + * The test loads a total of 9 framegraphs (3 forward, 3 deferred, and 3 tiled deferred) + * after a delay of 100 frames, with 10 frames seperating each load. After all loading + * is complete, the application quits. Results are printed to the console as milliseconds + * each load took to complete. + *

      + * In general, earlier loads take around 15ms, and later loads take around 2ms. + *

      + * Note that framegraph data are not cached. + * + * @author codex + */ +public class TestFrameGraphLoadingSpeeds extends SimpleApplication { + + private int frameDelay = 100; + private int loadIndex = 0; + + public static void main(String[] args) { + new TestFrameGraphLoadingSpeeds().start(); + } + + @Override + public void simpleInitApp() {} + @Override + public void simpleUpdate(float tpf) { + if (--frameDelay <= 0) { + switch (loadIndex++) { + case 6: + case 3: + case 0: load(loadIndex, "forward", "Common/FrameGraphs/Forward.j3g"); break; + case 7: + case 4: + case 1: load(loadIndex, "deferred", "Common/FrameGraphs/Deferred.j3g"); break; + case 8: + case 5: + case 2: load(loadIndex, "tiled deferred", "Common/FrameGraphs/TiledDeferred.j3g"); break; + default: stop(); + } + frameDelay = 10; + } + } + + private void load(int index, String name, String path) { + long timeBefore = System.currentTimeMillis(); + FrameGraph fg = new FrameGraph(assetManager, path); + long timeAfter = System.currentTimeMillis(); + System.out.println(index+": "+name+": "+(timeAfter-timeBefore)+"ms"); + } + +} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 560dc7f8f3..3a494c6551 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -662,6 +662,7 @@ public void simpleInitApp() { renderManager.setFrameGraph(graph); viewPort.setBackgroundColor(ColorRGBA.Green.mult(.1f)); + guiViewPort.setClearFlags(false, true, false); Geometry debugView = new Geometry("debug", new Quad(200, 200)); debugView.setLocalTranslation(0, 200, 0); From fe02e9490af76342b21277512a7335407be0efcc Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 25 May 2024 16:22:29 -0400 Subject: [PATCH 075/111] added framegraph event capture --- .../java/com/jme3/renderer/RenderManager.java | 42 ++- .../renderer/framegraph/FGRenderContext.java | 17 + .../jme3/renderer/framegraph/FrameGraph.java | 33 +- .../framegraph/FrameGraphFactory.java | 9 +- .../renderer/framegraph/FullScreenQuad.java | 9 + .../renderer/framegraph/RenderObjectMap.java | 39 ++- .../renderer/framegraph/ResourceList.java | 51 ++- .../framegraph/debug/FGFrameCapture.java | 174 ++++++++++ .../framegraph/definitions/TextureDef.java | 6 +- .../framegraph/io/MatParamTargetControl.java | 20 +- .../renderer/framegraph/passes/Attribute.java | 2 +- .../framegraph/passes/DeferredPass.java | 9 +- .../framegraph/passes/GBufferPass.java | 5 +- .../framegraph/passes/OutputPass.java | 24 ++ .../framegraph/passes/RenderPass.java | 7 + .../framegraph/passes/TileDeferredPass.java | 1 + .../ShadingCommon/DeferredShading.frag | 299 +++++++++--------- .../ShadingCommon/TextureTransfer.frag | 23 +- .../ShadingCommon/TextureTransfer.j3md | 6 +- .../Common/ShaderLib/ShadingModel.glsllib | 10 +- .../TestSimpleDeferredLighting.java | 45 ++- 21 files changed, 601 insertions(+), 230 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/FGFrameCapture.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 dc7326d6ff..753e451275 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -48,6 +48,7 @@ import com.jme3.profile.VpStep; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderObjectMap; +import com.jme3.renderer.framegraph.debug.FGFrameCapture; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; @@ -65,11 +66,14 @@ import com.jme3.system.Timer; import com.jme3.texture.FrameBuffer; import com.jme3.util.SafeArrayList; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.function.Predicate; +import java.util.logging.Level; +import java.util.logging.Logger; /** * A high-level rendering interface that is above the Renderer implementation. @@ -88,9 +92,10 @@ public class RenderManager { private final ArrayList preViewPorts = new ArrayList<>(); private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); - private final RenderObjectMap renderObjects = new RenderObjectMap(); + private final RenderObjectMap renderObjects; private final LinkedList executedFrameGraphs = new LinkedList<>(); private FrameGraph frameGraph; + private FGFrameCapture frameCapture; private Camera prevCam = null; private Material forcedMaterial = null; private String forcedTechnique = null; @@ -111,6 +116,7 @@ public class RenderManager { private int singlePassLightBatchSize = 1; private MatParamOverride boundDrawBufferId = new MatParamOverride(VarType.Int, "BoundDrawBuffer", 0); private Predicate renderFilter; + private int captureLifetime = 0; /** * Creates a high-level rendering interface over the @@ -121,6 +127,7 @@ public class RenderManager { public RenderManager(Renderer renderer) { this.renderer = renderer; this.forcedOverrides.add(boundDrawBufferId); + this.renderObjects = new RenderObjectMap(this); } /** @@ -155,6 +162,29 @@ public RenderObjectMap getRenderObjectMap() { return renderObjects; } + /** + * Sets the frame capture that captures relevant framegraph rendering events. + * + * @param frameCapture + * @param frames + */ + public void setFrameCapture(FGFrameCapture frameCapture, int frames) { + this.frameCapture = frameCapture; + this.captureLifetime = frames; + if (this.captureLifetime <= 0) { + this.frameCapture = null; + } + } + + /** + * Gets the frame capture that captures relevant framegraph rendering events. + * + * @return + */ + public FGFrameCapture getFrameCapture() { + return frameCapture; + } + /** * Sets the GeometryRenderHandler used to render geometry. *

      @@ -1426,6 +1456,16 @@ public void render(float tpf, boolean mainFrameBufferActive) { // flush object map renderObjects.flushMap(); + // tick frame capture + if (frameCapture != null && --captureLifetime <= 0) { + try { + frameCapture.export(); + } catch (IOException ex) { + Logger.getLogger(RenderManager.class.getName()).log(Level.SEVERE, null, ex); + } + frameCapture = null; + } + } /** 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 48f7dc668f..1f12149116 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 @@ -40,6 +40,7 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.debug.FGFrameCapture; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; @@ -239,6 +240,14 @@ public RenderQueue getRenderQueue() { public FullScreenQuad getScreen() { return screen; } + /** + * Gets the debug frame capture if one is assigned. + * + * @return + */ + public FGFrameCapture getFrameCapture() { + return renderManager.getFrameCapture(); + } /** * Gets the OpenCL context for compute shading. * @@ -288,5 +297,13 @@ public int getHeight() { public boolean isProfilerAvailable() { return profiler != null; } + /** + * Returns true if a debug frame snapshot is assigned. + * + * @return + */ + public boolean isFrameCaptureActive() { + return renderManager.getFrameCapture() != null; + } } 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 325769a89c..477357ada2 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 @@ -41,6 +41,7 @@ import com.jme3.profile.VpStep; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.debug.FGFrameCapture; import java.util.Iterator; import java.util.LinkedList; @@ -95,7 +96,6 @@ public class FrameGraph { * Creates a new blank framegraph. * * @param assetManager asset manager (not null) - * @param renderManager render manager (not null) */ public FrameGraph(AssetManager assetManager) { this.assetManager = assetManager; @@ -106,7 +106,6 @@ public FrameGraph(AssetManager assetManager) { * Creates a new framegraph from the given data. * * @param assetManager - * @param renderManager * @param data */ public FrameGraph(AssetManager assetManager, FrameGraphData data) { @@ -117,7 +116,6 @@ public FrameGraph(AssetManager assetManager, FrameGraphData data) { * Creates a new framegraph from data obtained by the given asset key. * * @param assetManager - * @param renderManager * @param key */ public FrameGraph(AssetManager assetManager, FrameGraphKey key) { @@ -127,7 +125,6 @@ public FrameGraph(AssetManager assetManager, FrameGraphKey key) { * Creates a new framegraph from data obtained by the given asset name. * * @param assetManager - * @param renderManager * @param dataAsset */ public FrameGraph(AssetManager assetManager, String dataAsset) { @@ -143,7 +140,7 @@ public FrameGraph(AssetManager assetManager, String dataAsset) { * @param tpf time per frame */ public void configure(RenderManager rm, ViewPort vp, AppProfiler prof, float tpf) { - resources.setObjectMap(rm.getRenderObjectMap()); + resources.setRenderManager(rm); context.target(rm, vp, prof, tpf); } /** @@ -179,14 +176,20 @@ public boolean execute() { // prepare ViewPort vp = context.getViewPort(); AppProfiler prof = context.getProfiler(); + FGFrameCapture cap = context.getFrameCapture(); + if (cap != null) { + if (!rendered) { + cap.renderFrame(); + } + cap.renderViewPort(context.getViewPort()); + } if (prof != null) prof.vpStep(VpStep.FrameGraphSetup, vp, null); if (!rendered) { resources.beginRenderingSession(); } for (RenderPass p : passes) { - if (prof != null) { - prof.fgStep(FgStep.Prepare, p.getProfilerName()); - } + if (prof != null) prof.fgStep(FgStep.Prepare, p.getProfilerName()); + if (cap != null) cap.prepareRenderPass(p.getIndex(), p.getProfilerName()); p.prepareRender(context); } // cull passes and resources @@ -200,9 +203,8 @@ public boolean execute() { context.pushRenderSettings(); for (RenderPass p : passes) { if (p.isUsed()) { - if (prof != null) { - prof.fgStep(FgStep.Execute, p.getProfilerName()); - } + if (prof != null) prof.fgStep(FgStep.Execute, p.getProfilerName()); + if (cap != null) cap.executeRenderPass(p.getIndex(), p.getProfilerName()); p.executeRender(context); context.popRenderSettings(); } @@ -211,9 +213,7 @@ public boolean execute() { // reset if (prof != null) prof.vpStep(VpStep.FrameGraphReset, vp, null); for (RenderPass p : passes) { - if (prof != null) { - prof.fgStep(FgStep.Reset, p.getProfilerName()); - } + if (prof != null) prof.fgStep(FgStep.Reset, p.getProfilerName()); p.resetRender(context); } // cleanup resources @@ -517,4 +517,9 @@ public FrameGraphData createData() { return new FrameGraphData(this, passes); } + @Override + public String toString() { + return "FrameGraph ("+name+")"; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index fe9f486e85..1f81d4c0cd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -32,7 +32,7 @@ package com.jme3.renderer.framegraph; import com.jme3.asset.AssetManager; -import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.framegraph.passes.DeferredPass; import com.jme3.renderer.framegraph.passes.GBufferPass; import com.jme3.renderer.framegraph.passes.OutputBucketPass; @@ -41,6 +41,7 @@ import com.jme3.renderer.framegraph.passes.RenderPass; import com.jme3.renderer.framegraph.passes.TileDeferredPass; import com.jme3.renderer.queue.RenderQueue; +import com.jme3.texture.Texture2D; /** * Utility class for constructing common framegraphs. @@ -82,12 +83,14 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { } else { deferred = fg.add(new TileDeferredPass()); } - OutputPass defOut = fg.add(new OutputPass()); + OutputPass defOut = fg.add(new OutputPass(0)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); fg.add(new PostProcessingPass()); fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); + Attribute gbufDebug = fg.add(new Attribute<>()); + gbufDebug.setName("GBufferDebug"); deferred.makeInput(gbuf, "Diffuse", "Diffuse"); deferred.makeInput(gbuf, "Specular", "Specular"); @@ -99,6 +102,8 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { defOut.makeInput(deferred, "Color", "Color"); defOut.makeInput(gbuf, "Depth", "Depth"); + gbufDebug.makeInput(gbuf, "Diffuse", "Value"); + return fg; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java index 90e6d339bf..831d5ae247 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java @@ -113,6 +113,15 @@ public void render(RenderManager rm, Texture2D color, Texture2D depth) { transferMat.getAdditionalRenderState().setDepthTest(writeDepth); transferMat.getAdditionalRenderState().setDepthWrite(writeDepth); render(rm, transferMat); + setAlphaDiscard(null); + } + } + + public void setAlphaDiscard(Float alphaDiscard) { + if (alphaDiscard == null) { + transferMat.clearParam("AlphaDiscard"); + } else { + transferMat.setFloat("AlphaDiscard", alphaDiscard); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index b7738650f1..eb5788f982 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -31,6 +31,8 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.debug.FGFrameCapture; import com.jme3.renderer.framegraph.definitions.ResourceDef; import java.util.HashMap; import java.util.Iterator; @@ -42,6 +44,7 @@ */ public class RenderObjectMap { + private final RenderManager renderManager; private final HashMap objectMap = new HashMap<>(); private final int timeout = 1; private int totalAllocations = 0; @@ -53,7 +56,9 @@ public class RenderObjectMap { private int totalObjects = 0; private int flushedObjects = 0; - public RenderObjectMap() {} + public RenderObjectMap(RenderManager renderManager) { + this.renderManager = renderManager; + } /** * Creates a new render object with a new internal object. @@ -103,6 +108,7 @@ public void allocate(RenderResource resource) { if (resource.isUndefined()) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); } + FGFrameCapture cap = renderManager.getFrameCapture(); totalAllocations++; ResourceDef def = resource.getDefinition(); if (def.isUseExisting()) { @@ -120,12 +126,15 @@ public void allocate(RenderResource resource) { } if (r != null) { resource.setObject(obj, r); + if (cap != null) cap.reallocateObject(id, resource.getIndex(), + resource.getResource().getClass().getSimpleName()); completedReservations++; objectsReallocated++; return; } } failedReservations++; + if (cap != null) cap.acquireSpecificFailed(id, resource.getIndex()); } // find object to allocate T indirectRes = null; @@ -135,6 +144,8 @@ public void allocate(RenderResource resource) { T r = def.applyDirectResource(obj.getObject()); if (r != null) { resource.setObject(obj, r); + if (cap != null) cap.reallocateObject(obj.getId(), resource.getIndex(), + resource.getResource().getClass().getSimpleName()); objectsReallocated++; return; } @@ -149,12 +160,16 @@ public void allocate(RenderResource resource) { if (indirectObj != null) { // allocate indirect object resource.setObject(indirectObj, indirectRes); + if (cap != null) cap.reallocateObject(indirectObj.getId(), resource.getIndex(), + resource.getResource().getClass().getSimpleName()); objectsReallocated++; return; } } // create new object resource.setObject(create(def)); + if (cap != null) cap.createObject(resource.getObject().getId(), + resource.getIndex(), resource.getResource().getClass().getSimpleName()); objectsCreated++; } /** @@ -171,6 +186,9 @@ public boolean reserve(long objectId, int index) { if (obj != null) { obj.reserve(index); officialReservations++; + if (renderManager.getFrameCapture() != null) { + renderManager.getFrameCapture().reserveObject(objectId, index); + } return true; } return false; @@ -205,6 +223,9 @@ public void dispose(RenderResource resource) { if (id >= 0) { RenderObject obj = objectMap.remove(id); if (obj != null) { + if (renderManager.getFrameCapture() != null) { + renderManager.getFrameCapture().disposeObject(id); + } obj.dispose(); } } @@ -237,9 +258,14 @@ public void clearReservations() { */ public void flushMap() { totalObjects = objectMap.size(); + if (renderManager.getFrameCapture() != null) { + renderManager.getFrameCapture().flushObjects(totalObjects); + } + FGFrameCapture cap = renderManager.getFrameCapture(); for (Iterator it = objectMap.values().iterator(); it.hasNext();) { RenderObject obj = it.next(); if (!obj.tickTimeout()) { + if (cap != null) cap.disposeObject(obj.getId()); obj.dispose(); it.remove(); flushedObjects++; @@ -247,6 +273,15 @@ public void flushMap() { } obj.setConstant(false); } + if (cap != null) { + cap.value("totalAllocations", totalAllocations); + cap.value("officialReservations", officialReservations); + cap.value("completedReservations", completedReservations); + cap.value("failedReservations", failedReservations); + cap.value("objectsCreated", objectsCreated); + cap.value("objectsReallocated", objectsReallocated); + cap.value("flushedObjects", flushedObjects); + } } /** * Clears the map. @@ -254,7 +289,9 @@ public void flushMap() { * All tracked render objects are disposed. */ public void clearMap() { + FGFrameCapture cap = renderManager.getFrameCapture(); for (RenderObject obj : objectMap.values()) { + if (cap != null) cap.disposeObject(obj.getId()); obj.dispose(); } objectMap.clear(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index a1a56d64d9..4fab78bc98 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -31,6 +31,8 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.debug.FGFrameCapture; import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture; @@ -46,7 +48,9 @@ public class ResourceList { private static final int INITIAL_SIZE = 20; + private RenderManager renderManager; private RenderObjectMap map; + private FGFrameCapture cap; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); private int nextSlot = 0; private int textureBinds = 0; @@ -158,7 +162,9 @@ protected RenderResource remove(int index) { * @return */ public ResourceTicket declare(ResourceProducer producer, ResourceDef def, ResourceTicket store) { - return create(producer, def).getTicket().copyIndexTo(store); + RenderResource resource = create(producer, def); + if (cap != null) cap.declareResource(resource.getIndex(), (store != null ? store.getName() : "")); + return resource.getTicket().copyIndexTo(store); } /** @@ -200,7 +206,9 @@ public void reserve(int passIndex, ResourceTicket... tickets) { * @param ticket */ public void reference(int passIndex, ResourceTicket ticket) { - locate(ticket).reference(passIndex); + RenderResource resource = locate(ticket); + resource.reference(passIndex); + if (cap != null) cap.referenceResource(resource.getIndex(), ticket.getName()); } /** * References the resource associated with the ticket if the ticket @@ -267,7 +275,9 @@ public > R getDefinition(Class type, ResourceTick * @param ticket */ public void setUndefined(ResourceTicket ticket) { - locate(ticket).setUndefined(); + RenderResource resource = locate(ticket); + resource.setUndefined(); + if (cap != null) cap.setResourceUndefined(resource.getIndex(), ticket.getName()); } /** @@ -281,6 +291,7 @@ public void setConstant(ResourceTicket ticket) { RenderObject obj = locate(ticket).getObject(); if (obj != null) { obj.setConstant(true); + if (cap != null) cap.setObjectConstant(obj.getId()); } } /** @@ -329,6 +340,7 @@ protected T acquire(RenderResource resource, ResourceTicket ticket) { if (resource.isVirtual()) { map.allocate(resource); } + if (cap != null) cap.acquireResource(resource.getIndex(), ticket.getName()); resource.getTicket().copyObjectTo(ticket); return resource.getResource(); } @@ -394,11 +406,13 @@ public void acquireColorTargets(FrameBuffer fbo, ResourceTicket)tickets[i]); if (acquired != existing) { fbo.setColorTarget(i, FrameBuffer.FrameBufferTarget.newTarget(acquired)); + if (cap != null) cap.bindTexture(tickets[i].getWorldIndex(), tickets[i].getName()); textureBinds++; } } for (; i < tickets.length; i++) { fbo.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(acquire(tickets[i]))); + if (cap != null) cap.bindTexture(tickets[i].getWorldIndex(), tickets[i].getName()); textureBinds++; } } @@ -420,6 +434,7 @@ public T acquireDepthTarget(FrameBuffer fbo, ResourceTicket< boolean unequalTargets = target != null && acquired != target.getTexture(); if (nullTarget || unequalTargets) { fbo.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(acquired)); + if (cap != null) cap.bindTexture(ticket.getWorldIndex(), ticket.getName()); textureBinds++; } return acquired; @@ -475,13 +490,19 @@ public T extractOrElse(ResourceTicket ticket, T value) { * @param ticket */ public void release(ResourceTicket ticket) { - RenderResource res = locate(ticket); - res.release(); - if (!res.isUsed()) { + RenderResource resource = locate(ticket); + resource.release(); + if (cap != null) { + cap.releaseResource(resource.getIndex(), ticket.getName()); + if (!resource.isUsed()) { + cap.releaseObject(resource.getObject().getId()); + } + } + if (!resource.isUsed()) { remove(ticket.getWorldIndex()); - res.setObject(null); - if (res.getDefinition().isDisposeOnRelease()) { - map.dispose(res); + resource.setObject(null); + if (resource.getDefinition().isDisposeOnRelease()) { + map.dispose(resource); } } } @@ -578,6 +599,10 @@ public void clear() { int size = resources.size(); resources = new ArrayList<>(size); nextSlot = 0; + if (cap != null) { + cap.clearResources(size); + cap.value("framebufferTextureBinds", textureBinds); + } } /** @@ -593,10 +618,12 @@ public int getTextureBinds() { /** * Sets the render object map. * - * @param map + * @param renderManager */ - public void setObjectMap(RenderObjectMap map) { - this.map = map; + public void setRenderManager(RenderManager renderManager) { + this.renderManager = renderManager; + this.map = this.renderManager.getRenderObjectMap(); + this.cap = this.renderManager.getFrameCapture(); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/FGFrameCapture.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/FGFrameCapture.java new file mode 100644 index 0000000000..088e7d23ee --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/FGFrameCapture.java @@ -0,0 +1,174 @@ +/* + * 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.debug; + +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.LinkedList; + +/** + * + * @author codex + */ +public class FGFrameCapture { + + private final File target; + private final LinkedList commands = new LinkedList<>(); + private int frame = 0; + private boolean includeNanos = true; + + public FGFrameCapture(File target) { + this.target = target; + } + + private void add(Event c) { + commands.addLast(c); + } + + public void renderFrame() { + add(new Event("StartRenderFrame", frame++)); + } + public void renderViewPort(ViewPort vp) { + Camera cam = vp.getCamera(); + add(new Event("StartViewPort", vp.getName(), cam.getWidth(), cam.getHeight())); + } + public void prepareRenderPass(int index, String name) { + commands.add(new Event("PrepareRenderPass", index, name)); + } + public void executeRenderPass(int index, String name) { + add(new Event("ExecuteRenderPass", index, name)); + } + + public void declareResource(int index, String ticket) { + add(new Event("DeclareResource", index, ticket)); + } + public void referenceResource(int index, String ticket) { + add(new Event("ReferenceResource", index, ticket)); + } + public void acquireResource(int index, String ticket) { + add(new Event("AcquireResource", index, ticket)); + } + public void setResourceUndefined(int index, String ticket) { + add(new Event("SetResourceUndefined", index, ticket)); + } + public void releaseResource(int index, String ticket) { + add(new Event("ReleaseResource", index, ticket)); + } + public void clearResources(int size) { + add(new Event("ClearResources", size)); + } + public void bindTexture(int index, String ticket) { + add(new Event("BindTexture", index, ticket)); + } + + public void reserveObject(long id, int index) { + add(new Event("ReserveObject", id, index)); + } + public void createObject(long id, int index, String type) { + add(new Event("CreateObject", id, index, type)); + } + public void reallocateObject(long id, int index, String type) { + add(new Event("ReallocateObject", id, index, type)); + } + public void acquireSpecificFailed(long id, int index) { + add(new Event("AcquireSpecificFailed", id, index)); + } + public void setObjectConstant(long id) { + add(new Event("SetObjectConstant", id)); + } + public void releaseObject(long id) { + add(new Event("ReleaseObject", id)); + } + public void disposeObject(long id) { + add(new Event("DisposeObject", id)); + } + public void flushObjects(int size) { + add(new Event("FlushObjects", size)); + } + + public void value(String name, Object value) { + add(new ValueEvent(name, value)); + } + + public void export() throws IOException { + if (target.exists()) { + target.delete(); + } + target.createNewFile(); + FileWriter writer = new FileWriter(target); + writer.write(commands.size()+" framegraph events over "+frame+" frames\n"); + for (Event e : commands) { + writer.write(e.toExportString(includeNanos)); + writer.write('\n'); + } + writer.close(); + } + + public void setIncludeNanos(boolean includeNanos) { + this.includeNanos = includeNanos; + } + + public boolean isIncludeNanos() { + return includeNanos; + } + + private class Event { + + protected final String operation; + protected final Object[] arguments; + protected final long startNanos; + + public Event(String operation, Object... arguments) { + this.operation = operation; + this.arguments = arguments; + this.startNanos = System.nanoTime(); + } + + public String getOperation() { + return operation; + } + public Object[] getArguments() { + return arguments; + } + + public String toExportString(boolean nanos) { + StringBuilder builder = new StringBuilder(); + builder.append("EVENT ") + .append(operation) + .append('('); + if (nanos) { + builder.append(nanos); + } + for (Object a : arguments) { + if (nanos) { + builder.append(','); + } + builder.append(a.toString()); + nanos = true; + } + return builder.append(')').toString(); + } + + } + private class ValueEvent extends Event { + + public ValueEvent(String field, Object value) { + super(field, value); + } + + @Override + public String toExportString(boolean nanos) { + StringBuilder builder = new StringBuilder(); + return builder.append("VALUE ") + .append(operation).append('=') + .append(arguments[0]).toString(); + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index ca982189dd..4dfea598e3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -60,9 +60,9 @@ public class TextureDef extends AbstractResourceDef imple private int samples = 1; private Image.Format format; private ColorSpace colorSpace = ColorSpace.Linear; - private Texture.MagFilter magFilter; - private Texture.MinFilter minFilter; - private Texture.ShadowCompareMode shadowCompare; + private Texture.MagFilter magFilter = Texture.MagFilter.Bilinear; + private Texture.MinFilter minFilter = Texture.MinFilter.BilinearNoMipMaps; + private Texture.ShadowCompareMode shadowCompare = Texture.ShadowCompareMode.Off; private Texture.WrapMode wrapS, wrapT, wrapR; private boolean formatFlexible = false; private boolean colorSpaceFlexible = false; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java index 42221501d8..f50e4f2a36 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java @@ -50,6 +50,7 @@ public class MatParamTargetControl extends AbstractControl implements GraphT private final String name; private final VarType type; + private ViewPort[] viewPorts; private Material material; private T value; @@ -85,11 +86,28 @@ public void setSpatial(Spatial spat) { } @Override public void setGraphValue(ViewPort viewPort, T value) { - this.value = value; + if (containsViewPort(viewPort)) { + this.value = value; + } + } + + private boolean containsViewPort(ViewPort vp) { + if (viewPorts == null) return true; + for (ViewPort p : viewPorts) { + if (p == vp) return true; + } + return false; + } + + public void setViewPorts(ViewPort... viewPorts) { + this.viewPorts = viewPorts; } public T getValue() { return value; } + public ViewPort[] getViewPorts() { + return viewPorts; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index d12a7d1a0d..0ea934c524 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -57,7 +57,7 @@ public class Attribute extends RenderPass implements Function { private ResourceTicket in, out; private T value; private ValueDef def; - private LinkedList> targets; + private final LinkedList> targets = new LinkedList<>(); private GraphSource source; @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 06988147d1..0210fc6941 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -35,6 +35,7 @@ import com.jme3.material.Material; import com.jme3.material.TechniqueDef; import com.jme3.material.logic.DeferredSinglePassLightingLogic; +import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; @@ -49,18 +50,18 @@ */ public class DeferredPass extends RenderPass { - private ResourceTicket depth, diffuse, specular, emissive, normal, outColor; + private ResourceTicket diffuse, specular, emissive, normal, depth, outColor; private ResourceTicket lights; private TextureDef colorDef; private Material material; @Override protected void initialize(FrameGraph frameGraph) { - depth = addInput("Depth"); diffuse = addInput("Diffuse"); specular = addInput("Specular"); emissive = addInput("Emissive"); normal = addInput("Normal"); + depth = addInput("Depth"); lights = addInput("Lights"); outColor = addOutput("Color"); colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); @@ -75,7 +76,7 @@ protected void prepare(FGRenderContext context) { colorDef.setSize(context.getWidth(), context.getHeight()); declare(colorDef, outColor); reserve(outColor); - reference(depth, diffuse, specular, emissive, normal); + reference(diffuse, specular, emissive, normal, depth); referenceOptional(lights); } @Override @@ -84,6 +85,7 @@ protected void execute(FGRenderContext context) { resources.acquireColorTargets(fb, outColor); context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); + context.getRenderer().setBackgroundColor(ColorRGBA.Blue); material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); material.setTexture("Context_InGBuff1", resources.acquire(specular)); material.setTexture("Context_InGBuff2", resources.acquire(emissive)); @@ -92,6 +94,7 @@ protected void execute(FGRenderContext context) { material.selectTechnique("DeferredPass", context.getRenderManager()); LightList lightList = resources.acquireOrElse(lights, null); context.getRenderer().setDepthRange(0, 1); + //context.renderFullscreen(material); if (lightList != null) { context.getScreen().render(context.getRenderManager(), material, lightList); } else { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index d027d42824..9799e6ed77 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -85,6 +85,7 @@ protected void initialize(FrameGraph frameGraph) { texDefs[4] = new TextureDef<>(Texture2D.class, tex, Image.Format.Depth); for (TextureDef d : texDefs) { d.setFormatFlexible(true); + //d.setUseExisting(false); } lightDef = new ValueDef(LightList.class, n -> new LightList(null)); lightDef.setReviser(list -> list.clear()); @@ -114,8 +115,7 @@ protected void execute(FGRenderContext context) { context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); LightList lightList = resources.acquire(lights); - // render to gBuffer - context.getRenderer().setBackgroundColor(mask.set(context.getViewPort().getBackgroundColor()).setAlpha(0)); + context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); context.getRenderManager().setForcedTechnique(GBUFFER_PASS); context.getRenderManager().setGeometryRenderHandler(this); context.renderViewPortQueue(RenderQueue.Bucket.Opaque, true); @@ -134,7 +134,6 @@ public boolean renderGeometry(RenderManager rm, Geometry geom) { if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null) { return false; } - System.out.println("render geometry"); rm.renderGeometry(geom); if (material.getActiveTechnique() != null) { LightList lts = geom.getFilterWorldLights(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java index 1b6b7fe851..7f724e5cd3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java @@ -31,10 +31,15 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.texture.Texture2D; +import java.io.IOException; /** * Renders a set of color and depth textures on a fullscreen quad to the @@ -45,6 +50,12 @@ public class OutputPass extends RenderPass { private ResourceTicket color, depth; + private float alphaDiscard = -1; + + public OutputPass() {} + public OutputPass(float alphaDiscard) { + this.alphaDiscard = alphaDiscard; + } @Override protected void initialize(FrameGraph frameGraph) { @@ -60,6 +71,9 @@ protected void execute(FGRenderContext context) { context.popFrameBuffer(); Texture2D colorTex = resources.acquireOrElse(color, null); Texture2D depthTex = resources.acquireOrElse(depth, null); + if (alphaDiscard >= 0) { + context.getScreen().setAlphaDiscard(alphaDiscard); + } context.transferTextures(colorTex, depthTex); } @Override @@ -70,5 +84,15 @@ protected void cleanup(FrameGraph frameGraph) {} public boolean isUsed() { return true; } + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(alphaDiscard, "AlphaDiscard", -1); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + alphaDiscard = in.readFloat("AlphaDiscard", -1); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 7bcefa7934..f0d0cfbacf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -507,6 +507,13 @@ public int getId() { public int getExportId() { return exportId; } + /** + * + * @return + */ + public int getIndex() { + return index; + } /** * Returns true if this pass is assigned to a framegraph. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index 71b4a6f511..16ba7b363f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java @@ -70,6 +70,7 @@ protected void initialize(FrameGraph frameGraph) { colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); colorDef.setFormatFlexible(true); material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"); + material = material.clone(); for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("TileBasedDeferredPass")) { t.setLogic(new TileBasedDeferredSinglePassLightingLogic(t, tileInfo)); } 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 4b564e0175..6158a16ba9 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -45,182 +45,179 @@ void main(){ float depth = texture2D(GBUFFER_DEPTH, texCoord).r; gl_FragDepth = depth; // 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, depth, 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 (shadingModelId == LEGACY_LIGHTING) { + vec3 vPos = getPosition(innerTexCoord, depth, 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 = m_NBLight; + #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) - float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f); - lightNum = m_NBLight; + spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, vec2(i * lightTexSizeInv, 0)), lightVec); #else - lightNum = NB_LIGHTS; + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); #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 + #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, depth, 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 indoorSunLightExposure = fract(shadingInfo.a) * 100.0f; - 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; + 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, depth, 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 indoorSunLightExposure = fract(shadingInfo.a) * 100.0f; + 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 = m_NBLight; + #else + lightNum = NB_LIGHTS; + #endif + gl_FragColor.rgb = vec3(0.0); + for( int i = 0;i < lightNum; ){ #if defined(USE_TEXTURE_PACK_MODE) - float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f); - lightNum = m_NBLight; + vec4 lightColor = texture2D(m_LightPackData1, vec2(i * lightTexSizeInv, 0)); + vec4 lightData1 = texture2D(m_LightPackData2, vec2(i * lightTexSizeInv, 0)); #else - lightNum = NB_LIGHTS; + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; #endif - gl_FragColor.rgb = vec3(0.0); - for( int i = 0;i < lightNum; ){ + 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) - vec4 lightColor = texture2D(m_LightPackData1, vec2(i * lightTexSizeInv, 0)); - vec4 lightData1 = texture2D(m_LightPackData2, vec2(i * lightTexSizeInv, 0)); + spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, vec2(i * lightTexSizeInv, 0)), lightVec); #else - vec4 lightColor = g_LightData[i]; - vec4 lightData1 = g_LightData[i+1]; + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); #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 - spotFallOff *= lightDir.w; + } + #endif + spotFallOff *= lightDir.w; - #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 + #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; + vec3 directDiffuse; + vec3 directSpecular; - float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir, - lightColor.rgb, fZero, Roughness, ndotv, - directDiffuse, directSpecular); + float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir, + lightColor.rgb, fZero, Roughness, ndotv, + directDiffuse, directSpecular); - vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular; + vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular; - gl_FragColor.rgb += directLighting * spotFallOff; - #if defined(USE_TEXTURE_PACK_MODE) - i++; - #else - i++; - #endif - } - // skyLight and reflectionProbe - 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; - } - else if(shadingModelId == SUBSURFACE_SCATTERING){ - // todo: + gl_FragColor.rgb += directLighting * spotFallOff; + #if defined(USE_TEXTURE_PACK_MODE) + i++; + #else + i++; + #endif } - } else if(shadingModelId == UNLIT) { + // skyLight and reflectionProbe + 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; + } else if (shadingModelId == SUBSURFACE_SCATTERING) { + // todo: + } else if (shadingModelId == UNLIT) { gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } else { discard; } - //discard; + if (innerTexCoord.y > 0.75) { + //discard; + } //gl_FragColor.a = 0.5; //gl_FragColor.a = 0.01; } diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag index 3a2a451ec0..7b1f093e9c 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag @@ -3,17 +3,13 @@ #ifdef WRITE_COLOR_MAP uniform sampler2D m_ColorMap; -#else - #ifdef WRITE_COLOR - uniform vec4 m_Color; + #ifdef ALPHA_DISCARD + uniform float m_AlphaDiscard; #endif #endif #ifdef WRITE_DEPTH uniform sampler2D m_DepthMap; #endif -#ifdef WRITE_ALPHA - uniform float m_Alpha; -#endif varying vec2 texCoord; @@ -21,12 +17,13 @@ void main() { #ifdef WRITE_COLOR_MAP gl_FragColor = texture2D(m_ColorMap, texCoord); - #else - #ifdef WRITE_COLOR - gl_FragColor = m_Color; - #else - gl_FragColor = vec4(0.0); + #ifdef ALPHA_DISCARD + if (gl_FragColor.a <= m_AlphaDiscard) { + discard; + } #endif + #else + gl_FragColor = vec4(0.0); #endif #ifdef WRITE_DEPTH @@ -35,9 +32,5 @@ void main() { gl_FragDepth = 1.0; #endif - #ifdef WRITE_ALPHA - gl_FragColor.a = m_Alpha; - #endif - } diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md index 528bafad9c..2f3560ee5d 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md @@ -3,8 +3,7 @@ MaterialDef TextureTransfer { MaterialParameters { Texture2D ColorMap Texture2D DepthMap - Color Color - Float Alpha + Float AlphaDiscard } Technique { @@ -22,9 +21,8 @@ MaterialDef TextureTransfer { Defines { WRITE_COLOR_MAP : ColorMap - WRITE_COLOR : Color WRITE_DEPTH : DepthMap - WRITE_ALPHA : Alpha + ALPHA_DISCARD : AlphaDiscard } } diff --git a/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib index b12bfe685d..a7d8715fae 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib @@ -1,9 +1,9 @@ // SHADING_MODEL // 0 is clearRT mask -#define LEGACY_LIGHTING 1 -#define STANDARD_LIGHTING 2 -#define UNLIT 3 -#define SUBSURFACE_SCATTERING 4 +#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) @@ -15,4 +15,4 @@ 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 +#endif diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 3a494c6551..701e21ee3c 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -37,7 +37,6 @@ import com.jme3.app.SimpleApplication; import com.jme3.asset.TextureKey; import com.jme3.environment.EnvironmentCamera; -import com.jme3.environment.EnvironmentProbeControl; import com.jme3.environment.LightProbeFactory; import com.jme3.environment.generation.JobProgressAdapter; import com.jme3.environment.util.EnvMapUtils; @@ -54,6 +53,10 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.FrameGraphFactory; +import com.jme3.renderer.framegraph.debug.FGFrameCapture; +import com.jme3.renderer.framegraph.io.MatParamTargetControl; +import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -62,6 +65,7 @@ import com.jme3.scene.instancing.InstancedGeometry; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; +import com.jme3.shader.VarType; import com.jme3.shadow.DirectionalLightShadowFilter; import com.jme3.system.AppSettings; import com.jme3.texture.Texture; @@ -69,6 +73,7 @@ import com.jme3.util.SkyFactory; import com.jme3.util.TangentBinormalGenerator; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; +import java.io.File; public class TestSimpleDeferredLighting extends SimpleApplication implements ActionListener { @@ -656,24 +661,37 @@ public void simpleInitApp() { stateManager.attach(new DetailedProfilerState()); //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - FrameGraph graph = new FrameGraph(assetManager, "Common/FrameGraphs/Deferred.j3g"); + FrameGraph forward = new FrameGraph(assetManager, "Common/FrameGraphs/Forward.j3g"); + forward.setName("forward"); + //FrameGraph deferred = new FrameGraph(assetManager, "Common/FrameGraphs/Deferred.j3g"); + FrameGraph deferred = FrameGraphFactory.deferred(assetManager, false); + deferred.setName("deferred1"); + FrameGraph deferred2 = FrameGraphFactory.deferred(assetManager, false); + deferred2.setName("deferred2"); //FrameGraph graph = FrameGraphFactory.forward(assetManager, renderManager); - //viewPort.setFrameGraph(graph); - renderManager.setFrameGraph(graph); + viewPort.setFrameGraph(deferred); + guiViewPort.setFrameGraph(deferred); + //renderManager.setFrameGraph(deferred); + renderManager.setFrameGraph(forward); + + File capTarget = new File(System.getProperty("user.home")+"/earlyFrameCapture.txt"); + FGFrameCapture cap = new FGFrameCapture(capTarget); + cap.setIncludeNanos(false); + renderManager.setFrameCapture(cap, 6); viewPort.setBackgroundColor(ColorRGBA.Green.mult(.1f)); - guiViewPort.setClearFlags(false, true, false); + guiViewPort.setBackgroundColor(ColorRGBA.Red.mult(.1f)); + //guiViewPort.setClearFlags(false, true, false); Geometry debugView = new Geometry("debug", new Quad(200, 200)); debugView.setLocalTranslation(0, 200, 0); Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - //debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); - //debugMat.setTransparent(true); debugView.setMaterial(debugMat); - //MatRenderParam texParam = new MatRenderParam("ColorMap", debugMat, VarType.Texture2D); - //texParam.enableDebug(); - //graph.bindToOutput(GBufferModule.RENDER_TARGETS[1], texParam); - //guiNode.attachChild(debugView); + MatParamTargetControl texTarget = new MatParamTargetControl("ColorMap", VarType.Texture2D); + texTarget.setViewPorts(viewPort); + deferred.get(Attribute.class, "GBufferDebug").addTarget(texTarget); + debugView.addControl(texTarget); + guiNode.attachChild(debugView); //renderManager.setRenderPath(currentRenderPath); testScene7(); @@ -690,7 +708,7 @@ public void simpleInitApp() { flyCam.setDragToRotate(true); flyCam.setMoveSpeed(50.0f); - rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); + //rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); registerInput(); } @@ -707,7 +725,7 @@ private void registerInput(){ } @Override - public void simpleUpdate(float tpf){ + public void simpleUpdate(float tpf) { if(sceneId == 1){ angle += tpf * 0.25f; angle %= FastMath.TWO_PI; @@ -727,7 +745,6 @@ else if(sceneId == 2){ // } } else if(sceneId == 9){ - frame++; if (frame == 2) { modelNode.removeFromParent(); From ce4b259ab520394953cddd29faa0cfb51fe4b41a Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 31 May 2024 08:30:10 -0400 Subject: [PATCH 076/111] fixed framebuffer update flag --- .../java/com/jme3/renderer/RenderManager.java | 36 +++-- .../renderer/framegraph/FGRenderContext.java | 8 +- .../jme3/renderer/framegraph/FrameGraph.java | 29 ++-- .../framegraph/FrameGraphFactory.java | 7 +- .../renderer/framegraph/RenderObject.java | 2 +- .../renderer/framegraph/RenderObjectMap.java | 103 +++++++++----- .../renderer/framegraph/ResourceList.java | 53 ++++--- ...ameCapture.java => GraphEventCapture.java} | 130 +++++++++++++++--- .../framegraph/io/MatParamTargetControl.java | 9 +- .../framegraph/passes/DeferredPass.java | 21 ++- .../framegraph/passes/GBufferPass.java | 22 ++- .../framegraph/passes/RenderPass.java | 27 +++- .../java/com/jme3/texture/FrameBuffer.java | 10 ++ .../java/jme3test/renderpath/TestRTT.java | 102 ++++++++++++++ .../TestSimpleDeferredLighting.java | 15 +- 15 files changed, 455 insertions(+), 119 deletions(-) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/{FGFrameCapture.java => GraphEventCapture.java} (53%) create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestRTT.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 753e451275..4ad97b3671 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.VpStep; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.RenderObjectMap; -import com.jme3.renderer.framegraph.debug.FGFrameCapture; +import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue.Bucket; @@ -95,7 +95,7 @@ public class RenderManager { private final RenderObjectMap renderObjects; private final LinkedList executedFrameGraphs = new LinkedList<>(); private FrameGraph frameGraph; - private FGFrameCapture frameCapture; + private GraphEventCapture graphCapture; private Camera prevCam = null; private Material forcedMaterial = null; private String forcedTechnique = null; @@ -168,11 +168,11 @@ public RenderObjectMap getRenderObjectMap() { * @param frameCapture * @param frames */ - public void setFrameCapture(FGFrameCapture frameCapture, int frames) { - this.frameCapture = frameCapture; + public void setGraphCapture(GraphEventCapture frameCapture, int frames) { + this.graphCapture = frameCapture; this.captureLifetime = frames; if (this.captureLifetime <= 0) { - this.frameCapture = null; + this.graphCapture = null; } } @@ -181,8 +181,8 @@ public void setFrameCapture(FGFrameCapture frameCapture, int frames) { * * @return */ - public FGFrameCapture getFrameCapture() { - return frameCapture; + public GraphEventCapture getGraphCapture() { + return graphCapture; } /** @@ -599,7 +599,7 @@ public void setForcedTechnique(String forcedTechnique) { * material or any overrides that exist in the scene graph that have the * same name. * - * @param override The override to add + * @param override The override to addEvent * @see MatParamOverride * @see #removeForcedMatParam(com.jme3.material.MatParamOverride) */ @@ -853,7 +853,7 @@ public void preloadScene(Spatial scene) { preloadScene(children.get(i)); } } else if (scene instanceof Geometry) { - // add to the render queue + // addEvent to the render queue Geometry gm = (Geometry) scene; if (gm.getMaterial() == null) { throw new IllegalStateException("No material is set for Geometry: " + gm.getName()); @@ -934,7 +934,7 @@ private void queueSubScene(Spatial scene, ViewPort vp) { queueSubScene(children.get(i), vp); } } else if (scene instanceof Geometry) { - // add to the render queue + // addEvent to the render queue Geometry gm = (Geometry) scene; if (gm.getMaterial() == null) { throw new IllegalStateException("No material is set for Geometry: " + gm.getName()); @@ -1414,6 +1414,10 @@ public void render(float tpf, boolean mainFrameBufferActive) { return; } + if (graphCapture != null) { + graphCapture.startRenderFrame(); + } + uniformBindingManager.newFrame(); renderObjects.newFrame(); @@ -1447,7 +1451,11 @@ public void render(float tpf, boolean mainFrameBufferActive) { } } - // call post frames for executed frame graphs only + if (graphCapture != null) { + graphCapture.endRenderFrame(); + } + + // cleanup for executed framegraphs only for (FrameGraph fg : executedFrameGraphs) { fg.renderingComplete(); } @@ -1457,13 +1465,13 @@ public void render(float tpf, boolean mainFrameBufferActive) { renderObjects.flushMap(); // tick frame capture - if (frameCapture != null && --captureLifetime <= 0) { + if (graphCapture != null && --captureLifetime <= 0) { try { - frameCapture.export(); + graphCapture.export(); } catch (IOException ex) { Logger.getLogger(RenderManager.class.getName()).log(Level.SEVERE, null, ex); } - frameCapture = null; + graphCapture = null; } } 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 1f12149116..4d63cc00ea 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 @@ -40,7 +40,7 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.debug.FGFrameCapture; +import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; @@ -245,8 +245,8 @@ public FullScreenQuad getScreen() { * * @return */ - public FGFrameCapture getFrameCapture() { - return renderManager.getFrameCapture(); + public GraphEventCapture getGraphCapture() { + return renderManager.getGraphCapture(); } /** * Gets the OpenCL context for compute shading. @@ -303,7 +303,7 @@ public boolean isProfilerAvailable() { * @return */ public boolean isFrameCaptureActive() { - return renderManager.getFrameCapture() != null; + return renderManager.getGraphCapture() != null; } } 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 477357ada2..198fab951e 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 @@ -41,7 +41,7 @@ import com.jme3.profile.VpStep; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.debug.FGFrameCapture; +import com.jme3.renderer.framegraph.debug.GraphEventCapture; import java.util.Iterator; import java.util.LinkedList; @@ -176,11 +176,8 @@ public boolean execute() { // prepare ViewPort vp = context.getViewPort(); AppProfiler prof = context.getProfiler(); - FGFrameCapture cap = context.getFrameCapture(); + GraphEventCapture cap = context.getGraphCapture(); if (cap != null) { - if (!rendered) { - cap.renderFrame(); - } cap.renderViewPort(context.getViewPort()); } if (prof != null) prof.vpStep(VpStep.FrameGraphSetup, vp, null); @@ -218,8 +215,12 @@ public boolean execute() { } // cleanup resources resources.clear(); - if (rendered) return false; - else return (rendered = true); + if (rendered) { + return false; + } else { + rendered = true; + return true; + } } /** * Should be called only when all rendering for the frame is complete. @@ -478,14 +479,16 @@ public final FrameGraph applyData(FrameGraphData data) { * * @param data * @return this instance - * @throws ClassCastException - * @throws NullPointerException + * @throws ClassCastException if the object is not an instance of {@link FrameGraphData}. + * @throws NullPointerException if the object is null */ public FrameGraph applyData(Object data) { - if (data != null && data instanceof FrameGraphData) { - return applyData((FrameGraphData)data); - } else if (data != null) { - throw new ClassCastException(data.getClass()+" cannot be cast to "+FrameGraphData.class); + if (data != null) { + if (data instanceof FrameGraphData) { + return applyData((FrameGraphData)data); + } else { + throw new ClassCastException(data.getClass()+" cannot be cast to "+FrameGraphData.class); + } } else { throw new NullPointerException("Proxy cannot be null"); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 1f81d4c0cd..5aa27e409f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -83,7 +83,7 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { } else { deferred = fg.add(new TileDeferredPass()); } - OutputPass defOut = fg.add(new OutputPass(0)); + //OutputPass defOut = fg.add(new OutputPass(0)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); @@ -98,9 +98,10 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { deferred.makeInput(gbuf, "Normal", "Normal"); deferred.makeInput(gbuf, "Depth", "Depth"); deferred.makeInput(gbuf, "Lights", "Lights"); + deferred.makeInput(gbuf, "NumRenders", "NumRenders"); - defOut.makeInput(deferred, "Color", "Color"); - defOut.makeInput(gbuf, "Depth", "Depth"); + //defOut.makeInput(deferred, "Color", "Color"); + //defOut.makeInput(gbuf, "Depth", "Depth"); gbufDebug.makeInput(gbuf, "Diffuse", "Value"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java index a6e87135da..f6978038e3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java @@ -55,7 +55,7 @@ public class RenderObject { private int timeoutDuration; private int timeout = 0; private boolean acquired = false; - private boolean constant = true; + private boolean constant = false; private Consumer disposer; /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index eb5788f982..fbcf9c3af1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -32,7 +32,7 @@ package com.jme3.renderer.framegraph; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.debug.FGFrameCapture; +import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.definitions.ResourceDef; import java.util.HashMap; import java.util.Iterator; @@ -46,7 +46,7 @@ public class RenderObjectMap { private final RenderManager renderManager; private final HashMap objectMap = new HashMap<>(); - private final int timeout = 1; + private final int timeout = 2; private int totalAllocations = 0; private int officialReservations = 0; private int completedReservations = 0; @@ -108,33 +108,12 @@ public void allocate(RenderResource resource) { if (resource.isUndefined()) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); } - FGFrameCapture cap = renderManager.getFrameCapture(); + GraphEventCapture cap = renderManager.getGraphCapture(); totalAllocations++; ResourceDef def = resource.getDefinition(); if (def.isUseExisting()) { - long id = resource.getTicket().getObjectId(); - // allocate reserved object - if (id >= 0) { - RenderObject obj = objectMap.get(id); - if (obj != null && isAvailable(obj) - && (obj.isReservedAt(resource.getLifeTime().getStartIndex()) - || !obj.isReservedWithin(resource.getLifeTime()))) { - // reserved object is only applied if it is accepted by the definition - T r = def.applyDirectResource(obj.getObject()); - if (r == null) { - r = def.applyIndirectResource(obj.getObject()); - } - if (r != null) { - resource.setObject(obj, r); - if (cap != null) cap.reallocateObject(id, resource.getIndex(), - resource.getResource().getClass().getSimpleName()); - completedReservations++; - objectsReallocated++; - return; - } - } - failedReservations++; - if (cap != null) cap.acquireSpecificFailed(id, resource.getIndex()); + if (allocateSpecific(resource)) { + return; } // find object to allocate T indirectRes = null; @@ -172,6 +151,62 @@ public void allocate(RenderResource resource) { resource.getIndex(), resource.getResource().getClass().getSimpleName()); objectsCreated++; } + /** + * Allocates the specific render object directly referenced by the resource, + * if one is referenced. + * + * @param + * @param resource + * @return true if the specific render object was allocated + */ + public boolean allocateSpecific(RenderResource resource) { + GraphEventCapture cap = renderManager.getGraphCapture(); + ResourceDef def = resource.getDefinition(); + long id = resource.getTicket().getObjectId(); + if (id < 0) return false; + // allocate reserved object + RenderObject obj = objectMap.get(id); + if (cap != null) cap.attemptReallocation(id, resource.getIndex()); + if (obj != null && isAvailable(obj) + && (obj.isReservedAt(resource.getLifeTime().getStartIndex()) + || !obj.isReservedWithin(resource.getLifeTime()))) { + // reserved object is only applied if it is accepted by the definition + T r = def.applyDirectResource(obj.getObject()); + if (r == null) { + r = def.applyIndirectResource(obj.getObject()); + } + if (r != null) { + resource.setObject(obj, r); + if (cap != null) cap.reallocateObject(id, resource.getIndex(), + resource.getResource().getClass().getSimpleName()); + completedReservations++; + objectsReallocated++; + return true; + } + } + failedReservations++; + if (cap != null) cap.allocateSpecificFailed(obj, resource); + return false; + } + /** + * Directly creates a new render object containing the value for the render + * resource. + *

      + * The object is still subject to the resource's definition, although the definition + * may not have created the internal value. + * + * @param + * @param resource + * @param value + */ + public void setDirect(RenderResource resource, T value) { + RenderObject object = create(resource.getDefinition(), value); + resource.setObject(object, value); + if (renderManager.getGraphCapture() != null) { + renderManager.getGraphCapture().setObjectDirect( + object.getId(), resource.getIndex(), value.getClass().getSimpleName()); + } + } /** * Makes a reservation of render object holding the specified id at the render * pass index so that no other resource may (without a reservation) use that @@ -186,8 +221,8 @@ public boolean reserve(long objectId, int index) { if (obj != null) { obj.reserve(index); officialReservations++; - if (renderManager.getFrameCapture() != null) { - renderManager.getFrameCapture().reserveObject(objectId, index); + if (renderManager.getGraphCapture() != null) { + renderManager.getGraphCapture().reserveObject(objectId, index); } return true; } @@ -223,8 +258,8 @@ public void dispose(RenderResource resource) { if (id >= 0) { RenderObject obj = objectMap.remove(id); if (obj != null) { - if (renderManager.getFrameCapture() != null) { - renderManager.getFrameCapture().disposeObject(id); + if (renderManager.getGraphCapture() != null) { + renderManager.getGraphCapture().disposeObject(id); } obj.dispose(); } @@ -258,10 +293,10 @@ public void clearReservations() { */ public void flushMap() { totalObjects = objectMap.size(); - if (renderManager.getFrameCapture() != null) { - renderManager.getFrameCapture().flushObjects(totalObjects); + if (renderManager.getGraphCapture() != null) { + renderManager.getGraphCapture().flushObjects(totalObjects); } - FGFrameCapture cap = renderManager.getFrameCapture(); + GraphEventCapture cap = renderManager.getGraphCapture(); for (Iterator it = objectMap.values().iterator(); it.hasNext();) { RenderObject obj = it.next(); if (!obj.tickTimeout()) { @@ -289,7 +324,7 @@ public void flushMap() { * All tracked render objects are disposed. */ public void clearMap() { - FGFrameCapture cap = renderManager.getFrameCapture(); + GraphEventCapture cap = renderManager.getGraphCapture(); for (RenderObject obj : objectMap.values()) { if (cap != null) cap.disposeObject(obj.getId()); obj.dispose(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 4fab78bc98..bd47a85305 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -32,7 +32,7 @@ package com.jme3.renderer.framegraph; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.framegraph.debug.FGFrameCapture; +import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture; @@ -50,7 +50,7 @@ public class ResourceList { private RenderManager renderManager; private RenderObjectMap map; - private FGFrameCapture cap; + private GraphEventCapture cap; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); private int nextSlot = 0; private int textureBinds = 0; @@ -119,7 +119,7 @@ protected boolean validate(ResourceTicket ticket) { protected int add(RenderResource res) { assert res != null; if (nextSlot >= resources.size()) { - // add resource to end of list + // addEvent resource to end of list resources.add(res); nextSlot++; return resources.size()-1; @@ -395,27 +395,34 @@ public T acquireOrElse(ResourceTicket ticket, T value) { public void acquireColorTargets(FrameBuffer fbo, ResourceTicket... tickets) { if (tickets.length == 0) { fbo.clearColorTargets(); + fbo.setUpdateNeeded(); return; } if (tickets.length < fbo.getNumColorTargets()) { fbo.trimColorTargetsTo(tickets.length-1); + fbo.setUpdateNeeded(); } int i = 0; for (int n = Math.min(fbo.getNumColorTargets(), tickets.length); i < n; i++) { - Texture existing = fbo.getColorTarget(i).getTexture(); - Texture acquired = acquire((ResourceTicket)tickets[i]); - if (acquired != existing) { - fbo.setColorTarget(i, FrameBuffer.FrameBufferTarget.newTarget(acquired)); - if (cap != null) cap.bindTexture(tickets[i].getWorldIndex(), tickets[i].getName()); - textureBinds++; - } + replaceColorTarget(fbo, tickets[i], i); } for (; i < tickets.length; i++) { - fbo.addColorTarget(FrameBuffer.FrameBufferTarget.newTarget(acquire(tickets[i]))); + fbo.addColorTarget(FrameBuffer.target(acquire(tickets[i]))); + fbo.setUpdateNeeded(); if (cap != null) cap.bindTexture(tickets[i].getWorldIndex(), tickets[i].getName()); textureBinds++; } } + private void replaceColorTarget(FrameBuffer fbo, ResourceTicket ticket, int i) { + Texture existing = fbo.getColorTarget(i).getTexture(); + Texture acquired = acquire(ticket); + if (acquired != existing) { + fbo.setColorTarget(i, FrameBuffer.target(acquired)); + fbo.setUpdateNeeded(); + if (cap != null) cap.bindTexture(ticket.getWorldIndex(), ticket.getName()); + textureBinds++; + } + } /** * Acquires and assigns a texture as the depth target to the framebuffer. *

      @@ -433,13 +440,25 @@ public T acquireDepthTarget(FrameBuffer fbo, ResourceTicket< boolean nullTarget = target == null; boolean unequalTargets = target != null && acquired != target.getTexture(); if (nullTarget || unequalTargets) { - fbo.setDepthTarget(FrameBuffer.FrameBufferTarget.newTarget(acquired)); + fbo.setDepthTarget(FrameBuffer.target(acquired)); + fbo.setUpdateNeeded(); if (cap != null) cap.bindTexture(ticket.getWorldIndex(), ticket.getName()); textureBinds++; } return acquired; } + /** + * Directly assign the resource associated with the ticket to the value. + * + * @param + * @param ticket + * @param value + */ + public void setDirect(ResourceTicket ticket, T value) { + map.setDirect(locate(ticket), value); + } + protected T extract(RenderResource resource, ResourceTicket ticket) { if (!resource.isUsed()) { throw new IllegalStateException(resource+" was unexpectedly extracted."); @@ -492,13 +511,11 @@ public T extractOrElse(ResourceTicket ticket, T value) { public void release(ResourceTicket ticket) { RenderResource resource = locate(ticket); resource.release(); - if (cap != null) { - cap.releaseResource(resource.getIndex(), ticket.getName()); - if (!resource.isUsed()) { + if (cap != null) cap.releaseResource(resource.getIndex(), ticket.getName()); + if (!resource.isUsed()) { + if (cap != null && resource.getObject() != null) { cap.releaseObject(resource.getObject().getId()); } - } - if (!resource.isUsed()) { remove(ticket.getWorldIndex()); resource.setObject(null); if (resource.getDefinition().isDisposeOnRelease()) { @@ -623,7 +640,7 @@ public int getTextureBinds() { public void setRenderManager(RenderManager renderManager) { this.renderManager = renderManager; this.map = this.renderManager.getRenderObjectMap(); - this.cap = this.renderManager.getFrameCapture(); + this.cap = this.renderManager.getGraphCapture(); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/FGFrameCapture.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java similarity index 53% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/FGFrameCapture.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java index 088e7d23ee..b8dfce73d3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/FGFrameCapture.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java @@ -6,43 +6,56 @@ import com.jme3.renderer.Camera; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.RenderObject; +import com.jme3.renderer.framegraph.RenderResource; +import com.jme3.texture.FrameBuffer; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.LinkedList; +import java.util.function.Supplier; /** * * @author codex */ -public class FGFrameCapture { +public class GraphEventCapture { private final File target; - private final LinkedList commands = new LinkedList<>(); + private final LinkedList events = new LinkedList<>(); private int frame = 0; private boolean includeNanos = true; - public FGFrameCapture(File target) { + public GraphEventCapture(File target) { this.target = target; } private void add(Event c) { - commands.addLast(c); + events.addLast(c); + } + public void addEvent(String operation, Object... arguments) { + add(new Event(operation, arguments)); } - public void renderFrame() { - add(new Event("StartRenderFrame", frame++)); + public void startRenderFrame() { + add(new SuperEvent("StartRenderFrame", frame)); + } + public void endRenderFrame() { + add(new SuperEvent("EndRenderFrame", frame++)); } public void renderViewPort(ViewPort vp) { Camera cam = vp.getCamera(); - add(new Event("StartViewPort", vp.getName(), cam.getWidth(), cam.getHeight())); + add(new SuperEvent("StartViewPort", vp.getName(), cam.getWidth(), cam.getHeight())); } public void prepareRenderPass(int index, String name) { - commands.add(new Event("PrepareRenderPass", index, name)); + events.add(new Event("PrepareRenderPass", index, name)); } public void executeRenderPass(int index, String name) { add(new Event("ExecuteRenderPass", index, name)); } + public void createFrameBuffer(FrameBuffer fb) { + add(new Event("CreateFrameBuffer", fb.getWidth(), fb.getHeight(), fb.getSamples())); + } public void declareResource(int index, String ticket) { add(new Event("DeclareResource", index, ticket)); @@ -72,11 +85,23 @@ public void reserveObject(long id, int index) { public void createObject(long id, int index, String type) { add(new Event("CreateObject", id, index, type)); } + public void setObjectDirect(long id, int index, String type) { + add(new Event("SetObjectDirect", id, index, type)); + } public void reallocateObject(long id, int index, String type) { add(new Event("ReallocateObject", id, index, type)); } - public void acquireSpecificFailed(long id, int index) { - add(new Event("AcquireSpecificFailed", id, index)); + public void attemptReallocation(long id, int index) { + add(new Event("AttemptSpecificReallocation", id, index)); + } + public void allocateSpecificFailed(RenderObject object, RenderResource resource) { + add(new Failure("AllocateSpecific", + new Check("nullObject", () -> object != null, true), + new Check("acquired", () -> !object.isAcquired()), + new Check("constant", () -> !object.isConstant()), + new Check("conflicting", () -> object.isReservedAt(resource.getLifeTime().getStartIndex()) + || !object.isReservedWithin(resource.getLifeTime())) + )); } public void setObjectConstant(long id) { add(new Event("SetObjectConstant", id)); @@ -92,7 +117,7 @@ public void flushObjects(int size) { } public void value(String name, Object value) { - add(new ValueEvent(name, value)); + add(new Value(name, value)); } public void export() throws IOException { @@ -101,8 +126,8 @@ public void export() throws IOException { } target.createNewFile(); FileWriter writer = new FileWriter(target); - writer.write(commands.size()+" framegraph events over "+frame+" frames\n"); - for (Event e : commands) { + writer.write(events.size()+" framegraph events over "+frame+" frames\n"); + for (Event e : events) { writer.write(e.toExportString(includeNanos)); writer.write('\n'); } @@ -138,7 +163,8 @@ public Object[] getArguments() { public String toExportString(boolean nanos) { StringBuilder builder = new StringBuilder(); - builder.append("EVENT ") + builder.append(getEventType()) + .append(" ") .append(operation) .append('('); if (nanos) { @@ -153,21 +179,91 @@ public String toExportString(boolean nanos) { } return builder.append(')').toString(); } + public String getEventType() { + return "EVENT"; + } + + } + private class SuperEvent extends Event { + + public SuperEvent(String operation, Object... arguments) { + super(operation, arguments); + } + + @Override + public String getEventType() { + return "SUPEREVENT"; + } } - private class ValueEvent extends Event { + private class Value extends Event { - public ValueEvent(String field, Object value) { + public Value(String field, Object value) { super(field, value); } @Override public String toExportString(boolean nanos) { StringBuilder builder = new StringBuilder(); - return builder.append("VALUE ") + return builder.append(getEventType()).append(" ") .append(operation).append('=') .append(arguments[0]).toString(); } + @Override + public String getEventType() { + return "VALUE"; + } + + } + private class Failure extends Event { + + public Failure(String operation, Check... checks) { + super(operation, new Object[checks.length]); + int i = 0; + for (; i < checks.length; i++) { + boolean success = checks[i].run(); + if (!success) { + arguments[i] = checks[i].name; + if (checks[i].terminal) { + break; + } + continue; + } + arguments[i] = '-'; + } + for (; i < checks.length; i++) { + arguments[i] = '?'; + } + } + + @Override + public String getEventType() { + return "FAILURE"; + } + + } + + private class Check { + + private final String name; + private final Supplier check; + private final boolean terminal; + + public Check(String name, Supplier check) { + this(name, check, false); + } + public Check(String name, Supplier check, boolean terminal) { + this.name = name; + this.check = check; + this.terminal = terminal; + } + + public boolean run() { + return check.get(); + } + public String asArgument(boolean b) { + return name+"="+b; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java index f50e4f2a36..e7a97c0cb1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java @@ -61,8 +61,10 @@ public MatParamTargetControl(String name, VarType type) { @Override protected void controlUpdate(float tpf) { + //System.out.println("check: assign to material?"); if (value != null) { - material.setParam(name, type, value); + //System.out.println("assign "+value.getClass().getSimpleName()+" to material"); + //material.setParam(name, type, value); } } @Override @@ -88,6 +90,11 @@ public void setSpatial(Spatial spat) { public void setGraphValue(ViewPort viewPort, T value) { if (containsViewPort(viewPort)) { this.value = value; + if (this.value != null) { + material.setParam(name, type, this.value); + } else { + material.clearParam(name); + } } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 0210fc6941..72c8460c0b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -52,6 +52,7 @@ public class DeferredPass extends RenderPass { private ResourceTicket diffuse, specular, emissive, normal, depth, outColor; private ResourceTicket lights; + private ResourceTicket numRenders; private TextureDef colorDef; private Material material; @@ -63,6 +64,7 @@ protected void initialize(FrameGraph frameGraph) { normal = addInput("Normal"); depth = addInput("Depth"); lights = addInput("Lights"); + numRenders = addInput("NumRenders"); outColor = addOutput("Color"); colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); colorDef.setFormatFlexible(true); @@ -77,15 +79,19 @@ protected void prepare(FGRenderContext context) { declare(colorDef, outColor); reserve(outColor); reference(diffuse, specular, emissive, normal, depth); - referenceOptional(lights); + referenceOptional(lights, numRenders); } @Override protected void execute(FGRenderContext context) { FrameBuffer fb = getFrameBuffer(context, 1); + //if (resources.acquireOrElse(numRenders, 1) == 0) { + // return; + //} resources.acquireColorTargets(fb, outColor); - context.getRenderer().setFrameBuffer(fb); - context.getRenderer().clearBuffers(true, true, true); - context.getRenderer().setBackgroundColor(ColorRGBA.Blue); + context.popFrameBuffer(); + //context.getRenderer().setFrameBuffer(fb); + //context.getRenderer().clearBuffers(true, true, true); + //context.getRenderer().setBackgroundColor(ColorRGBA.Blue.clone().setAlpha(0)); material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); material.setTexture("Context_InGBuff1", resources.acquire(specular)); material.setTexture("Context_InGBuff2", resources.acquire(emissive)); @@ -93,8 +99,9 @@ protected void execute(FGRenderContext context) { material.setTexture("Context_InGBuff4", resources.acquire(depth)); material.selectTechnique("DeferredPass", context.getRenderManager()); LightList lightList = resources.acquireOrElse(lights, null); - context.getRenderer().setDepthRange(0, 1); + //context.getRenderer().setDepthRange(0, 1); //context.renderFullscreen(material); + //context.getScreen().setAlphaDiscard(0f); if (lightList != null) { context.getScreen().render(context.getRenderManager(), material, lightList); } else { @@ -105,5 +112,9 @@ protected void execute(FGRenderContext context) { protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} + @Override + public boolean isUsed() { + return true; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 9799e6ed77..25c9f154c7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -46,6 +46,7 @@ import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; +import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; import java.util.LinkedList; import java.util.function.Function; @@ -64,10 +65,13 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private ResourceTicket diffuse, specular, emissive, normal, depth; private ResourceTicket lights; + private ResourceTicket numRendersTicket; private ValueDef lightDef; + private ValueDef numRendersDef; private final TextureDef[] texDefs = new TextureDef[5]; private final LinkedList accumulatedLights = new LinkedList<>(); - private final ColorRGBA mask = new ColorRGBA(); + private Texture2D diffuseTex; + private int numRenders = 0; @Override protected void initialize(FrameGraph frameGraph) { @@ -77,23 +81,34 @@ protected void initialize(FrameGraph frameGraph) { normal = addOutput("Normal"); depth = addOutput("Depth"); lights = addOutput("Lights"); + numRendersTicket = addOutput("NumRenders"); Function tex = img -> new Texture2D(img); texDefs[0] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); texDefs[1] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); texDefs[2] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); texDefs[3] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA32F); texDefs[4] = new TextureDef<>(Texture2D.class, tex, Image.Format.Depth); + int i = -1; for (TextureDef d : texDefs) { + i++; d.setFormatFlexible(true); //d.setUseExisting(false); + //d.setDisposeOnRelease(true); + //d.setStaticTimeout(0); } lightDef = new ValueDef(LightList.class, n -> new LightList(null)); lightDef.setReviser(list -> list.clear()); + numRendersDef = new ValueDef(Boolean.class, n -> true); + numRendersDef.setUseExisting(false); + numRendersDef.setDisposeOnRelease(true); } @Override protected void prepare(FGRenderContext context) { int w = context.getWidth(); int h = context.getHeight(); + if (diffuseTex == null || diffuseTex.getImage().getWidth() != w || diffuseTex.getImage().getHeight() != h) { + diffuseTex = new Texture2D(w, h, Image.Format.RGBA16F); + } for (TextureDef d : texDefs) { d.setSize(w, h); } @@ -103,13 +118,16 @@ protected void prepare(FGRenderContext context) { declare(texDefs[3], normal); declare(texDefs[4], depth); declare(lightDef, lights); + declare(numRendersDef, numRendersTicket); reserve(diffuse, specular, emissive, normal, depth, lights); + numRenders = 0; } @Override protected void execute(FGRenderContext context) { // acquire texture targets FrameBuffer fb = getFrameBuffer(context, 1); fb.setMultiTarget(true); + //resources.setDirect(diffuse, diffuseTex); resources.acquireColorTargets(fb, diffuse, specular, emissive, normal); resources.acquireDepthTarget(fb, depth); context.getRenderer().setFrameBuffer(fb); @@ -123,6 +141,7 @@ protected void execute(FGRenderContext context) { while (!accumulatedLights.isEmpty()) { lightList.add(accumulatedLights.pollFirst()); } + resources.setDirect(numRendersTicket, numRenders); } @Override protected void reset(FGRenderContext context) {} @@ -135,6 +154,7 @@ public boolean renderGeometry(RenderManager rm, Geometry geom) { return false; } rm.renderGeometry(geom); + numRenders++; if (material.getActiveTechnique() != null) { LightList lts = geom.getFilterWorldLights(); for (Light l : lts) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index f0d0cfbacf..2229822c88 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -36,11 +36,14 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceList; import com.jme3.renderer.framegraph.ResourceProducer; import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import java.io.IOException; @@ -388,12 +391,13 @@ public void disconnectFrom(RenderPass pass) { * If no existing framebuffer matches, a new framebuffer will be created * and returned. * + * @param cap graph event capturer, for debugging, may be null. * @param width * @param height * @param samples * @return */ - protected FrameBuffer getFrameBuffer(int width, int height, int samples) { + protected FrameBuffer getFrameBuffer(GraphEventCapture cap, int width, int height, int samples) { for (PassFrameBuffer fb : frameBuffers) { if (fb.qualifies(width, height, samples)) { return fb.use(); @@ -401,20 +405,35 @@ protected FrameBuffer getFrameBuffer(int width, int height, int samples) { } PassFrameBuffer fb = new PassFrameBuffer(width, height, samples); frameBuffers.add(fb); + if (cap != null) cap.createFrameBuffer(fb.frameBuffer); return fb.use(); } + /** + * Gets an existing framebuffer that matches the given properties. + *

      + * In no existing framebuffer matches, a new framebuffer will be created + * and returned. + * + * @param width + * @param height + * @param samples + * @return + */ + protected FrameBuffer getFrameBuffer(int width, int height, int samples) { + return getFrameBuffer(null, width, height, samples); + } /** * Gets an existing framebuffer that matches the context. *

      * If no existing framebuffer matches, a new framebuffer will be created - * and returned. + * and returned. Uses event capturing if available. * * @param context * @param samples * @return */ protected FrameBuffer getFrameBuffer(FGRenderContext context, int samples) { - return getFrameBuffer(context.getWidth(), context.getHeight(), samples); + return getFrameBuffer(context.getGraphCapture(), context.getWidth(), context.getHeight(), samples); } /** @@ -446,7 +465,7 @@ public void shiftExecutionIndex(int threshold, boolean positive) { * * @param shift */ - public void shiftId(long shift) { + public void shiftId(int shift) { id += shift; } /** diff --git a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java index f1a9a97140..4403a758c9 100644 --- a/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java +++ b/jme3-core/src/main/java/com/jme3/texture/FrameBuffer.java @@ -249,6 +249,16 @@ public static FrameBufferTextureTarget newTarget(Texture tx, TextureCubeMap.Face return t; } } + + public static FrameBufferTextureTarget target(Texture tx) { + return FrameBufferTarget.newTarget(tx); + } + public static FrameBufferBufferTarget target(Format format) { + return FrameBufferTarget.newTarget(format); + } + public static FrameBufferTextureTarget target(Texture tx, TextureCubeMap.Face face) { + return FrameBufferTarget.newTarget(tx, face); + } /** * A private constructor to inhibit instantiation of this class. diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRTT.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRTT.java new file mode 100644 index 0000000000..0e1f79bddc --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestRTT.java @@ -0,0 +1,102 @@ +/* + * 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; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Quad; +import com.jme3.system.AppSettings; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import java.util.LinkedList; + +/** + * Temporary test to narrow down a bug involving render to texture. + * + * @author codex + */ +public class TestRTT extends SimpleApplication { + + private FrameBuffer fbo; + private Material targetMat1, targetMat2, targetMat3; + private Texture targetTex; + private final LinkedList stack = new LinkedList<>(); + private final int frameDelay = 50; + private int frame = frameDelay; + + private static final int w = 768, h = 768; + + public static void main(String[] args) { + TestRTT app = new TestRTT(); + AppSettings settings = new AppSettings(true); + settings.setWidth(w); + settings.setHeight(h); + app.setSettings(settings); + app.start(); + } + + @Override + public void simpleInitApp() { + + flyCam.setDragToRotate(true); + guiViewPort.setClearFlags(true, true, true); + guiViewPort.setBackgroundColor(ColorRGBA.Green.mult(.05f)); + + fbo = new FrameBuffer(w, h, 1); + viewPort.setOutputFrameBuffer(fbo); + + Geometry g = new Geometry("box", new Box(1, 1, 1)); + Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + m.setColor("Color", ColorRGBA.Blue); + g.setMaterial(m); + rootNode.attachChild(g); + + Geometry quad1 = new Geometry("quad1", new Quad(300, 300)); + quad1.setLocalTranslation(70, 410, 0); + targetMat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + quad1.setMaterial(targetMat1); + guiNode.attachChild(quad1); + + Geometry quad2 = new Geometry("quad2", new Quad(300, 300)); + quad2.setLocalTranslation(380, 410, 0); + targetMat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + quad2.setMaterial(targetMat2); + guiNode.attachChild(quad2); + + Geometry quad3 = new Geometry("quad3", new Quad(300, 300)); + quad3.setLocalTranslation(310, 50, 0); + targetMat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + quad3.setMaterial(targetMat3); + guiNode.attachChild(quad3); + + stack.add(new Texture2D(w, h, Image.Format.RGBA8)); + stack.add(new Texture2D(w, h, Image.Format.RGBA8)); + + } + @Override + public void simpleUpdate(float tpf) { + if (frame++ >= frameDelay) { + frame = 0; + if (targetTex == stack.getFirst()) { + targetTex = stack.getLast(); + } else { + targetTex = stack.getFirst(); + } + targetMat1.setTexture("ColorMap", stack.getFirst()); + targetMat2.setTexture("ColorMap", stack.getLast()); + targetMat3.setTexture("ColorMap", targetTex); + fbo.clearColorTargets(); + fbo.addColorTarget(FrameBuffer.target(targetTex)); + // this fixes the entire issue + fbo.setUpdateNeeded(); + } + } + +} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 701e21ee3c..25f7716105 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -54,7 +54,7 @@ import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; -import com.jme3.renderer.framegraph.debug.FGFrameCapture; +import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.io.MatParamTargetControl; import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.queue.RenderQueue; @@ -659,6 +659,7 @@ private void testScene11(){ public void simpleInitApp() { stateManager.attach(new DetailedProfilerState()); + //guiViewPort.setEnabled(false); //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); FrameGraph forward = new FrameGraph(assetManager, "Common/FrameGraphs/Forward.j3g"); @@ -672,17 +673,23 @@ public void simpleInitApp() { viewPort.setFrameGraph(deferred); guiViewPort.setFrameGraph(deferred); //renderManager.setFrameGraph(deferred); - renderManager.setFrameGraph(forward); + //renderManager.setFrameGraph(forward); File capTarget = new File(System.getProperty("user.home")+"/earlyFrameCapture.txt"); - FGFrameCapture cap = new FGFrameCapture(capTarget); + GraphEventCapture cap = new GraphEventCapture(capTarget); cap.setIncludeNanos(false); - renderManager.setFrameCapture(cap, 6); + renderManager.setGraphCapture(cap, 6); viewPort.setBackgroundColor(ColorRGBA.Green.mult(.1f)); guiViewPort.setBackgroundColor(ColorRGBA.Red.mult(.1f)); //guiViewPort.setClearFlags(false, true, false); + //Camera myCam = cam.clone(); + //ViewPort vp = renderManager.createPostView("myPostView", myCam); + //vp.setClearFlags(false, true, false); + //vp.attachScene(rootNode); + //vp.setFrameGraph(deferred); + Geometry debugView = new Geometry("debug", new Quad(200, 200)); debugView.setLocalTranslation(0, 200, 0); Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); From 55941843b3007bb15562959d4e5d645d17735efa Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 3 Jun 2024 08:18:32 -0400 Subject: [PATCH 077/111] fixed broken light count --- .../DeferredSinglePassLightingLogic.java | 19 ++- .../java/com/jme3/renderer/RenderManager.java | 6 +- .../renderer/framegraph/FGRenderContext.java | 2 +- .../framegraph/FrameGraphFactory.java | 14 +- .../renderer/framegraph/RenderObjectMap.java | 23 ++- .../renderer/framegraph/ResourceList.java | 10 +- .../framegraph/debug/GraphEventCapture.java | 73 ++++----- .../framegraph/definitions/TextureDef.java | 4 + .../renderer/framegraph/io/GraphTarget.java | 3 +- .../framegraph/io/MatParamTargetControl.java | 4 +- .../renderer/framegraph/passes/Attribute.java | 15 +- .../framegraph/passes/BucketPass.java | 2 +- .../framegraph/passes/DeferredPass.java | 20 ++- .../framegraph/passes/GBufferPass.java | 11 +- .../framegraph/passes/OutputPass.java | 15 +- .../ShadingCommon/DeferredShading.frag | 139 +++++++++--------- .../ShadingCommon/TextureTransfer.frag | 7 + .../ShadingCommon/TextureTransfer.j3md | 2 + .../TestSimpleDeferredLighting.java | 10 +- 19 files changed, 220 insertions(+), 159 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 79efc3ccbf..372676f64b 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 @@ -472,7 +472,7 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry int numLights = 0; Renderer renderer = renderManager.getRenderer(); boolean isLightCullStageDraw = false; - if(geometry.getUserData(LIGHT_CULL_DRAW_STAGE) != null){ + if (geometry.getUserData(LIGHT_CULL_DRAW_STAGE) != null) { isLightCullStageDraw = geometry.getUserData(LIGHT_CULL_DRAW_STAGE); } // todo: One optimization approach here is: @@ -501,25 +501,30 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry // Uniform lightCount = shader.getUniform("g_LightCount"); // lightCount.setValue(VarType.Int, count); // lightCount.setValue(VarType.Int, this.lightNum); - geometry.getMaterial().setInt("NBLight", count); - if(count == 0){ - numLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, numLights, isLightCullStageDraw, lastBindUnit.textureUnit); + // Note: setting the light count here makes the new value miss the render + //geometry.getMaterial().setInt("NBLight", count); + if (count == 0) { + updateLightListPackToTexture(shader, geometry, lights, count, + renderManager, numLights, isLightCullStageDraw, lastBindUnit.textureUnit); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } else while (numLights < 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) - numLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, numLights, isLightCullStageDraw, lastBindUnit.textureUnit); + numLights = updateLightListPackToTexture(shader, geometry, lights, count, + renderManager, numLights, isLightCullStageDraw, lastBindUnit.textureUnit); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } } else { int batchSize = renderManager.getSinglePassLightBatchSize(); if (lights.size() == 0) { - updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, 0, isLightCullStageDraw); + updateLightListUniforms(shader, geometry, lights, batchSize, + renderManager, 0, isLightCullStageDraw); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } else while (numLights < lights.size()) { - numLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, numLights, isLightCullStageDraw); + numLights = updateLightListUniforms(shader, geometry, lights, batchSize, + renderManager, numLights, isLightCullStageDraw); renderer.setShader(shader); renderMeshFromGeometry(renderer, geometry); } 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 4ad97b3671..4040e42383 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -599,7 +599,7 @@ public void setForcedTechnique(String forcedTechnique) { * material or any overrides that exist in the scene graph that have the * same name. * - * @param override The override to addEvent + * @param override The override to addUserEvent * @see MatParamOverride * @see #removeForcedMatParam(com.jme3.material.MatParamOverride) */ @@ -853,7 +853,7 @@ public void preloadScene(Spatial scene) { preloadScene(children.get(i)); } } else if (scene instanceof Geometry) { - // addEvent to the render queue + // addUserEvent to the render queue Geometry gm = (Geometry) scene; if (gm.getMaterial() == null) { throw new IllegalStateException("No material is set for Geometry: " + gm.getName()); @@ -934,7 +934,7 @@ private void queueSubScene(Spatial scene, ViewPort vp) { queueSubScene(children.get(i), vp); } } else if (scene instanceof Geometry) { - // addEvent to the render queue + // addUserEvent to the render queue Geometry gm = (Geometry) scene; if (gm.getMaterial() == null) { throw new IllegalStateException("No material is set for Geometry: " + gm.getName()); 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 4d63cc00ea..ce97e08b5b 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 @@ -167,7 +167,7 @@ public void renderFullscreen(Material mat) { * @param color color texture, or null * @param depth depth texture, or null */ - public void transferTextures(Texture2D color, Texture2D depth) { + public void renderTextures(Texture2D color, Texture2D depth) { screen.render(renderManager, color, depth); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 5aa27e409f..e70906d69d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -83,12 +83,12 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { } else { deferred = fg.add(new TileDeferredPass()); } - //OutputPass defOut = fg.add(new OutputPass(0)); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); + OutputPass defOut = fg.add(new OutputPass(0f)); +// fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); +// fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); - fg.add(new PostProcessingPass()); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); +// fg.add(new PostProcessingPass()); +// fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); Attribute gbufDebug = fg.add(new Attribute<>()); gbufDebug.setName("GBufferDebug"); @@ -100,8 +100,8 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { deferred.makeInput(gbuf, "Lights", "Lights"); deferred.makeInput(gbuf, "NumRenders", "NumRenders"); - //defOut.makeInput(deferred, "Color", "Color"); - //defOut.makeInput(gbuf, "Depth", "Depth"); + defOut.makeInput(deferred, "Color", "Color"); + defOut.makeInput(gbuf, "Depth", "Depth"); gbufDebug.makeInput(gbuf, "Diffuse", "Value"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index fbcf9c3af1..ae99d7e585 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -46,7 +46,9 @@ public class RenderObjectMap { private final RenderManager renderManager; private final HashMap objectMap = new HashMap<>(); - private final int timeout = 2; + private final int timeout = 1; + + // statistics private int totalAllocations = 0; private int officialReservations = 0; private int completedReservations = 0; @@ -199,7 +201,7 @@ public boolean allocateSpecific(RenderResource resource) { * @param resource * @param value */ - public void setDirect(RenderResource resource, T value) { + public void allocateDirect(RenderResource resource, T value) { RenderObject object = create(resource.getDefinition(), value); resource.setObject(object, value); if (renderManager.getGraphCapture() != null) { @@ -248,6 +250,19 @@ public T extract(RenderResource resource) { RenderObject obj = objectMap.remove(resource.getTicket().getObjectId()); return (obj != null ? obj.getObject() : null); } + /** + * Removes the render object holding the given value from the map. + * + * @param value + */ + public void remove(Object value) { + for (Iterator it = objectMap.values().iterator(); it.hasNext();) { + RenderObject object = it.next(); + if (object.getObject() == value) { + it.remove(); + } + } + } /** * Disposes the render object pointed to by the resource. * @@ -293,10 +308,8 @@ public void clearReservations() { */ public void flushMap() { totalObjects = objectMap.size(); - if (renderManager.getGraphCapture() != null) { - renderManager.getGraphCapture().flushObjects(totalObjects); - } GraphEventCapture cap = renderManager.getGraphCapture(); + if (cap != null) cap.flushObjects(totalObjects); for (Iterator it = objectMap.values().iterator(); it.hasNext();) { RenderObject obj = it.next(); if (!obj.tickTimeout()) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index bd47a85305..ce40e11393 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -119,7 +119,7 @@ protected boolean validate(ResourceTicket ticket) { protected int add(RenderResource res) { assert res != null; if (nextSlot >= resources.size()) { - // addEvent resource to end of list + // addUserEvent resource to end of list resources.add(res); nextSlot++; return resources.size()-1; @@ -437,9 +437,7 @@ private void replaceColorTarget(FrameBuffer fbo, ResourceTic public T acquireDepthTarget(FrameBuffer fbo, ResourceTicket ticket) { T acquired = acquire(ticket); FrameBuffer.RenderBuffer target = fbo.getDepthTarget(); - boolean nullTarget = target == null; - boolean unequalTargets = target != null && acquired != target.getTexture(); - if (nullTarget || unequalTargets) { + if (target == null || acquired != target.getTexture()) { fbo.setDepthTarget(FrameBuffer.target(acquired)); fbo.setUpdateNeeded(); if (cap != null) cap.bindTexture(ticket.getWorldIndex(), ticket.getName()); @@ -456,7 +454,7 @@ public T acquireDepthTarget(FrameBuffer fbo, ResourceTicket< * @param value */ public void setDirect(ResourceTicket ticket, T value) { - map.setDirect(locate(ticket), value); + map.allocateDirect(locate(ticket), value); } protected T extract(RenderResource resource, ResourceTicket ticket) { @@ -517,10 +515,10 @@ public void release(ResourceTicket ticket) { cap.releaseObject(resource.getObject().getId()); } remove(ticket.getWorldIndex()); - resource.setObject(null); if (resource.getDefinition().isDisposeOnRelease()) { map.dispose(resource); } + resource.setObject(null); } } /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java index b8dfce73d3..c1de89125f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java @@ -25,6 +25,7 @@ public class GraphEventCapture { private final LinkedList events = new LinkedList<>(); private int frame = 0; private boolean includeNanos = true; + private long userNanos = 0; public GraphEventCapture(File target) { this.target = target; @@ -33,19 +34,22 @@ public GraphEventCapture(File target) { private void add(Event c) { events.addLast(c); } - public void addEvent(String operation, Object... arguments) { - add(new Event(operation, arguments)); + public void addUserEvent(String operation, Object... arguments) { + add(new Event("USEREVENT", operation, arguments)); + } + public void value(String name, Object value) { + add(new Value(name, value)); } public void startRenderFrame() { - add(new SuperEvent("StartRenderFrame", frame)); + add(new Event("SUPEREVENT", "StartRenderFrame", frame)); } public void endRenderFrame() { - add(new SuperEvent("EndRenderFrame", frame++)); + add(new Event("SUPEREVENT", "EndRenderFrame", frame++)); } public void renderViewPort(ViewPort vp) { Camera cam = vp.getCamera(); - add(new SuperEvent("StartViewPort", vp.getName(), cam.getWidth(), cam.getHeight())); + add(new Event("SUPEREVENT", "StartViewPort", vp.getName(), cam.getWidth(), cam.getHeight())); } public void prepareRenderPass(int index, String name) { events.add(new Event("PrepareRenderPass", index, name)); @@ -116,8 +120,22 @@ public void flushObjects(int size) { add(new Event("FlushObjects", size)); } - public void value(String name, Object value) { - add(new Value(name, value)); + public void startNanos(String subject) { + userNanos = System.nanoTime(); + add(new Event("PROFILE", "StartNanos", subject)); + } + public long lapNanos(String subject) { + return breakNanos(subject, subject); + } + public long breakNanos(String endSubject, String startSubject) { + long duration = endNanos(endSubject); + startNanos(startSubject); + return duration; + } + public long endNanos(String subject) { + long duration = Math.abs(System.nanoTime()-userNanos); + add(new Event("PROFILE", "EndNanos", subject, duration+"ns", (duration/1000000)+"ms")); + return duration; } public void export() throws IOException { @@ -137,18 +155,22 @@ public void export() throws IOException { public void setIncludeNanos(boolean includeNanos) { this.includeNanos = includeNanos; } - public boolean isIncludeNanos() { return includeNanos; } - private class Event { + private static class Event { + protected String eventType; protected final String operation; protected final Object[] arguments; protected final long startNanos; - + public Event(String operation, Object... arguments) { + this("EVENT", operation, arguments); + } + public Event(String eventType, String operation, Object... arguments) { + this.eventType = eventType; this.operation = operation; this.arguments = arguments; this.startNanos = System.nanoTime(); @@ -180,23 +202,11 @@ public String toExportString(boolean nanos) { return builder.append(')').toString(); } public String getEventType() { - return "EVENT"; - } - - } - private class SuperEvent extends Event { - - public SuperEvent(String operation, Object... arguments) { - super(operation, arguments); - } - - @Override - public String getEventType() { - return "SUPEREVENT"; + return eventType; } } - private class Value extends Event { + private static class Value extends Event { public Value(String field, Object value) { super(field, value); @@ -215,21 +225,18 @@ public String getEventType() { } } - private class Failure extends Event { + private static class Failure extends Event { public Failure(String operation, Check... checks) { super(operation, new Object[checks.length]); int i = 0; for (; i < checks.length; i++) { - boolean success = checks[i].run(); - if (!success) { + if (!checks[i].run()) { arguments[i] = checks[i].name; - if (checks[i].terminal) { - break; - } - continue; + if (checks[i].terminal) break; + } else { + arguments[i] = '-'; } - arguments[i] = '-'; } for (; i < checks.length; i++) { arguments[i] = '?'; @@ -243,7 +250,7 @@ public String getEventType() { } - private class Check { + private static class Check { private final String name; private final Supplier check; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 4dfea598e3..682fb829e8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -138,6 +138,10 @@ public Consumer getDisposalMethod() { return this; } @Override + public boolean isDisposeOnRelease() { + return false; + } + @Override public void accept(T t) { t.getImage().dispose(); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java index 9b8d0fa6ed..fbc43a2781 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java @@ -46,7 +46,8 @@ public interface GraphTarget { * * @param viewPort viewport currently being rendered * @param value value from framegraph + * @return true if value is used */ - public void setGraphValue(ViewPort viewPort, T value); + public boolean setGraphValue(ViewPort viewPort, T value); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java index e7a97c0cb1..582c04061b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java @@ -87,7 +87,7 @@ public void setSpatial(Spatial spat) { } } @Override - public void setGraphValue(ViewPort viewPort, T value) { + public boolean setGraphValue(ViewPort viewPort, T value) { if (containsViewPort(viewPort)) { this.value = value; if (this.value != null) { @@ -95,7 +95,9 @@ public void setGraphValue(ViewPort viewPort, T value) { } else { material.clearParam(name); } + return true; } + return false; } private boolean containsViewPort(ViewPort vp) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index 0ea934c524..a093515a43 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -75,15 +75,22 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { - value = resources.acquireOrElse(in, null); - if (value != null && !targets.isEmpty()) { + T inVal = resources.acquireOrElse(in, null); + if (inVal != null && !targets.isEmpty()) { + boolean used = false; for (GraphTarget t : targets) { - t.setGraphValue(context.getViewPort(), value); + if (t.setGraphValue(context.getViewPort(), inVal)) { + used = true; + } + } + if (used) { + resources.setConstant(in); } - resources.setConstant(in); } if (source != null) { value = source.getGraphValue(context.getViewPort()); + } else { + value = null; } if (value != null) { resources.acquire(out); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 8e7a72c89e..945ba16a83 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -108,7 +108,7 @@ protected void execute(FGRenderContext context) { context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); - context.transferTextures(resources.acquireOrElse(inColor, null), resources.acquireOrElse(inDepth, null)); + context.renderTextures(resources.acquireOrElse(inColor, null), resources.acquireOrElse(inDepth, null)); context.getRenderer().setDepthRange(depth); if (bucket == Bucket.Gui) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 72c8460c0b..5045d2e050 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -31,6 +31,7 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.asset.AssetManager; import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.material.TechniqueDef; @@ -49,7 +50,8 @@ * @author codex */ public class DeferredPass extends RenderPass { - + + private AssetManager assetManager; private ResourceTicket diffuse, specular, emissive, normal, depth, outColor; private ResourceTicket lights; private ResourceTicket numRenders; @@ -68,7 +70,9 @@ protected void initialize(FrameGraph frameGraph) { outColor = addOutput("Color"); colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); colorDef.setFormatFlexible(true); - material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); + //colorDef.setUseExisting(false); + assetManager = frameGraph.getAssetManager(); + material = new Material(assetManager, "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { t.setLogic(new DeferredSinglePassLightingLogic(t)); } @@ -83,15 +87,17 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { + //material = new Material(assetManager, "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); + System.out.println("deferred pass: "+context.getViewPort().getName()); FrameBuffer fb = getFrameBuffer(context, 1); //if (resources.acquireOrElse(numRenders, 1) == 0) { // return; //} resources.acquireColorTargets(fb, outColor); - context.popFrameBuffer(); - //context.getRenderer().setFrameBuffer(fb); - //context.getRenderer().clearBuffers(true, true, true); - //context.getRenderer().setBackgroundColor(ColorRGBA.Blue.clone().setAlpha(0)); + //context.popFrameBuffer(); + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); material.setTexture("Context_InGBuff1", resources.acquire(specular)); material.setTexture("Context_InGBuff2", resources.acquire(emissive)); @@ -103,8 +109,10 @@ protected void execute(FGRenderContext context) { //context.renderFullscreen(material); //context.getScreen().setAlphaDiscard(0f); if (lightList != null) { + material.setInt("NBLight", lightList.size()); context.getScreen().render(context.getRenderManager(), material, lightList); } else { + material.setInt("NBLight", 0); context.renderFullscreen(material); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 25c9f154c7..a511fe3e14 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -70,7 +70,6 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private ValueDef numRendersDef; private final TextureDef[] texDefs = new TextureDef[5]; private final LinkedList accumulatedLights = new LinkedList<>(); - private Texture2D diffuseTex; private int numRenders = 0; @Override @@ -88,9 +87,7 @@ protected void initialize(FrameGraph frameGraph) { texDefs[2] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); texDefs[3] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA32F); texDefs[4] = new TextureDef<>(Texture2D.class, tex, Image.Format.Depth); - int i = -1; for (TextureDef d : texDefs) { - i++; d.setFormatFlexible(true); //d.setUseExisting(false); //d.setDisposeOnRelease(true); @@ -104,11 +101,7 @@ protected void initialize(FrameGraph frameGraph) { } @Override protected void prepare(FGRenderContext context) { - int w = context.getWidth(); - int h = context.getHeight(); - if (diffuseTex == null || diffuseTex.getImage().getWidth() != w || diffuseTex.getImage().getHeight() != h) { - diffuseTex = new Texture2D(w, h, Image.Format.RGBA16F); - } + int w = context.getWidth(), h = context.getHeight(); for (TextureDef d : texDefs) { d.setSize(w, h); } @@ -119,7 +112,7 @@ protected void prepare(FGRenderContext context) { declare(texDefs[4], depth); declare(lightDef, lights); declare(numRendersDef, numRendersTicket); - reserve(diffuse, specular, emissive, normal, depth, lights); + reserve(diffuse, specular, emissive, normal, depth); numRenders = 0; } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java index 7f724e5cd3..06178549fa 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java @@ -35,6 +35,7 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; +import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; @@ -50,10 +51,12 @@ public class OutputPass extends RenderPass { private ResourceTicket color, depth; - private float alphaDiscard = -1; + private Float alphaDiscard; - public OutputPass() {} - public OutputPass(float alphaDiscard) { + public OutputPass() { + this(null); + } + public OutputPass(Float alphaDiscard) { this.alphaDiscard = alphaDiscard; } @@ -71,10 +74,10 @@ protected void execute(FGRenderContext context) { context.popFrameBuffer(); Texture2D colorTex = resources.acquireOrElse(color, null); Texture2D depthTex = resources.acquireOrElse(depth, null); - if (alphaDiscard >= 0) { + if (alphaDiscard != null) { context.getScreen().setAlphaDiscard(alphaDiscard); } - context.transferTextures(colorTex, depthTex); + context.renderTextures(colorTex, depthTex); } @Override protected void reset(FGRenderContext context) {} @@ -82,7 +85,7 @@ protected void reset(FGRenderContext context) {} protected void cleanup(FrameGraph frameGraph) {} @Override public boolean isUsed() { - return true; + return color.hasSource() || depth.hasSource(); } @Override public void write(JmeExporter ex) throws IOException { 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 6158a16ba9..973486aeca 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -33,19 +33,23 @@ uniform int m_NBLight; void main(){ - vec2 innerTexCoord; -#if defined(USE_LIGHTS_CULL_MODE) - innerTexCoord = gl_FragCoord.xy * g_ResolutionInverse; -#else - innerTexCoord = texCoord; -#endif + #if defined(USE_LIGHTS_CULL_MODE) + vec2 innerTexCoord = gl_FragCoord.xy * g_ResolutionInverse; + #else + vec2 innerTexCoord = texCoord; + #endif // unpack GBuffer vec4 shadingInfo = texture2D(Context_InGBuff2, innerTexCoord); int shadingModelId = int(floor(shadingInfo.a)); + //shadingModelId = -1; float depth = texture2D(GBUFFER_DEPTH, texCoord).r; gl_FragDepth = depth; - // Perform corresponding pixel shading based on the shading model - if (shadingModelId == LEGACY_LIGHTING) { + // Due to GPU architecture, each shading mode is performed for each pixel, which is very inefficient. + // TODO: Remove these if statements if possible. + if (shadingModelId == -1) { + gl_FragColor.rgb = texture2D(Context_InGBuff0, innerTexCoord).rgb; + gl_FragColor.a = 1.0; + } else if (shadingModelId == LEGACY_LIGHTING) { vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord); vec4 diffuseColor = texture2D(Context_InGBuff0, innerTexCoord); @@ -55,41 +59,39 @@ void main(){ 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 = m_NBLight; - #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)); + #ifdef USE_TEXTURE_PACK_MODE + float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f); + lightNum = m_NBLight; #else - vec4 lightColor = g_LightData[i]; - vec4 lightData1 = g_LightData[i+1]; + lightNum = NB_LIGHTS; #endif + for (int i = 0; i < lightNum;) { + #ifdef 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); + #if __VERSION__ >= 110 + // allow use of control flow + if(lightColor.w > 1.0){ #endif + #ifdef 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 @@ -118,12 +120,16 @@ void main(){ gl_FragColor.rgb += lightColor.rgb * diffuseColor.rgb * vec3(light.x) + lightColor.rgb * specularColor.rgb * vec3(light.y); - #if defined(USE_TEXTURE_PACK_MODE) - i++; + #ifdef USE_TEXTURE_PACK_MODE + i++; #else - i+=3; + i+=3; #endif } + // debug: if there are no lights, render red + //if (lightNum == 0) { + // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + //} } else if (shadingModelId == STANDARD_LIGHTING) { // todo: vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); @@ -141,23 +147,22 @@ void main(){ 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 = m_NBLight; + #ifdef USE_TEXTURE_PACK_MODE + float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f); + lightNum = m_NBLight; #else - lightNum = NB_LIGHTS; + 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)); + for (int i = 0; i < lightNum;) { + #ifdef 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]; + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; #endif vec4 lightDir; vec3 lightVec; @@ -165,25 +170,25 @@ void main(){ 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 - } + // allow use of control flow + if(lightColor.w > 1.0){ + #endif + #ifdef 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 spotFallOff *= lightDir.w; #ifdef NORMALMAP - //Normal map -> lighting is computed in tangent space - lightDir.xyz = normalize(lightDir.xyz * tbnMat); + //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); + //no Normal map -> lighting is computed in view space + lightDir.xyz = normalize(lightDir.xyz); #endif vec3 directDiffuse; @@ -196,28 +201,26 @@ void main(){ vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular; gl_FragColor.rgb += directLighting * spotFallOff; - #if defined(USE_TEXTURE_PACK_MODE) - i++; - #else i++; - #endif } // skyLight and reflectionProbe - vec3 skyLightAndReflection = renderSkyLightAndReflectionProbes(indoorSunLightExposure, 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; + gl_FragColor.rgb = vec3(1-lightNum); + gl_FragColor.a = 1.0; } else if (shadingModelId == SUBSURFACE_SCATTERING) { - // todo: + // TODO: implement subsurface scattering } else if (shadingModelId == UNLIT) { gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } else { discard; } - if (innerTexCoord.y > 0.75) { - //discard; - } + //gl_FragColor.r = gl_FragColor.a; //gl_FragColor.a = 0.5; //gl_FragColor.a = 0.01; } diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag index 7b1f093e9c..b70d3dc4af 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.frag @@ -19,9 +19,16 @@ void main() { gl_FragColor = texture2D(m_ColorMap, texCoord); #ifdef ALPHA_DISCARD if (gl_FragColor.a <= m_AlphaDiscard) { + //gl_FragColor = vec4(1.0); discard; } #endif + if (gl_FragColor.rgb == vec3(0.0)) { + //gl_FragColor.rgb = vec3(1.0, 0.0, 0.0); + } + #ifdef DEBUG + gl_FragColor.rgba = vec4(gl_FragColor.a, 0.0, 0.0, 1.0); + #endif #else gl_FragColor = vec4(0.0); #endif diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md index 2f3560ee5d..cca116177f 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md @@ -4,6 +4,7 @@ MaterialDef TextureTransfer { Texture2D ColorMap Texture2D DepthMap Float AlphaDiscard + Boolean Debug } Technique { @@ -23,6 +24,7 @@ MaterialDef TextureTransfer { WRITE_COLOR_MAP : ColorMap WRITE_DEPTH : DepthMap ALPHA_DISCARD : AlphaDiscard + DEBUG : Debug } } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 25f7716105..1871e90a97 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -49,6 +49,7 @@ import com.jme3.input.controls.KeyTrigger; import com.jme3.light.*; import com.jme3.material.Material; +import com.jme3.material.RenderState; import com.jme3.math.*; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; @@ -63,6 +64,7 @@ import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.instancing.InstancedGeometry; +import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; import com.jme3.shader.VarType; @@ -678,7 +680,7 @@ public void simpleInitApp() { File capTarget = new File(System.getProperty("user.home")+"/earlyFrameCapture.txt"); GraphEventCapture cap = new GraphEventCapture(capTarget); cap.setIncludeNanos(false); - renderManager.setGraphCapture(cap, 6); + renderManager.setGraphCapture(cap, 10); viewPort.setBackgroundColor(ColorRGBA.Green.mult(.1f)); guiViewPort.setBackgroundColor(ColorRGBA.Red.mult(.1f)); @@ -693,6 +695,7 @@ public void simpleInitApp() { Geometry debugView = new Geometry("debug", new Quad(200, 200)); debugView.setLocalTranslation(0, 200, 0); Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + //debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); debugView.setMaterial(debugMat); MatParamTargetControl texTarget = new MatParamTargetControl("ColorMap", VarType.Texture2D); texTarget.setViewPorts(viewPort); @@ -700,6 +703,11 @@ public void simpleInitApp() { debugView.addControl(texTarget); guiNode.attachChild(debugView); + Geometry g = new Geometry("test", new Box(1, 1, 1)); + g.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); + g.setQueueBucket(RenderQueue.Bucket.Opaque); + //guiNode.attachChild(g); + //renderManager.setRenderPath(currentRenderPath); testScene7(); // cam.setFrustumPerspective(45.0f, 4.0f / 3.0f, 0.01f, 100.0f); From a41e33fbc2e19ae7e38bbdc8b337e7d4c45c095d Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 3 Jun 2024 08:24:18 -0400 Subject: [PATCH 078/111] revert debugging --- .../com/jme3/renderer/framegraph/FrameGraphFactory.java | 9 ++++----- .../jme3/renderer/framegraph/passes/DeferredPass.java | 4 ---- .../Common/MatDefs/ShadingCommon/DeferredShading.frag | 7 ++----- .../jme3test/renderpath/TestSimpleDeferredLighting.java | 4 ++-- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index e70906d69d..efcde08030 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -84,11 +84,11 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { deferred = fg.add(new TileDeferredPass()); } OutputPass defOut = fg.add(new OutputPass(0f)); -// fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); -// fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); -// fg.add(new PostProcessingPass()); -// fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); + fg.add(new PostProcessingPass()); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); Attribute gbufDebug = fg.add(new Attribute<>()); gbufDebug.setName("GBufferDebug"); @@ -98,7 +98,6 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { deferred.makeInput(gbuf, "Normal", "Normal"); deferred.makeInput(gbuf, "Depth", "Depth"); deferred.makeInput(gbuf, "Lights", "Lights"); - deferred.makeInput(gbuf, "NumRenders", "NumRenders"); defOut.makeInput(deferred, "Color", "Color"); defOut.makeInput(gbuf, "Depth", "Depth"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 5045d2e050..8f1aac0136 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -88,11 +88,7 @@ protected void prepare(FGRenderContext context) { @Override protected void execute(FGRenderContext context) { //material = new Material(assetManager, "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); - System.out.println("deferred pass: "+context.getViewPort().getName()); FrameBuffer fb = getFrameBuffer(context, 1); - //if (resources.acquireOrElse(numRenders, 1) == 0) { - // return; - //} resources.acquireColorTargets(fb, outColor); //context.popFrameBuffer(); context.getRenderer().setFrameBuffer(fb); 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 973486aeca..7535706bd9 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -41,15 +41,12 @@ void main(){ // unpack GBuffer vec4 shadingInfo = texture2D(Context_InGBuff2, innerTexCoord); int shadingModelId = int(floor(shadingInfo.a)); - //shadingModelId = -1; + float depth = texture2D(GBUFFER_DEPTH, texCoord).r; gl_FragDepth = depth; // Due to GPU architecture, each shading mode is performed for each pixel, which is very inefficient. // TODO: Remove these if statements if possible. - if (shadingModelId == -1) { - gl_FragColor.rgb = texture2D(Context_InGBuff0, innerTexCoord).rgb; - gl_FragColor.a = 1.0; - } else if (shadingModelId == LEGACY_LIGHTING) { + if (shadingModelId == LEGACY_LIGHTING) { vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord); vec4 diffuseColor = texture2D(Context_InGBuff0, innerTexCoord); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 1871e90a97..badb9d234c 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -667,7 +667,7 @@ public void simpleInitApp() { FrameGraph forward = new FrameGraph(assetManager, "Common/FrameGraphs/Forward.j3g"); forward.setName("forward"); //FrameGraph deferred = new FrameGraph(assetManager, "Common/FrameGraphs/Deferred.j3g"); - FrameGraph deferred = FrameGraphFactory.deferred(assetManager, false); + FrameGraph deferred = FrameGraphFactory.deferred(assetManager, true); deferred.setName("deferred1"); FrameGraph deferred2 = FrameGraphFactory.deferred(assetManager, false); deferred2.setName("deferred2"); @@ -680,7 +680,7 @@ public void simpleInitApp() { File capTarget = new File(System.getProperty("user.home")+"/earlyFrameCapture.txt"); GraphEventCapture cap = new GraphEventCapture(capTarget); cap.setIncludeNanos(false); - renderManager.setGraphCapture(cap, 10); + //renderManager.setGraphCapture(cap, 10); viewPort.setBackgroundColor(ColorRGBA.Green.mult(.1f)); guiViewPort.setBackgroundColor(ColorRGBA.Red.mult(.1f)); From c94bee25a5e2d602c6598ba78076e42eb5f9288e Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 3 Jun 2024 12:37:45 -0400 Subject: [PATCH 079/111] fix merge conflict --- .../java/com/jme3/renderer/RenderManager.java | 2 +- .../framegraph/FrameGraphFactory.java | 4 --- .../renderer/framegraph/RenderObjectMap.java | 27 ++++++++++++++++-- .../resources/Common/FrameGraphs/Deferred.j3g | Bin 1451 -> 1440 bytes .../Common/FrameGraphs/TiledDeferred.j3g | Bin 1459 -> 1448 bytes .../TestFrameGraphImportExport.java | 4 +-- 6 files changed, 27 insertions(+), 10 deletions(-) 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 4040e42383..13e5971bb8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -1515,7 +1515,7 @@ public void setRenderFilter(Predicate filter) { /** * Returns the render filter that the RenderManager is currently using * - * @return + * @return the render filter */ public Predicate getRenderFilter() { return renderFilter; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index efcde08030..cebaeee02d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -89,8 +89,6 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); fg.add(new PostProcessingPass()); fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); - Attribute gbufDebug = fg.add(new Attribute<>()); - gbufDebug.setName("GBufferDebug"); deferred.makeInput(gbuf, "Diffuse", "Diffuse"); deferred.makeInput(gbuf, "Specular", "Specular"); @@ -102,8 +100,6 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { defOut.makeInput(deferred, "Color", "Color"); defOut.makeInput(gbuf, "Depth", "Depth"); - gbufDebug.makeInput(gbuf, "Diffuse", "Value"); - return fg; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index ae99d7e585..107c36796c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -46,7 +46,7 @@ public class RenderObjectMap { private final RenderManager renderManager; private final HashMap objectMap = new HashMap<>(); - private final int timeout = 1; + private int staticTimeout = 1; // statistics private int totalAllocations = 0; @@ -81,7 +81,7 @@ protected RenderObject create(ResourceDef def) { * @return */ protected RenderObject create(ResourceDef def, T value) { - RenderObject obj = new RenderObject(def, value, timeout); + RenderObject obj = new RenderObject(def, value, staticTimeout); objectMap.put(obj.getId(), obj); return obj; } @@ -344,7 +344,28 @@ public void clearMap() { } objectMap.clear(); } - + + /** + * Sets the default number of frame boundaries an object can experience without + * being used before being disposed. + *

      + * default=1 (can survive one frame boundary) + * + * @param staticTimeout + */ + public void setStaticTimeout(int staticTimeout) { + this.staticTimeout = staticTimeout; + } + + /** + * Gets the default number of frame boundaries an object can experience without + * being used before being disposed. + * + * @return + */ + public int getStaticTimeout() { + return staticTimeout; + } /** * Get the total number of allocations that occured during the last render frame. * diff --git a/jme3-core/src/main/resources/Common/FrameGraphs/Deferred.j3g b/jme3-core/src/main/resources/Common/FrameGraphs/Deferred.j3g index f3cbfe401942962865dc32b02b200c9d0324e557..162413476962fb1d1a8a28fb80815585a026b8fd 100644 GIT binary patch delta 185 zcmZ3@y?}c|Ka&t6g9rly1CL`)K}MoWW^r<2(d30prS*wGK{g<61!8s}?gwHHAl?DQ zoIrdBh`E6H84z|Han`-b*plFd>?O0=ai9jHQgs?v*G`j9804Xj}g>o`Vsy22)A=;H+g zd|(UnKcR>*sCoJ5irqWYz!x>D?l4WFG#Sm}*uI@-r_GIu(PDodB@5@Ty%pAWQXKpM D^Ufa6 diff --git a/jme3-core/src/main/resources/Common/FrameGraphs/TiledDeferred.j3g b/jme3-core/src/main/resources/Common/FrameGraphs/TiledDeferred.j3g index d345baffdad1d4048199754e660c909c3a3a8a43..ed45c02beb1b6e271aedbb0e5b01df8787ac5835 100644 GIT binary patch delta 174 zcmdnYy@Gp#HIon{g9rly1CL`)K}MoWW^r<2(PUqyv-PP!K{g=n1Y&j|o(#ksK)eTt zIf3{A5OV?XDVr^pSxy6~U znwh&F{gAu%mUTP#I+v0rbfGC-X+}?)(}!aEl9z0Q3(Rqe1+MUfYwR(>2d4N&b}Zb< fBo}^JD2%PTJ}S~g=FH-KQ Date: Thu, 6 Jun 2024 17:34:23 -0400 Subject: [PATCH 080/111] start moving lighting logic outside matdef logic --- .../jme3/renderer/framegraph/FrameGraph.java | 17 +++ .../renderer/framegraph/RenderModule.java | 13 ++ .../renderer/framegraph/ResourceList.java | 52 ++++++- .../framegraph/definitions/TextureDef.java | 41 +++++- .../framegraph/filters/SoftBloomPass.java | 13 ++ .../framegraph/io/MatParamTargetControl.java | 9 +- .../framegraph/light/LightImagePacker.java | 127 +++++++++++++++++ .../renderer/framegraph/passes/Attribute.java | 46 ++++++- .../framegraph/passes/DeferredPass.java | 3 + .../framegraph/passes/LightImagePass.java | 63 +++++++++ .../framegraph/passes/RenderPass.java | 15 +- .../framegraph/passes/ScalingPass.java | 128 ++++++++++++++++++ .../TestSimpleDeferredLighting.java | 1 - 13 files changed, 504 insertions(+), 24 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderModule.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/filters/SoftBloomPass.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ScalingPass.java 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 198fab951e..f2246aab45 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 @@ -42,6 +42,7 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.debug.GraphEventCapture; +import com.jme3.renderer.framegraph.passes.Attribute; import java.util.Iterator; import java.util.LinkedList; @@ -272,6 +273,21 @@ public T add(T pass, int index) { } return pass; } + /** + * Creates and adds an Attribute pass and links it to the given ticket. + *

      + * This is handy for quickly debugging various resources in the graph. + * + * @param + * @param ticket ticket to reference from + * @return created Attribute + */ + public Attribute addAttribute(ResourceTicket ticket) { + Attribute attr = add(new Attribute<>()); + attr.getInput(Attribute.VALUE).setSource(ticket); + return attr; + } + /** * Gets the first pass that is of or a subclass of the given class. * @@ -319,6 +335,7 @@ public T get(Class type, int id) { } return null; } + /** * Removes the pass at the index in the queue. *

      diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderModule.java new file mode 100644 index 0000000000..8ab9d35ab8 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderModule.java @@ -0,0 +1,13 @@ +/* + * 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 codex + */ +public class RenderModule { + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index ce40e11393..4079c917a9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -393,10 +393,21 @@ public T acquireOrElse(ResourceTicket ticket, T value) { * @param tickets */ public void acquireColorTargets(FrameBuffer fbo, ResourceTicket... tickets) { + acquireColorTargets(fbo, null, tickets); + } + /** + * Acquires and assigns textures as color targets to the framebuffer. + * + * @param fbo + * @param texArray array to populate with acquired textures, or null + * @param tickets + * @return populated texture array + */ + public Texture[] acquireColorTargets(FrameBuffer fbo, Texture[] texArray, ResourceTicket[] tickets) { if (tickets.length == 0) { fbo.clearColorTargets(); fbo.setUpdateNeeded(); - return; + return texArray; } if (tickets.length < fbo.getNumColorTargets()) { fbo.trimColorTargetsTo(tickets.length-1); @@ -404,24 +415,55 @@ public void acquireColorTargets(FrameBuffer fbo, ResourceTicket + * @param fbo + * @param ticket + * @return acquired texture + */ + public T acquireColorTarget(FrameBuffer fbo, ResourceTicket ticket) { + if (ticket == null) { + if (fbo.getNumColorTargets() > 0) { + fbo.clearColorTargets(); + fbo.setUpdateNeeded(); + } + return null; + } + if (fbo.getNumColorTargets() > 1) { + fbo.trimColorTargetsTo(0); + fbo.setUpdateNeeded(); + } + return replaceColorTarget(fbo, ticket, 0); } - private void replaceColorTarget(FrameBuffer fbo, ResourceTicket ticket, int i) { + private T replaceColorTarget(FrameBuffer fbo, ResourceTicket ticket, int i) { Texture existing = fbo.getColorTarget(i).getTexture(); - Texture acquired = acquire(ticket); + T acquired = acquire(ticket); if (acquired != existing) { fbo.setColorTarget(i, FrameBuffer.target(acquired)); fbo.setUpdateNeeded(); if (cap != null) cap.bindTexture(ticket.getWorldIndex(), ticket.getName()); textureBinds++; } + return acquired; } /** * Acquires and assigns a texture as the depth target to the framebuffer. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 682fb829e8..94f76af184 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -50,7 +50,7 @@ * @param */ public class TextureDef extends AbstractResourceDef implements Consumer { - + private final Class type; private Function textureBuilder; private Function imageExtractor; @@ -231,6 +231,22 @@ public void setDepth(int depth) { } this.depth = depth; } + /** + * Sets the width and height of the texture to the length. + * + * @param length + */ + public void setSquare(int length) { + width = height = length; + } + /** + * Sets the width, height, and depth of the texture to the length. + * + * @param length + */ + public void setCube(int length) { + width = height = depth = length; + } /** * Sets the width and height of the texture. * @@ -253,6 +269,29 @@ public void setSize(int width, int height, int depth) { setHeight(height); setDepth(depth); } + /** + * Sets the given texture demensions to contain the specified number of pixels. + * + * @param pixels + * @param w true to set width + * @param h true to set height + * @param d true to set depth + */ + public void setNumPixels(int pixels, boolean w, boolean h, boolean d) { + int n = 0; + if (w) n++; + if (h) n++; + if (d) n++; + int length; + switch (n) { + case 3: length = (int)Math.ceil(Math.cbrt(pixels)); break; + case 2: length = (int)Math.ceil(Math.sqrt(pixels)); break; + default: length = pixels; + } + if (w) width = length; + if (h) height = length; + if (d) depth = length; + } /** * Sets the number of samples of the texture's image. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/filters/SoftBloomPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/filters/SoftBloomPass.java new file mode 100644 index 0000000000..c73b9dff3e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/filters/SoftBloomPass.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.filters; + +/** + * + * @author codex + */ +public class SoftBloomPass { + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java index 582c04061b..a12993c11c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java @@ -34,6 +34,7 @@ import com.jme3.material.Material; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.scene.Geometry; import com.jme3.scene.SceneGraphIterator; import com.jme3.scene.Spatial; @@ -60,13 +61,7 @@ public MatParamTargetControl(String name, VarType type) { } @Override - protected void controlUpdate(float tpf) { - //System.out.println("check: assign to material?"); - if (value != null) { - //System.out.println("assign "+value.getClass().getSimpleName()+" to material"); - //material.setParam(name, type, value); - } - } + protected void controlUpdate(float tpf) {} @Override protected void controlRender(RenderManager rm, ViewPort vp) {} @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java new file mode 100644 index 0000000000..67a1fb2436 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java @@ -0,0 +1,127 @@ +/* + * 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.light; + +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.texture.Image; +import com.jme3.texture.Texture2D; +import com.jme3.texture.image.ImageRaster; + +/** + * + * @author codex + */ +public class LightImagePacker { + + private final Texture2D[] textures = new Texture2D[3]; + private final ImageRaster[] rasters = new ImageRaster[3]; + private final ColorRGBA tempColor = new ColorRGBA(); + + public LightImagePacker() {} + + public void setTextures(Texture2D tex1, Texture2D tex2, Texture2D tex3) { + validateSize(tex1, tex2); + validateSize(tex1, tex3); + updateTexture(0, tex1); + updateTexture(1, tex2); + updateTexture(2, tex3); + } + public Texture2D[] getTextures() { + return textures; + } + public Texture2D getTexture(int i) { + return textures[i]; + } + + public void packLightsToTextures(LightList lights) { + if (lights.size() == 0) { + return; + } + int x = 0, y = 0; + int w = textures[0].getImage().getWidth(); + int h = textures[0].getImage().getHeight(); + boolean spotlight = false; + for (Light l : lights) { + if (l.getType() == Light.Type.Ambient || l.getType() == Light.Type.Probe) { + continue; + } + tempColor.set(l.getColor()).setAlpha(l.getType().getId()); + rasters[0].setPixel(x, y, tempColor); + switch (l.getType()) { + case Directional: + DirectionalLight dl = (DirectionalLight)l; + vectorToColor(dl.getDirection(), tempColor); + rasters[1].setPixel(x, y, tempColor); + break; + case Point: + PointLight pl = (PointLight)l; + vectorToColor(pl.getPosition(), tempColor); + tempColor.a = pl.getInvRadius(); + rasters[1].setPixel(x, y, tempColor); + break; + case Spot: + SpotLight sl = (SpotLight)l; + vectorToColor(sl.getPosition(), tempColor); + tempColor.a = sl.getInvSpotRange(); + rasters[1].setPixel(x, y, tempColor); + // 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. + vectorToColor(sl.getDirection(), tempColor); + tempColor.a = sl.getPackedAngleCos(); + rasters[2].setPixel(x, y, tempColor); + spotlight = true; + break; + } + if (++x >= w) { + x = 0; + if (++y >= h) { + break; + } + } + } + textures[0].getImage().setUpdateNeeded(); + textures[1].getImage().setUpdateNeeded(); + if (spotlight) { + textures[2].getImage().setUpdateNeeded(); + } + } + + private void validateSamples(Texture2D tex) { + if (tex.getImage().getMultiSamples() != 1) { + throw new IllegalArgumentException("Texture cannot be multisampled."); + } + } + private void validateSize(Texture2D base, Texture2D target) { + Image baseImg = base.getImage(); + Image targetImg = target.getImage(); + if (baseImg.getWidth() != targetImg.getWidth() || baseImg.getHeight() != targetImg.getHeight()) { + throw new IllegalArgumentException("Texture has incorrect demensions."); + } + } + private void updateTexture(int i, Texture2D tex) { + validateSamples(tex); + if (textures[i] != tex) { + textures[i] = tex; + rasters[i] = ImageRaster.create(tex.getImage()); + } + } + private ColorRGBA vectorToColor(Vector3f vec, ColorRGBA color) { + if (color == null) { + color = new ColorRGBA(); + } + color.r = vec.x; + color.g = vec.y; + color.b = vec.z; + return color; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index a093515a43..8d1e63809c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -31,12 +31,15 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; import com.jme3.renderer.framegraph.io.GraphTarget; import com.jme3.renderer.framegraph.io.GraphSource; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.ValueDef; +import java.io.IOException; import java.util.LinkedList; import java.util.function.Function; @@ -54,19 +57,23 @@ */ public class Attribute extends RenderPass implements Function { + public static final String VALUE = "Value"; + private ResourceTicket in, out; private T value; private ValueDef def; private final LinkedList> targets = new LinkedList<>(); private GraphSource source; + private boolean constantOutput = false; @Override protected void initialize(FrameGraph frameGraph) { - in = addInput("Value"); - out = addOutput("Value"); + in = addInput(VALUE); + out = addOutput(VALUE); def = new ValueDef<>(null, this); def.setDisposeOnRelease(true); def.setUseExisting(false); + def.setDisposalMethod(object -> {}); } @Override protected void prepare(FGRenderContext context) { @@ -94,7 +101,7 @@ protected void execute(FGRenderContext context) { } if (value != null) { resources.acquire(out); - resources.setConstant(out); + if (constantOutput) resources.setConstant(out); } else { resources.setUndefined(out); } @@ -114,6 +121,16 @@ public boolean isUsed() { public T apply(Object t) { return value; } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + ex.getCapsule(this).write(constantOutput, "constantOutput", false); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + constantOutput = im.getCapsule(this).readBoolean("constantOutput", false); + } /** * Adds the graph target. @@ -142,5 +159,28 @@ public void removeTarget(GraphTarget target) { public void setSource(GraphSource source) { this.source = source; } + /** + * If true, the outgoing object is set as constant. + * + * @param constantOutput + */ + public void setConstantOutput(boolean constantOutput) { + this.constantOutput = constantOutput; + } + + /** + * + * @return + */ + public ValueDef getOutputDef() { + return def; + } + /** + * + * @return + */ + public boolean isConstantOutput() { + return constantOutput; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 8f1aac0136..ce7aab86b1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -42,6 +42,8 @@ import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; /** @@ -57,6 +59,7 @@ public class DeferredPass extends RenderPass { private ResourceTicket numRenders; private TextureDef colorDef; private Material material; + private int maxLights = 1000; @Override protected void initialize(FrameGraph frameGraph) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java new file mode 100644 index 0000000000..861ec4185f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java @@ -0,0 +1,63 @@ +/* + * 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.passes; + +import com.jme3.light.LightList; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.renderer.framegraph.light.LightImagePacker; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; + +/** + * + * @author codex + */ +public class LightImagePass extends RenderPass { + + private LightImagePacker packer = new LightImagePacker(); + private ResourceTicket lights; + private ResourceTicket[] textures = new ResourceTicket[3]; + private TextureDef texDef; + private int maxLights = 500; + + @Override + protected void initialize(FrameGraph frameGraph) { + lights = addInput("Lights"); + textures[0] = addOutput("Texture1"); + textures[1] = addOutput("Texture2"); + textures[2] = addOutput("Texture3"); + texDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); + texDef.setFormat(Image.Format.RGBA32F); + texDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); + texDef.setMagFilter(Texture.MagFilter.Nearest); + texDef.setWrap(Texture.WrapMode.EdgeClamp); + texDef.setNumPixels(maxLights, true, true, false); + } + @Override + protected void prepare(FGRenderContext context) { + for (ResourceTicket t : textures) { + declare(texDef, t); + reserve(t); + } + reference(lights); + } + @Override + protected void execute(FGRenderContext context) { + packer.setTextures( + resources.acquire(textures[0]), + resources.acquire(textures[1]), + resources.acquire(textures[2])); + packer.packLightsToTextures(resources.acquire(lights)); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 2229822c88..073f397e8f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -36,8 +36,6 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; -import com.jme3.renderer.Camera; -import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceList; @@ -69,6 +67,7 @@ public abstract class RenderPass implements ResourceProducer, Savable { private final LinkedList outputs = new LinkedList<>(); private final LinkedList frameBuffers = new LinkedList<>(); protected ResourceList resources; + protected boolean autoTicketRelease = true; /** * Initializes the pass to the framegraph. @@ -102,7 +101,9 @@ public void prepareRender(FGRenderContext context) { */ public void executeRender(FGRenderContext context) { execute(context); - releaseAll(); + if (autoTicketRelease) { + releaseAll(); + } } /** * Resets the pass from rendering. @@ -337,7 +338,7 @@ protected ResourceTicket addOutput(String name) { * @param name * @return */ - protected ResourceTicket getInputByName(String name) { + public ResourceTicket getInput(String name) { for (ResourceTicket t : inputs) { if (name.equals(t.getName())) { return t; @@ -351,7 +352,7 @@ protected ResourceTicket getInputByName(String name) { * @param name * @return */ - protected ResourceTicket getOutputByName(String name) { + public ResourceTicket getOutput(String name) { for (ResourceTicket t : outputs) { if (name.equals(t.getName())) { return t; @@ -368,8 +369,8 @@ protected ResourceTicket getOutputByName(String name) { * @param inTicket */ public void makeInput(RenderPass pass, String outTicket, String inTicket) { - ResourceTicket out = Objects.requireNonNull(pass.getOutputByName(outTicket)); - ResourceTicket in = Objects.requireNonNull(getInputByName(inTicket)); + ResourceTicket out = Objects.requireNonNull(pass.getOutput(outTicket)); + ResourceTicket in = Objects.requireNonNull(getInput(inTicket)); in.setSource(out); } /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ScalingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ScalingPass.java new file mode 100644 index 0000000000..1c2f4953fd --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/ScalingPass.java @@ -0,0 +1,128 @@ +/* + * 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.passes; + +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture2D; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author codex + */ +public class ScalingPass extends RenderPass { + + private static final Logger logger = Logger.getLogger(ScalingPass.class.getName()); + + private ResourceTicket inTex, outTex, tweenTex; + private TextureDef outTexDef, tweenTexDef; + private Material material; + private int renders = 5; + private boolean downsample = true; + private final Vector2f tempTexelSize = new Vector2f(); + + public ScalingPass() { + autoTicketRelease = false; + } + + @Override + protected void initialize(FrameGraph frameGraph) { + inTex = addInput("Texture"); + outTex = addOutput("Texture"); + tweenTex = new ResourceTicket<>(); + outTexDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); + tweenTexDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); + } + @Override + protected void prepare(FGRenderContext context) { + declare(outTexDef, outTex); + reserve(outTex); + reference(inTex); + } + @Override + protected void execute(FGRenderContext context) { + context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); + Texture2D prev = resources.acquire(inTex); + int w = prev.getImage().getWidth(); + int h = prev.getImage().getHeight(); + if (downsample) { + capNumRenders(w, h); + } + for (int i = 0; i < renders-1; i++) { + w = increment(w); + h = increment(h); + declare(tweenTexDef, tweenTex); + prev = render(context, tweenTex, tweenTexDef, prev, w, h); + resources.release(tweenTex); + } + w = increment(w); + h = increment(h); + render(context, outTex, outTexDef, prev, w, h); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + + private int increment(int n) { + if (downsample) return n >> 1; + else return n << 1; + } + private void capNumRenders(int w, int h) { + int limit = Math.min(w, h); + for (int i = 0; i < renders; i++) { + limit = limit >> 1; + if (limit <= 2) { + renders = i; + logger.log(Level.INFO, "Number of renders capped at {0} due to texture size.", i); + break; + } + } + } + private Texture2D render(FGRenderContext context, ResourceTicket ticket, + TextureDef def, Texture2D prev, int w, int h) { + def.setSize(w, h); + def.setFormat(prev.getImage().getFormat()); + FrameBuffer fb = getFrameBuffer(w, h, 1); + Texture2D tex = resources.acquireColorTarget(fb, ticket); + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + if (material != null) { + renderMaterial(context, prev, w, h); + } else { + context.renderTextures(prev, null); + } + return tex; + } + + protected void renderMaterial(FGRenderContext context, Texture2D texture, int w, int h) { + material.setTexture("Texture", texture); + material.setVector2("TexelSize", tempTexelSize.set(1f/w, 1f/h)); + context.getScreen().render(context.getRenderManager(), material); + } + + public void setMaterial(Material material) { + this.material = material; + } + public void setDownsample(boolean downsample) { + this.downsample = downsample; + } + + public Material getMaterial() { + return material; + } + public boolean isDownsample() { + return downsample; + } + +} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index badb9d234c..2ed6c3c113 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -49,7 +49,6 @@ import com.jme3.input.controls.KeyTrigger; import com.jme3.light.*; import com.jme3.material.Material; -import com.jme3.material.RenderState; import com.jme3.math.*; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; From d02fa6aa5d643271b060d91ae23e2e9170ef8fac Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 7 Jun 2024 15:33:46 -0400 Subject: [PATCH 081/111] added ticket groups --- .../DeferredSinglePassLightingLogic.java | 5 +- .../material/logic/TechniqueDefLogic.java | 2 + .../jme3/renderer/GeometryRenderHandler.java | 4 +- .../java/com/jme3/renderer/RenderLogic.java | 32 +++++ .../renderer/framegraph/FGRenderContext.java | 2 +- .../renderer/framegraph/FrameGraphData.java | 10 ++ .../framegraph/FrameGraphFactory.java | 15 +- .../framegraph/passes/DeferredPass.java | 30 ++-- .../framegraph/passes/GBufferPass.java | 34 ++--- .../framegraph/passes/RenderPass.java | 122 ++++++++++++++-- .../com/jme3/renderer/queue/RenderQueue.java | 4 +- .../MatDefs/Light/LightingGBufferPack.frag | 2 +- .../MatDefs/Light/PBRLightingGBufferPack.frag | 87 ++++++------ .../ShadingCommon/DeferredShading.frag | 132 ++++++++++-------- .../ShadingCommon/DeferredShading.j3md | 31 ++-- .../Common/ShaderLib/Deferred.glsllib | 61 ++++---- .../Common/ShaderLib/ShadingModel.glsllib | 18 +-- .../com/jme3/material/plugins/J3MLoader.java | 2 +- 18 files changed, 353 insertions(+), 240 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/RenderLogic.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 372676f64b..bac906cf3e 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 @@ -105,11 +105,8 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo private final int ambientDefines; public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) { - this(techniqueDef, true); - } - public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef, boolean useLightTextures) { super(techniqueDef); - this.useLightTextures = useLightTextures; + this.useLightTextures = true; singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean); if (this.useLightTextures) { packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int); diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java index 097c1fb003..687d79cdb1 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java @@ -35,6 +35,7 @@ import com.jme3.light.LightList; import com.jme3.material.Material.BindUnits; import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderLogic; import com.jme3.renderer.RenderManager; import com.jme3.scene.Geometry; import com.jme3.shader.DefineList; @@ -94,4 +95,5 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager * @param lastBindUnits the index of the most recently used units */ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits); + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java b/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java index 157fc370ab..21e57d1237 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java +++ b/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java @@ -43,8 +43,8 @@ public interface GeometryRenderHandler { /** * Renders the given geometry, or returns false. * - * @param rm render manager - * @param geom geometry to render + * @param rm renderGeometry manager + * @param geom geometry to renderGeometry * @return true if the geometry was rendered */ public boolean renderGeometry(RenderManager rm, Geometry geom); diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderLogic.java b/jme3-core/src/main/java/com/jme3/renderer/RenderLogic.java new file mode 100644 index 0000000000..311f9cc645 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderLogic.java @@ -0,0 +1,32 @@ +/* + * 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; + +import com.jme3.light.LightList; +import com.jme3.material.Material; +import com.jme3.scene.Geometry; +import com.jme3.shader.Shader; + +/** + * + * + * @author codex + */ +public interface RenderLogic { + + public boolean render(RenderManager rm, Geometry geometry); + + /** + * + * @param renderManager + * @param shader + * @param geometry + * @param lights + * @param lastBindUnits + * @return + */ + public boolean render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, Material.BindUnits lastBindUnits); + +} 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 ce97e08b5b..2618a04b56 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 @@ -36,7 +36,6 @@ import com.jme3.opencl.CommandQueue; import com.jme3.opencl.Context; import com.jme3.profile.AppProfiler; -import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; @@ -46,6 +45,7 @@ import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture2D; import java.util.function.Predicate; +import com.jme3.renderer.GeometryRenderHandler; /** * Contains necessary context for framegraph rendering. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java index 7d06f936ab..47ec099b20 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java @@ -156,9 +156,19 @@ public void apply(FrameGraph fg) { connections = null; } + /** + * Returns true if this data is export only, otherwise the data is import only. + * + * @return + */ public boolean isExportOnly() { return export; } + /** + * Returns true if this data has been consumed. + * + * @return + */ public boolean isConsumed() { return passes == null; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index cebaeee02d..c0fc6e5543 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -32,7 +32,6 @@ package com.jme3.renderer.framegraph; import com.jme3.asset.AssetManager; -import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.framegraph.passes.DeferredPass; import com.jme3.renderer.framegraph.passes.GBufferPass; import com.jme3.renderer.framegraph.passes.OutputBucketPass; @@ -41,7 +40,6 @@ import com.jme3.renderer.framegraph.passes.RenderPass; import com.jme3.renderer.framegraph.passes.TileDeferredPass; import com.jme3.renderer.queue.RenderQueue; -import com.jme3.texture.Texture2D; /** * Utility class for constructing common framegraphs. @@ -90,12 +88,13 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { fg.add(new PostProcessingPass()); fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); - deferred.makeInput(gbuf, "Diffuse", "Diffuse"); - deferred.makeInput(gbuf, "Specular", "Specular"); - deferred.makeInput(gbuf, "Emissive", "Emissive"); - deferred.makeInput(gbuf, "Normal", "Normal"); - deferred.makeInput(gbuf, "Depth", "Depth"); - deferred.makeInput(gbuf, "Lights", "Lights"); + deferred.makeInput(gbuf, "GBufferData", "GBufferData"); +// deferred.makeInput(gbuf, "Diffuse", "Diffuse"); +// deferred.makeInput(gbuf, "Specular", "Specular"); +// deferred.makeInput(gbuf, "Emissive", "Emissive"); +// deferred.makeInput(gbuf, "Normal", "Normal"); +// deferred.makeInput(gbuf, "Depth", "Depth"); +// deferred.makeInput(gbuf, "Lights", "Lights"); defOut.makeInput(deferred, "Color", "Color"); defOut.makeInput(gbuf, "Depth", "Depth"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index ce7aab86b1..c34dca91a2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -54,7 +54,8 @@ public class DeferredPass extends RenderPass { private AssetManager assetManager; - private ResourceTicket diffuse, specular, emissive, normal, depth, outColor; + private ResourceTicket[] gbuffers; + private ResourceTicket outColor; private ResourceTicket lights; private ResourceTicket numRenders; private TextureDef colorDef; @@ -63,11 +64,7 @@ public class DeferredPass extends RenderPass { @Override protected void initialize(FrameGraph frameGraph) { - diffuse = addInput("Diffuse"); - specular = addInput("Specular"); - emissive = addInput("Emissive"); - normal = addInput("Normal"); - depth = addInput("Depth"); + gbuffers = addInputGroup("GBufferData", 5); lights = addInput("Lights"); numRenders = addInput("NumRenders"); outColor = addOutput("Color"); @@ -85,33 +82,28 @@ protected void prepare(FGRenderContext context) { colorDef.setSize(context.getWidth(), context.getHeight()); declare(colorDef, outColor); reserve(outColor); - reference(diffuse, specular, emissive, normal, depth); + reference(gbuffers); referenceOptional(lights, numRenders); } @Override protected void execute(FGRenderContext context) { - //material = new Material(assetManager, "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); FrameBuffer fb = getFrameBuffer(context, 1); resources.acquireColorTargets(fb, outColor); - //context.popFrameBuffer(); context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); - material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); - material.setTexture("Context_InGBuff1", resources.acquire(specular)); - material.setTexture("Context_InGBuff2", resources.acquire(emissive)); - material.setTexture("Context_InGBuff3", resources.acquire(normal)); - material.setTexture("Context_InGBuff4", resources.acquire(depth)); + material.setTexture("Context_InGBuff0", resources.acquire(gbuffers[0])); + material.setTexture("Context_InGBuff1", resources.acquire(gbuffers[1])); + material.setTexture("Context_InGBuff2", resources.acquire(gbuffers[2])); + material.setTexture("Context_InGBuff3", resources.acquire(gbuffers[3])); + material.setTexture("Context_InGBuff4", resources.acquire(gbuffers[4])); material.selectTechnique("DeferredPass", context.getRenderManager()); LightList lightList = resources.acquireOrElse(lights, null); - //context.getRenderer().setDepthRange(0, 1); - //context.renderFullscreen(material); - //context.getScreen().setAlphaDiscard(0f); if (lightList != null) { - material.setInt("NBLight", lightList.size()); + material.setInt("NBLights", lightList.size()); context.getScreen().render(context.getRenderManager(), material, lightList); } else { - material.setInt("NBLight", 0); + material.setInt("NBLights", 0); context.renderFullscreen(material); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index a511fe3e14..b1b0488f7e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -36,7 +36,6 @@ import com.jme3.light.LightList; import com.jme3.material.Material; import com.jme3.math.ColorRGBA; -import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.RenderManager; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; @@ -50,6 +49,7 @@ import com.jme3.texture.Texture2D; import java.util.LinkedList; import java.util.function.Function; +import com.jme3.renderer.GeometryRenderHandler; /** * Renders diffuse, specular, emissive, normal, and depth information to a set of @@ -63,7 +63,7 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private final static String GBUFFER_PASS = "GBufferPass"; - private ResourceTicket diffuse, specular, emissive, normal, depth; + private ResourceTicket[] gbuffers; private ResourceTicket lights; private ResourceTicket numRendersTicket; private ValueDef lightDef; @@ -74,12 +74,8 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { @Override protected void initialize(FrameGraph frameGraph) { - diffuse = addOutput("Diffuse"); - specular = addOutput("Specular"); - emissive = addOutput("Emissive"); - normal = addOutput("Normal"); - depth = addOutput("Depth"); - lights = addOutput("Lights"); + gbuffers = addOutputGroup("GBufferData", 5); + lights = addOutput("Lights"); numRendersTicket = addOutput("NumRenders"); Function tex = img -> new Texture2D(img); texDefs[0] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); @@ -87,12 +83,6 @@ protected void initialize(FrameGraph frameGraph) { texDefs[2] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); texDefs[3] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA32F); texDefs[4] = new TextureDef<>(Texture2D.class, tex, Image.Format.Depth); - for (TextureDef d : texDefs) { - d.setFormatFlexible(true); - //d.setUseExisting(false); - //d.setDisposeOnRelease(true); - //d.setStaticTimeout(0); - } lightDef = new ValueDef(LightList.class, n -> new LightList(null)); lightDef.setReviser(list -> list.clear()); numRendersDef = new ValueDef(Boolean.class, n -> true); @@ -102,17 +92,13 @@ protected void initialize(FrameGraph frameGraph) { @Override protected void prepare(FGRenderContext context) { int w = context.getWidth(), h = context.getHeight(); - for (TextureDef d : texDefs) { - d.setSize(w, h); + for (int i = 0; i < gbuffers.length; i++) { + texDefs[i].setSize(w, h); + declare(texDefs[i], gbuffers[i]); } - declare(texDefs[0], diffuse); - declare(texDefs[1], specular); - declare(texDefs[2], emissive); - declare(texDefs[3], normal); - declare(texDefs[4], depth); declare(lightDef, lights); declare(numRendersDef, numRendersTicket); - reserve(diffuse, specular, emissive, normal, depth); + reserve(gbuffers); numRenders = 0; } @Override @@ -121,8 +107,8 @@ protected void execute(FGRenderContext context) { FrameBuffer fb = getFrameBuffer(context, 1); fb.setMultiTarget(true); //resources.setDirect(diffuse, diffuseTex); - resources.acquireColorTargets(fb, diffuse, specular, emissive, normal); - resources.acquireDepthTarget(fb, depth); + resources.acquireColorTargets(fb, gbuffers[0], gbuffers[1], gbuffers[2], gbuffers[3]); + resources.acquireDepthTarget(fb, gbuffers[4]); context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); LightList lightList = resources.acquire(lights); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 073f397e8f..c33763f054 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -45,6 +45,8 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.Objects; @@ -66,6 +68,7 @@ public abstract class RenderPass implements ResourceProducer, Savable { private final LinkedList inputs = new LinkedList<>(); private final LinkedList outputs = new LinkedList<>(); private final LinkedList frameBuffers = new LinkedList<>(); + private final HashMap groups = new HashMap<>(); protected ResourceList resources; protected boolean autoTicketRelease = true; @@ -125,10 +128,12 @@ public void cleanupPass(FrameGraph frameGraph) { t.setPassId(-1); } for (ResourceTicket t : outputs) { + t.setSource(null); t.setPassId(-1); } inputs.clear(); outputs.clear(); + groups.clear(); index = -1; } @@ -332,6 +337,79 @@ protected ResourceTicket addInput(String name) { protected ResourceTicket addOutput(String name) { return addOutput(new ResourceTicket<>(name)); } + /** + * Adds the ticket array as a group input under the given name. + * + * @param + * @param name + * @param array + * @return ticket array + */ + protected ResourceTicket[] addInputGroup(String name, ResourceTicket... array) { + for (ResourceTicket t : array) { + if (t == null) { + throw new NullPointerException("Ticket cannot be null in group."); + } + addInput(t); + } + groups.put(name, array); + return array; + } + /** + * Adds the ticket array as a group output under the given name. + * + * @param + * @param name + * @param array + * @return ticket array + */ + protected ResourceTicket[] addOutputGroup(String name, ResourceTicket... array) { + for (ResourceTicket t : array) { + if (t == null) { + throw new NullPointerException("Ticket cannot be null in group."); + } + addOutput(t); + } + groups.put(name, array); + return array; + } + /** + * Creates and adds a ticket array as a group input of the specified length under the given name. + *

      + * Each ticket is named the given name suffixed by the array index. + * + * @param + * @param name + * @param length + * @return created ticket array + */ + protected ResourceTicket[] addInputGroup(String name, int length) { + ResourceTicket[] array = new ResourceTicket[length]; + for (int i = 0; i < length; i++) { + addInput(array[i] = new ResourceTicket<>(name+i)); + } + groups.put(name, array); + return array; + } + /** + * Creates and adds a ticket array as a group output of the specified length under the given name. + *

      + * Each ticket is named the given name suffixed by the array index. + * + * @param + * @param name + * @param length + * @return create ticket array + */ + protected ResourceTicket[] addOutputGroup(String name, int length) { + ResourceTicket[] array = new ResourceTicket[length]; + for (int i = 0; i < length; i++) { + addOutput(array[i] = new ResourceTicket<>(name+i)); + } + groups.put(name, array); + return array; + } + /** * Gets the named input ticket, or null if none exists. * @@ -361,17 +439,43 @@ public ResourceTicket getOutput(String name) { return null; } /** - * Makes the named output ticket belonging to the given pass the source of - * the named input ticket belonging to this pass. + * Gets the ticket array registered under the name. * - * @param pass - * @param outTicket - * @param inTicket + * @param name + * @return */ - public void makeInput(RenderPass pass, String outTicket, String inTicket) { - ResourceTicket out = Objects.requireNonNull(pass.getOutput(outTicket)); - ResourceTicket in = Objects.requireNonNull(getInput(inTicket)); - in.setSource(out); + public ResourceTicket[] getGroup(String name) { + return groups.get(name); + } + + /** + * Makes the named source (output) ticket belonging to the given pass the source of + * the named target (input) ticket belonging to this pass. + *

      + * If both the source name and target name correspond to ticket groups, the + * groups will be connected. + * + * @param pass + * @param sourceTicket + * @param targetTicket + */ + public void makeInput(RenderPass pass, String sourceTicket, String targetTicket) { + ResourceTicket[] sourceArray = pass.getGroup(sourceTicket); + if (sourceArray != null) { + ResourceTicket[] targetArray = getGroup(targetTicket); + if (targetArray != null) { + if (sourceArray.length < targetArray.length) { + throw new IllegalArgumentException("Source ticket array does not satisfy target ticket array."); + } + for (int i = 0; i < targetArray.length; i++) { + targetArray[i].setSource(sourceArray[i]); + } + return; + } + } + ResourceTicket source = Objects.requireNonNull(pass.getOutput(sourceTicket), "Source ticket cannot be null."); + ResourceTicket target = Objects.requireNonNull(getInput(targetTicket), "Target ticket cannot be null."); + target.setSource(source); } /** * Nullifies all sources belonging to the given pass. 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 07c70e483a..0326708aa1 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 @@ -33,11 +33,11 @@ import com.jme3.post.SceneProcessor; import com.jme3.renderer.Camera; -import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.RenderManager; import com.jme3.scene.Geometry; import com.jme3.scene.Spatial; import java.util.LinkedList; +import com.jme3.renderer.GeometryRenderHandler; /** * RenderQueue is used to queue up and sort @@ -66,7 +66,7 @@ public RenderQueue() { } /** - * The render queue Bucket specifies the bucket + * The renderGeometry queue Bucket specifies the bucket * to which the spatial will be placed when rendered. *

      * The behavior of the rendering will differ depending on which diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag index f4911adb5d..ada4c37dc5 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag @@ -208,5 +208,5 @@ void main(){ Context_OutGBuff1.a = m_Shininess; // shading model id - Context_OutGBuff2.a = LEGACY_LIGHTING; + Context_OutGBuff2.a = PHONG_LIGHTING; } 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 e3079c696b..f65cd8399f 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag @@ -11,7 +11,7 @@ varying vec2 texCoord; #ifdef SEPARATE_TEXCOORD - varying vec2 texCoord2; + varying vec2 texCoord2; #endif varying vec4 Color; @@ -25,23 +25,23 @@ varying vec3 wPosition; #if NB_PROBES >= 1 - uniform samplerCube g_PrefEnvMap; - uniform vec3 g_ShCoeffs[9]; - uniform mat4 g_LightProbeData; + 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; + 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; + uniform samplerCube g_PrefEnvMap3; + uniform vec3 g_ShCoeffs3[9]; + uniform mat4 g_LightProbeData3; #endif #ifdef BASECOLORMAP - uniform sampler2D m_BaseColorMap; + uniform sampler2D m_BaseColorMap; #endif #ifdef USE_PACKED_MR @@ -59,7 +59,7 @@ varying vec3 wPosition; uniform vec4 m_Emissive; #endif #ifdef EMISSIVEMAP - uniform sampler2D m_EmissiveMap; + uniform sampler2D m_EmissiveMap; #endif #if defined(EMISSIVE) || defined(EMISSIVEMAP) uniform float m_EmissivePower; @@ -67,39 +67,39 @@ varying vec3 wPosition; #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 + 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; + uniform sampler2D m_ParallaxMap; #endif #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) uniform float m_ParallaxHeight; #endif #ifdef LIGHTMAP - uniform sampler2D m_LightMap; + uniform sampler2D m_LightMap; #endif #if defined(NORMALMAP) || defined(PARALLAXMAP) - uniform sampler2D m_NormalMap; - varying vec4 wTangent; + uniform sampler2D m_NormalMap; + varying vec4 wTangent; #endif varying vec3 wNormal; #ifdef DISCARD_ALPHA - uniform float m_AlphaDiscardThreshold; + uniform float m_AlphaDiscardThreshold; #endif -void main(){ +void main() { + vec2 newTexCoord; vec3 viewDir = normalize(g_CameraPosition - wPosition); @@ -160,7 +160,7 @@ void main(){ float alpha = albedo.a; #ifdef DISCARD_ALPHA - if(alpha < m_AlphaDiscardThreshold){ + if (alpha < m_AlphaDiscardThreshold) { discard; } #endif @@ -169,16 +169,11 @@ void main(){ // 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)); + vec4 normalHeight = texture2D(m_NormalMap, newTexCoord); + 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); #else - vec3 normal = norm; + vec3 normal = norm; #endif #ifdef SPECGLOSSPIPELINE @@ -235,24 +230,24 @@ void main(){ //float ndotv = max( dot( normal, viewDir ),0.0); - #if defined(EMISSIVE) || defined (EMISSIVEMAP) + #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; + outGBuffer2.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; + outGBuffer3.xy = n1; + outGBuffer3.zw = n2; + outGBuffer0.rgb = floor(diffuseColor.rgb * 100.0f) + ao * 0.1f; + outGBuffer1.rgb = floor(specularColor.rgb * 100.0f) + fZero * 0.1f; + outGBuffer1.a = Roughness; + outGBuffer0.a = alpha; // shading model id - Context_OutGBuff2.a = STANDARD_LIGHTING + 0.01f; + outGBuffer2.a = PBR_LIGHTING + 0.01; } 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 7535706bd9..6ab4f2031d 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -11,7 +11,7 @@ // skyLight and reflectionProbe uniform vec4 g_AmbientLightColor; #import "Common/ShaderLib/SkyLightReflectionProbe.glsllib" -#if defined(USE_LIGHTS_CULL_MODE) +#ifdef USE_LIGHT_TEXTURES uniform vec2 g_ResolutionInverse; #else varying vec2 texCoord; @@ -20,70 +20,78 @@ uniform vec4 g_AmbientLightColor; varying mat4 viewProjectionMatrixInverse; uniform mat4 g_ViewMatrix; uniform vec3 g_CameraPosition; -uniform int m_NBLight; +uniform int m_NBLights; -#if defined(USE_TEXTURE_PACK_MODE) - uniform int g_LightCount; - uniform sampler2D m_LightPackData1; - uniform sampler2D m_LightPackData2; - uniform sampler2D m_LightPackData3; +#ifdef USE_LIGHT_TEXTURES + //uniform int g_LightCount; + uniform sampler2D m_NBLightss; + uniform sampler2D m_LightTex1; + uniform sampler2D m_LightTex2; + uniform sampler2D m_LightTex3; + uniform vec2 m_LightTexSize; + uniform vec2 m_LightTexInv; #else uniform vec4 g_LightData[NB_LIGHTS]; #endif void main(){ - #if defined(USE_LIGHTS_CULL_MODE) + #ifdef USE_LIGHT_TEXTURES vec2 innerTexCoord = gl_FragCoord.xy * g_ResolutionInverse; #else vec2 innerTexCoord = texCoord; #endif - // unpack GBuffer - vec4 shadingInfo = texture2D(Context_InGBuff2, innerTexCoord); + // unpack m_GBuffer + vec4 shadingInfo = texture2D(m_GBuffer2, innerTexCoord); int shadingModelId = int(floor(shadingInfo.a)); - float depth = texture2D(GBUFFER_DEPTH, texCoord).r; + float depth = texture2D(m_DepthGBuffer, texCoord).r; gl_FragDepth = depth; // Due to GPU architecture, each shading mode is performed for each pixel, which is very inefficient. // TODO: Remove these if statements if possible. - if (shadingModelId == LEGACY_LIGHTING) { + if (shadingModelId == PHONG_LIGHTING) { + // phong shading vec3 vPos = getPosition(innerTexCoord, depth, 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; + vec4 buff1 = texture2D(m_GBuffer1, innerTexCoord); + vec4 diffuseColor = texture2D(m_GBuffer0, innerTexCoord); + vec3 specularColor = floor(buff1.rgb) * 0.01; + vec3 AmbientSum = min(fract(buff1.rgb) * 100.0, vec3(1.0)) * g_AmbientLightColor.rgb; + float shininess = buff1.a; float alpha = diffuseColor.a; - vec3 normal = texture2D(Context_InGBuff3, innerTexCoord).xyz; + vec3 normal = texture2D(m_GBuffer3, innerTexCoord).xyz; vec3 viewDir = normalize(g_CameraPosition - vPos); gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; gl_FragColor.a = alpha; - int lightNum = 0; - #ifdef USE_TEXTURE_PACK_MODE + //int lightNum = 0; + #ifdef USE_LIGHT_TEXTURES float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f); - lightNum = m_NBLight; - #else - lightNum = NB_LIGHTS; + int x = 0; + int y = 0; #endif - for (int i = 0; i < lightNum;) { - #ifdef USE_TEXTURE_PACK_MODE - vec4 lightColor = texture2D(m_LightPackData1, vec2(i * lightTexSizeInv, 0)); - vec4 lightData1 = texture2D(m_LightPackData2, vec2(i * lightTexSizeInv, 0)); + for (int i = 0; i < m_NBLights;) { + #ifdef USE_LIGHT_TEXTURES + vec2 pixel = vec2(x, y) * m_LightTexInv; + vec4 lightColor = texture2D(m_LightTex1, pixel); + vec4 lightData1 = texture2D(m_LightTex2, pixel); + if (++x >= m_LightTexSize.x) { + x = 0; + y++; + } #else vec4 lightColor = g_LightData[i]; vec4 lightData1 = g_LightData[i+1]; #endif vec4 lightDir; vec3 lightVec; - lightComputeDir(vPos, lightColor.w, lightData1, lightDir,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){ + if (lightColor.w > 1.0) { #endif - #ifdef USE_TEXTURE_PACK_MODE - spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, vec2(i * lightTexSizeInv, 0)), lightVec); + #ifdef USE_LIGHT_TEXTURES + spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); #else spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); #endif @@ -99,7 +107,7 @@ void main(){ lightDir.xyz = normalize(lightDir.xyz); #endif - vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , Shininess); + vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , shininess); // Workaround, since it is not possible to modify varying variables // #ifdef USE_REFLECTION @@ -117,21 +125,17 @@ void main(){ gl_FragColor.rgb += lightColor.rgb * diffuseColor.rgb * vec3(light.x) + lightColor.rgb * specularColor.rgb * vec3(light.y); - #ifdef USE_TEXTURE_PACK_MODE + #ifdef USE_LIGHT_TEXTURES i++; #else - i+=3; + i += 3; #endif } - // debug: if there are no lights, render red - //if (lightNum == 0) { - // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); - //} - } else if (shadingModelId == STANDARD_LIGHTING) { - // todo: + } else if (shadingModelId == PBR_LIGHTING) { + // PBR shading vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); - vec4 buff0 = texture2D(Context_InGBuff0, innerTexCoord); - vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord); + vec4 buff0 = texture2D(m_GBuffer0, innerTexCoord); + vec4 buff1 = texture2D(m_GBuffer1, innerTexCoord); vec3 emissive = shadingInfo.rgb; vec3 diffuseColor = floor(buff0.rgb) * 0.01f; vec3 specularColor = floor(buff1.rgb) * 0.01f; @@ -140,23 +144,28 @@ void main(){ float Roughness = buff1.a; float indoorSunLightExposure = fract(shadingInfo.a) * 100.0f; float alpha = buff0.a; - vec4 n1n2 = texture2D(Context_InGBuff3, innerTexCoord); + vec4 n1n2 = texture2D(m_GBuffer3, 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; - #ifdef USE_TEXTURE_PACK_MODE + #ifdef USE_LIGHT_TEXTURES float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f); - lightNum = m_NBLight; + int x = 0; + int y = 0; #else - lightNum = NB_LIGHTS; #endif gl_FragColor.rgb = vec3(0.0); - for (int i = 0; i < lightNum;) { - #ifdef USE_TEXTURE_PACK_MODE - vec4 lightColor = texture2D(m_LightPackData1, vec2(i * lightTexSizeInv, 0)); - vec4 lightData1 = texture2D(m_LightPackData2, vec2(i * lightTexSizeInv, 0)); + for (int i = 0; i < m_NBLights;) { + #ifdef USE_LIGHT_TEXTURES + vec2 pixel = vec2(x, y) * m_LightTexInv; + vec4 lightColor = texture2D(m_LightTex1, pixel); + vec4 lightData1 = texture2D(m_LightTex2, pixel); + if (++x >= m_LightTexSize.x) { + x = 0; + y++; + } #else vec4 lightColor = g_LightData[i]; vec4 lightData1 = g_LightData[i+1]; @@ -170,10 +179,10 @@ void main(){ // allow use of control flow if(lightColor.w > 1.0){ #endif - #ifdef USE_TEXTURE_PACK_MODE - spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, vec2(i * lightTexSizeInv, 0)), lightVec); + #ifdef USE_LIGHT_TEXTURES + spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); #else - spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); #endif #if __VERSION__ >= 110 } @@ -192,13 +201,17 @@ void main(){ vec3 directSpecular; float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir, - lightColor.rgb, fZero, Roughness, ndotv, - directDiffuse, directSpecular); + lightColor.rgb, fZero, Roughness, ndotv, + directDiffuse, directSpecular); - vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular; + vec3 directLighting = diffuseColor.rgb * directDiffuse + directSpecular; gl_FragColor.rgb += directLighting * spotFallOff; - i++; + #ifdef USE_LIGHT_TEXTURES + i++; + #else + i += 3; + #endif } // skyLight and reflectionProbe vec3 skyLightAndReflection = renderSkyLightAndReflectionProbes( @@ -209,9 +222,10 @@ void main(){ gl_FragColor.a = alpha; gl_FragColor.rgb = vec3(1-lightNum); gl_FragColor.a = 1.0; - } else if (shadingModelId == SUBSURFACE_SCATTERING) { + } /*else if (shadingModelId == SUBSURFACE_SCATTERING) { // TODO: implement subsurface scattering - } else if (shadingModelId == UNLIT) { + }*/ else if (shadingModelId == UNLIT) { + // unlit shading gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); } else { 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 2e76ec0cd8..4f80ed7f98 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md @@ -1,23 +1,25 @@ MaterialDef DeferredShading { MaterialParameters { - Int NBLight - // For instancing - Boolean UseInstancing - // UseLightsCull + + Int NBLights Boolean UseLightsCullMode + Boolean UseLightTextures - // Context GBuffer Data - Texture2D Context_InGBuff0 - Texture2D Context_InGBuff1 - Texture2D Context_InGBuff2 - Texture2D Context_InGBuff3 - Texture2D Context_InGBuff4 + // GBuffer Data + Texture2D GBuffer0 + Texture2D GBuffer1 + Texture2D GBuffer2 + Texture2D GBuffer3 + Texture2D GBuffer4 // LightData - Texture2D LightPackData1 - Texture2D LightPackData2 - Texture2D LightPackData3 + Texture2D LightTex1 + Texture2D LightTex2 + Texture2D LightTex3 + Vector2 LightTexSize + Vector2 LightTexInv + } Technique DeferredPass { @@ -34,8 +36,9 @@ MaterialDef DeferredShading { } Defines { - INSTANCING : UseInstancing USE_LIGHTS_CULL_MODE : UseLightsCullMode + USE_LIGHT_TEXTURES : UseLightTextures + NB_LIGHTS : NBLights } } diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib index 468f090896..b81b1370b7 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib @@ -1,39 +1,29 @@ -#ifndef _JME_CONTEXT_ -#define _JME_CONTEXT_ - +//#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 + layout(location = 0) out vec4 out0; + layout(location = 1) out vec4 out1; + layout(location = 2) out vec4 out2; + layout(location = 3) out vec4 out3; + layout(location = 4) out vec4 out4; + #define outGBuffer0 out0 + #define outGBuffer1 out1 + #define outGBuffer2 out2 + #define outGBuffer3 out3 + #define outGBuffer4 out4 #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 - + #define outGBuffer0 gl_FragData[0] + #define outGBuffer1 gl_FragData[1] + #define outGBuffer2 gl_FragData[2] + #define outGBuffer3 gl_FragData[3] + #define outGBuffer4 gl_FragData[4] #endif -#define GBUFFER_DEPTH Context_InGBuff4 +uniform sampler2D m_GBuffer0; +uniform sampler2D m_GBuffer1; +uniform sampler2D m_GBuffer2; +uniform sampler2D m_GBuffer3; +uniform sampler2D m_DepthGBuffer; +//#endif 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); @@ -54,5 +44,8 @@ vec3 getPosition(in vec2 texCoord, in float depth, in mat4 matrixInverse){ } vec3 getPosition(in vec2 texCoord, in mat4 matrixInverse){ - return getPosition(texCoord, texture2D(GBUFFER_DEPTH, texCoord).r, matrixInverse); + return getPosition(texCoord, texture2D(depthGBuffer, texCoord).r, matrixInverse); } + + + diff --git a/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib index a7d8715fae..db72345b81 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib @@ -1,18 +1,4 @@ -// SHADING_MODEL -// 0 is clearRT mask -#define LEGACY_LIGHTING 1 -#define STANDARD_LIGHTING 2 +#define PHONG_LIGHTING 1 +#define PBR_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 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 9ce2a09ca1..dc37bd9cb4 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 @@ -656,7 +656,7 @@ private void readTechnique(Statement techStat) throws IOException{ technique.setLogic(new SinglePassLightingLogic(technique)); break; case DeferredSinglePass: - technique.setLogic(new DeferredSinglePassLightingLogic(technique, true)); + technique.setLogic(new DeferredSinglePassLightingLogic(technique)); break; case TileBasedDeferredSinglePass: technique.setLogic(new TileBasedDeferredSinglePassLightingLogic(technique, null)); From 0d659aa706ec7bb43bf12d5122da50290f9231b6 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:17:48 -0400 Subject: [PATCH 082/111] migrated lighting logic to render pass --- .../java/com/jme3/material/MaterialDef.java | 19 ++ .../java/com/jme3/material/Technique.java | 8 +- .../java/com/jme3/material/TechniqueDef.java | 37 ++- .../logic/DefaultTechniqueDefLogic.java | 12 +- .../com/jme3/material/logic/RenderLogic.java | 57 ++++ .../material/logic/TechniqueDefLogic.java | 24 +- .../java/com/jme3/renderer/RenderLogic.java | 32 --- .../java/com/jme3/renderer/RenderManager.java | 23 ++ .../renderer/framegraph/FGRenderContext.java | 4 + .../framegraph/FrameGraphFactory.java | 17 +- .../renderer/framegraph/RenderResource.java | 31 ++- .../renderer/framegraph/ResourceList.java | 27 +- .../framegraph/definitions/ResourceDef.java | 10 + .../framegraph/definitions/TextureDef.java | 23 +- .../framegraph/light/LightImagePacker.java | 52 ++-- .../framegraph/passes/DeferredPass.java | 244 ++++++++++++++++-- .../framegraph/passes/GBufferPass.java | 10 +- .../renderer/framegraph/passes/Junction.java | 85 +++++- .../framegraph/passes/LightImagePass.java | 83 +++++- .../passes/LightListExtractPass.java | 77 ++++++ .../framegraph/passes/RenderPass.java | 79 +++++- .../com/jme3/renderer/opengl/GLRenderer.java | 1 + .../main/java/com/jme3/shader/DefineList.java | 4 + .../MatDefs/Light/LightingGBufferPack.frag | 12 +- .../ShadingCommon/DeferredShading.frag | 70 ++--- .../ShadingCommon/DeferredShading.j3md | 13 +- .../Common/ShaderLib/Deferred.glsllib | 4 +- .../ShaderLib/SkyLightReflectionProbe.glsllib | 49 ++-- .../TestSimpleDeferredLighting.java | 18 +- 29 files changed, 888 insertions(+), 237 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/material/logic/RenderLogic.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/RenderLogic.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightListExtractPass.java diff --git a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java index 9cbd482e00..1035acabdd 100644 --- a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java +++ b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java @@ -32,6 +32,7 @@ package com.jme3.material; import com.jme3.asset.AssetManager; +import com.jme3.material.logic.RenderLogic; import com.jme3.shader.VarType; import com.jme3.texture.image.ColorSpace; @@ -185,6 +186,24 @@ public void addTechniqueDef(TechniqueDef technique) { public List getTechniqueDefs(String name) { return techniques.get(name); } + + /** + * Gets the first TechniqueDef under the name of the given light mode. + * + * @param name + * @param mode + * @return first matching TechniqueDef, or null + */ + public TechniqueDef getTechniqueDef(String name, TechniqueDef.LightMode mode) { + List list = techniques.get(name); + if (list == null) return null; + for (TechniqueDef d : list) { + if (d.getLightMode() == mode) { + return d; + } + } + return null; + } /** * diff --git a/jme3-core/src/main/java/com/jme3/material/Technique.java b/jme3-core/src/main/java/com/jme3/material/Technique.java index 5091028a85..bc9608e3b7 100644 --- a/jme3-core/src/main/java/com/jme3/material/Technique.java +++ b/jme3-core/src/main/java/com/jme3/material/Technique.java @@ -35,6 +35,7 @@ import com.jme3.light.LightList; import com.jme3.material.Material.BindUnits; import com.jme3.material.TechniqueDef.LightMode; +import com.jme3.material.logic.RenderLogic; import com.jme3.material.logic.TechniqueDefLogic; import com.jme3.renderer.Caps; import com.jme3.renderer.RenderManager; @@ -164,8 +165,11 @@ Shader makeCurrent(RenderManager renderManager, SafeArrayList * @param lastTexUnit the index of the most recently used texture unit */ void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) { - TechniqueDefLogic logic = def.getLogic(); - logic.render(renderManager, shader, geometry, lights, lastBindUnits); + if (renderManager.getRenderLogic() != null) { + renderManager.getRenderLogic().render(renderManager, shader, geometry, lights, lastBindUnits); + } else { + def.getLogic().render(renderManager, shader, geometry, lights, lastBindUnits); + } } /** 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 dce83fb022..b1baa5300b 100644 --- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java +++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.*; +import java.util.function.Function; /** * Describes a technique definition. @@ -66,6 +67,7 @@ public class TechniqueDef implements Savable, Cloneable { * Describes light rendering mode. */ public enum LightMode { + /** * Disable light-based rendering */ @@ -134,6 +136,11 @@ public enum LightMode { */ StaticPass, + /** + * + */ + Custom, + } public enum ShadowMode { @@ -175,6 +182,7 @@ public enum LightSpace { private LightMode lightMode = LightMode.Disable; private ShadowMode shadowMode = ShadowMode.Disable; private TechniqueDefLogic logic; + private boolean logicInit = false; private ArrayList worldBinds; //The space in which the light should be transposed before sending to the shader. @@ -260,10 +268,36 @@ public void setLightMode(LightMode lightMode) { public void setLogic(TechniqueDefLogic logic) { this.logic = logic; } - + public TechniqueDefLogic getLogic() { return logic; } + + public T getLogic(Class type) { + if (logic == null) return null; + if (!type.isAssignableFrom(logic.getClass())) { + throw new ClassCastException("TechniqueDefLogic is not of "+type.getName()); + } + return (T)logic; + } + + /** + * Sets the technique def logic if the current logic is null or of a different type. + * + * @param + * @param type + * @param func + * @return + */ + public T setLogicOrElse(Class type, Function func) { + if (logic == null || !type.isAssignableFrom(logic.getClass())) { + T l = func.apply(this); + setLogic(l); + return l; + } else { + return (T)logic; + } + } /** * Returns the shadow mode. @@ -457,7 +491,6 @@ public void addShaderParamDefine(String paramName, VarType paramType, String def */ public int addShaderUnmappedDefine(String defineName, VarType defineType) { int defineId = defineNames.size(); - defineNames.add(defineName); defineTypes.add(defineType); return defineId; diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java index ca8f7d1efa..55a76b7c99 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/DefaultTechniqueDefLogic.java @@ -59,7 +59,15 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager EnumSet rendererCaps, LightList lights, DefineList defines) { return techniqueDef.getShader(assetManager, rendererCaps, defines); } - + + /** + * Renders mesh from geometry. + * + * @param renderer + * @param geom + * @deprecated use {@link com.jme3.renderer.TechniqueDefLogic#renderMeshFromGeometry(com.jme3.renderer.Renderer, com.jme3.scene.Geometry)} instead. + */ + @Deprecated public static void renderMeshFromGeometry(Renderer renderer, Geometry geom) { Mesh mesh = geom.getMesh(); int lodLevel = geom.getLodLevel(); @@ -95,6 +103,6 @@ protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLi public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) { Renderer renderer = renderManager.getRenderer(); renderer.setShader(shader); - renderMeshFromGeometry(renderer, geometry); + TechniqueDefLogic.renderMeshFromGeometry(renderer, geometry); } } diff --git a/jme3-core/src/main/java/com/jme3/material/logic/RenderLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/RenderLogic.java new file mode 100644 index 0000000000..e7e78c09a6 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/logic/RenderLogic.java @@ -0,0 +1,57 @@ +/* + * 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.material.logic; + +import com.jme3.asset.AssetManager; +import com.jme3.light.LightList; +import com.jme3.material.Material; +import com.jme3.material.TechniqueDef; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.instancing.InstancedGeometry; +import com.jme3.shader.DefineList; +import com.jme3.shader.Shader; +import java.util.EnumSet; + +/** + * + * + * @author codex + */ +public interface RenderLogic { + + /** + * + * @param def + */ + public void initTechniqueDef(TechniqueDef def); + + /** + * + * @param assetManager + * @param renderManager + * @param rendererCaps + * @param lights + * @param defines + * @return + */ + public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, + EnumSet rendererCaps, LightList lights, DefineList defines); + + /** + * + * @param rm + * @param shader + * @param geometry + * @param lights + * @param lastBindUnits + */ + public void render(RenderManager rm, Shader shader, Geometry geometry, + LightList lights, Material.BindUnits lastBindUnits); + +} diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java index 687d79cdb1..475d13ffae 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/TechniqueDefLogic.java @@ -34,10 +34,13 @@ import com.jme3.asset.AssetManager; import com.jme3.light.LightList; import com.jme3.material.Material.BindUnits; +import com.jme3.material.TechniqueDef; import com.jme3.renderer.Caps; -import com.jme3.renderer.RenderLogic; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.instancing.InstancedGeometry; import com.jme3.shader.DefineList; import com.jme3.shader.Shader; import com.jme3.shader.Uniform; @@ -96,4 +99,23 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager */ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits); + /** + * + * @param renderer + * @param geom + */ + public static void renderMeshFromGeometry(Renderer renderer, Geometry geom) { + Mesh mesh = geom.getMesh(); + int lodLevel = geom.getLodLevel(); + if (geom instanceof InstancedGeometry) { + InstancedGeometry instGeom = (InstancedGeometry) geom; + int numVisibleInstances = instGeom.getNumVisibleInstances(); + if (numVisibleInstances > 0) { + renderer.renderMesh(mesh, lodLevel, numVisibleInstances, instGeom.getAllInstanceData()); + } + } else { + renderer.renderMesh(mesh, lodLevel, 1, null); + } + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderLogic.java b/jme3-core/src/main/java/com/jme3/renderer/RenderLogic.java deleted file mode 100644 index 311f9cc645..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderLogic.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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; - -import com.jme3.light.LightList; -import com.jme3.material.Material; -import com.jme3.scene.Geometry; -import com.jme3.shader.Shader; - -/** - * - * - * @author codex - */ -public interface RenderLogic { - - public boolean render(RenderManager rm, Geometry geometry); - - /** - * - * @param renderManager - * @param shader - * @param geometry - * @param lights - * @param lastBindUnits - * @return - */ - public boolean render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, Material.BindUnits lastBindUnits); - -} 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 24fd3137d4..f949d59b16 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -31,6 +31,7 @@ */ package com.jme3.renderer; +import com.jme3.material.logic.RenderLogic; import com.jme3.light.DefaultLightFilter; import com.jme3.light.LightFilter; import com.jme3.light.LightList; @@ -102,6 +103,7 @@ public class RenderManager { private RenderState forcedRenderState = null; private final SafeArrayList forcedOverrides = new SafeArrayList<>(MatParamOverride.class); + private RenderLogic logic; private GeometryRenderHandler renderGeometry; private int viewX; private int viewY; @@ -206,6 +208,27 @@ public GeometryRenderHandler getGeometryRenderHandler() { return renderGeometry; } + /** + * Sets the technique rendering logic. + *

      + * If not null, the rendering logic is used in place of a rendered technique's + * normal logic. This feature is highly experimental. + * + * @param logic + */ + public void setRenderLogic(RenderLogic logic) { + this.logic = logic; + } + + /** + * Gets the technique rendering logic. + * + * @return + */ + public RenderLogic getRenderLogic() { + return logic; + } + /** * Returns the pre ViewPort with the given name. * 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 2618a04b56..9e57130707 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 @@ -46,6 +46,7 @@ import com.jme3.texture.Texture2D; import java.util.function.Predicate; import com.jme3.renderer.GeometryRenderHandler; +import com.jme3.material.logic.RenderLogic; /** * Contains necessary context for framegraph rendering. @@ -69,6 +70,7 @@ public class FGRenderContext { private Material forcedMat; private FrameBuffer frameBuffer; private GeometryRenderHandler geomRender; + private RenderLogic logic; private Predicate geomFilter; private RenderState renderState; @@ -115,6 +117,7 @@ public void pushRenderSettings() { forcedMat = renderManager.getForcedMaterial(); frameBuffer = renderManager.getRenderer().getCurrentFrameBuffer(); geomRender = renderManager.getGeometryRenderHandler(); + logic = renderManager.getRenderLogic(); geomFilter = renderManager.getRenderFilter(); renderState = renderManager.getForcedRenderState(); } @@ -126,6 +129,7 @@ public void popRenderSettings() { renderManager.setForcedMaterial(forcedMat); renderManager.getRenderer().setFrameBuffer(frameBuffer); renderManager.setGeometryRenderHandler(geomRender); + renderManager.setRenderLogic(logic); renderManager.setRenderFilter(geomFilter); renderManager.setForcedRenderState(renderState); renderManager.getRenderer().setDepthRange(0, 1); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index c0fc6e5543..02f259c510 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -34,6 +34,7 @@ import com.jme3.asset.AssetManager; import com.jme3.renderer.framegraph.passes.DeferredPass; import com.jme3.renderer.framegraph.passes.GBufferPass; +import com.jme3.renderer.framegraph.passes.LightImagePass; import com.jme3.renderer.framegraph.passes.OutputBucketPass; import com.jme3.renderer.framegraph.passes.OutputPass; import com.jme3.renderer.framegraph.passes.PostProcessingPass; @@ -75,6 +76,7 @@ public static FrameGraph forward(AssetManager assetManager) { public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { FrameGraph fg = new FrameGraph(assetManager); GBufferPass gbuf = fg.add(new GBufferPass()); + LightImagePass lightImg = fg.add(new LightImagePass()); RenderPass deferred; if (!tiled) { deferred = fg.add(new DeferredPass()); @@ -88,16 +90,17 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { fg.add(new PostProcessingPass()); fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); + lightImg.makeInput(gbuf, "Lights", "Lights"); + + deferred.makeInput(lightImg, "Textures", "LightTextures"); + deferred.makeInput(lightImg, "NumLights", "NumLights"); + deferred.makeInput(lightImg, "Ambient", "Ambient"); + deferred.makeInput(lightImg, "Probes", "Probes"); + //deferred.makeInput(gbuf, "Lights", "Lights"); deferred.makeInput(gbuf, "GBufferData", "GBufferData"); -// deferred.makeInput(gbuf, "Diffuse", "Diffuse"); -// deferred.makeInput(gbuf, "Specular", "Specular"); -// deferred.makeInput(gbuf, "Emissive", "Emissive"); -// deferred.makeInput(gbuf, "Normal", "Normal"); -// deferred.makeInput(gbuf, "Depth", "Depth"); -// deferred.makeInput(gbuf, "Lights", "Lights"); defOut.makeInput(deferred, "Color", "Color"); - defOut.makeInput(gbuf, "Depth", "Depth"); + defOut.makeInput(gbuf, "GBufferData[4]", "Depth"); return fg; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 20394aebba..00ea15d994 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -51,7 +51,7 @@ public class RenderResource { private int refs = 0; private boolean survivesRefCull = false; private boolean undefined = false; - + /** * * @param producer @@ -89,8 +89,10 @@ public void release() { public void setObject(RenderObject object) { if (object != null) { setObject(object, object.getObject()); - } else if (this.object != null) { - this.object.release(); + } else { + if (this.object != null) { + this.object.release(); + } this.object = null; resource = null; } @@ -115,6 +117,15 @@ public void setObject(RenderObject object, T resource) { this.object.acquire(); ticket.setObjectId(this.object.getId()); } + /** + * Directly sets the concrete resource held by this render resource. + * + * @param resource + */ + public void setPrimitive(T resource) { + object = null; + this.resource = resource; + } /** * Marks this resource as undefined. */ @@ -207,7 +218,19 @@ public void setSurvivesRefCull(boolean survivesRefCull) { * @return */ public boolean isVirtual() { - return object == null && !undefined; + return resource == null && !undefined; + } + /** + * Returns true if this resource is primitive. + *

      + * A resource is primitive when it holds a concrete resource without a + * corresponding render object. Primitive resources are handled niavely, + * because they are not directly associated with a render object. + * + * @return + */ + public boolean isPrimitive() { + return resource != null && object == null; } /** * Returns true if this resource is referenced by users other than the diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 4079c917a9..0bd1598b6c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -107,7 +107,7 @@ protected RenderResource locate(ResourceTicket ticket) { * @param ticket * @return */ - protected boolean validate(ResourceTicket ticket) { + public boolean validate(ResourceTicket ticket) { return ticket != null && ticket.getWorldIndex() >= 0; } /** @@ -490,13 +490,19 @@ public T acquireDepthTarget(FrameBuffer fbo, ResourceTicket< /** * Directly assign the resource associated with the ticket to the value. + *

      + * A render object is not created to store the value. Instead, the render resource + * will directly store the value. Note that the value will be lost when the + * render resource is destroyed. + *

      + * This is intended to called in place of {@link #acquire(com.jme3.renderer.framegraph.ResourceTicket)}. * * @param * @param ticket * @param value */ - public void setDirect(ResourceTicket ticket, T value) { - map.allocateDirect(locate(ticket), value); + public void setPrimitive(ResourceTicket ticket, T value) { + locate(ticket).setPrimitive(value); } protected T extract(RenderResource resource, ResourceTicket ticket) { @@ -557,10 +563,17 @@ public void release(ResourceTicket ticket) { cap.releaseObject(resource.getObject().getId()); } remove(ticket.getWorldIndex()); - if (resource.getDefinition().isDisposeOnRelease()) { - map.dispose(resource); + if (!resource.isVirtual() && !resource.isUndefined()) { + ResourceDef def = resource.getDefinition(); + if (def != null && def.isDisposeOnRelease()) { + if (!resource.isPrimitive()) { + map.dispose(resource); + } else { + resource.getDefinition().dispose(resource.getResource()); + } + } + resource.setObject(null); } - resource.setObject(null); } } /** @@ -631,7 +644,7 @@ public void cullUnreferenced() { if (!producer.dereference()) { // if producer is not referenced, dereference all input resources for (ResourceTicket t : producer.getInputTickets()) { - if (t.getWorldIndex() < 0) { + if (!validate(t)) { continue; } RenderResource r = locate(t); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index 43712233af..43eee9e065 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -109,4 +109,14 @@ public default boolean isDisposeOnRelease() { return false; } + /** + * Disposes the resource using the disposal method, if not null. + * + * @param resource + */ + public default void dispose(T resource) { + Consumer d = getDisposalMethod(); + if (d != null) d.accept(resource); + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 94f76af184..13761da2bf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -146,13 +146,13 @@ public void accept(T t) { t.getImage().dispose(); } - private T createTexture(Image img) { + protected T createTexture(Image img) { T tex = textureBuilder.apply(img); tex.getImage().setMultiSamples(samples); setupTexture(tex); return tex; } - private void setupTexture(Texture tex) { + protected void setupTexture(Texture tex) { if (magFilter != null) { tex.setMagFilter(magFilter); } @@ -168,17 +168,23 @@ private void setupTexture(Texture tex) { if (wrapT != null) { tex.setWrap(Texture.WrapAxis.T, wrapT); } - if (wrapR != null) { + if (wrapR != null && depth > 0) { tex.setWrap(Texture.WrapAxis.R, wrapR); } } - private boolean validateImage(Image img) { - return img.getWidth() == width && img.getHeight() == height && (depth == 0 || img.getDepth() == depth) + protected boolean validateImage(Image img) { + return validateImageSize(img) && (samples <= 0 || img.getMultiSamples() == samples) - && (img.getFormat() == format || (formatFlexible && img.getFormat().isDepthFormat() == format.isDepthFormat())) + && validateImageFormat(img) && (colorSpaceFlexible || img.getColorSpace() == colorSpace); } - + protected boolean validateImageSize(Image img) { + return img.getWidth() == width && img.getHeight() == height && (depth == 0 || img.getDepth() == depth); + } + protected boolean validateImageFormat(Image img) { + return img.getFormat() == format || (formatFlexible && img.getFormat().isDepthFormat() == format.isDepthFormat()); + } + /** * Sets the function that constructs a texture from an image. * @@ -278,6 +284,9 @@ public void setSize(int width, int height, int depth) { * @param d true to set depth */ public void setNumPixels(int pixels, boolean w, boolean h, boolean d) { + width = height = 1; + if (depth > 0) depth = 1; + else depth = 0; int n = 0; if (w) n++; if (h) n++; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java index 67a1fb2436..7a32cedd38 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java @@ -7,6 +7,7 @@ import com.jme3.light.DirectionalLight; import com.jme3.light.Light; import com.jme3.light.LightList; +import com.jme3.light.LightProbe; import com.jme3.light.PointLight; import com.jme3.light.SpotLight; import com.jme3.math.ColorRGBA; @@ -14,6 +15,7 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture2D; import com.jme3.texture.image.ImageRaster; +import java.util.List; /** * @@ -24,6 +26,7 @@ public class LightImagePacker { private final Texture2D[] textures = new Texture2D[3]; private final ImageRaster[] rasters = new ImageRaster[3]; private final ColorRGBA tempColor = new ColorRGBA(); + private boolean hasAmbient = false; public LightImagePacker() {} @@ -41,51 +44,55 @@ public Texture2D getTexture(int i) { return textures[i]; } - public void packLightsToTextures(LightList lights) { + public int packLights(LightList lights, ColorRGBA ambient, List probes) { + ambient.set(0, 0, 0, 1); + probes.clear(); if (lights.size() == 0) { - return; + return 0; } - int x = 0, y = 0; - int w = textures[0].getImage().getWidth(); - int h = textures[0].getImage().getHeight(); + int numLights = 0; + int i = 0; + int limit = textures[0].getImage().getWidth(); boolean spotlight = false; + hasAmbient = false; for (Light l : lights) { - if (l.getType() == Light.Type.Ambient || l.getType() == Light.Type.Probe) { + if (l.getType() == Light.Type.Ambient) { + ambient.addLocal(l.getColor()); + hasAmbient = true; + continue; + } + if (l.getType() == Light.Type.Probe) { + probes.add((LightProbe)l); continue; } tempColor.set(l.getColor()).setAlpha(l.getType().getId()); - rasters[0].setPixel(x, y, tempColor); + rasters[0].setPixel(i, 0, tempColor); switch (l.getType()) { case Directional: DirectionalLight dl = (DirectionalLight)l; - vectorToColor(dl.getDirection(), tempColor); - rasters[1].setPixel(x, y, tempColor); + vectorToColor(dl.getDirection(), tempColor).a = 0; + rasters[1].setPixel(i, 0, tempColor); break; case Point: PointLight pl = (PointLight)l; vectorToColor(pl.getPosition(), tempColor); tempColor.a = pl.getInvRadius(); - rasters[1].setPixel(x, y, tempColor); + rasters[1].setPixel(i, 0, tempColor); break; case Spot: SpotLight sl = (SpotLight)l; vectorToColor(sl.getPosition(), tempColor); tempColor.a = sl.getInvSpotRange(); - rasters[1].setPixel(x, y, tempColor); - // 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. + rasters[1].setPixel(i, 0, tempColor); vectorToColor(sl.getDirection(), tempColor); tempColor.a = sl.getPackedAngleCos(); - rasters[2].setPixel(x, y, tempColor); + rasters[2].setPixel(i, 0, tempColor); spotlight = true; break; } - if (++x >= w) { - x = 0; - if (++y >= h) { - break; - } + numLights++; + if (++i >= limit) { + break; } } textures[0].getImage().setUpdateNeeded(); @@ -93,6 +100,11 @@ public void packLightsToTextures(LightList lights) { if (spotlight) { textures[2].getImage().setUpdateNeeded(); } + return numLights; + } + + public boolean hasAmbientLight() { + return hasAmbient; } private void validateSamples(Texture2D tex) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index c34dca91a2..c607aea0fd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -32,49 +32,95 @@ package com.jme3.renderer.framegraph.passes; import com.jme3.asset.AssetManager; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; import com.jme3.light.LightList; +import com.jme3.light.LightProbe; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; import com.jme3.material.Material; import com.jme3.material.TechniqueDef; -import com.jme3.material.logic.DeferredSinglePassLightingLogic; +import com.jme3.material.logic.SkyLightAndReflectionProbeRender; +import com.jme3.material.logic.TechniqueDefLogic; import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.Renderer; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.TextureDef; +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.FrameBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; +import com.jme3.texture.image.ImageRaster; +import java.io.IOException; +import java.util.EnumSet; +import java.util.LinkedList; +import java.util.List; /** * Renders GBuffer information using deferred lighting to a color texture. * * @author codex */ -public class DeferredPass extends RenderPass { +public class DeferredPass extends RenderPass implements TechniqueDefLogic { + private static Defines defs; + private static final List localProbeList = new LinkedList<>(); + + private boolean tiled = false; private AssetManager assetManager; - private ResourceTicket[] gbuffers; private ResourceTicket outColor; private ResourceTicket lights; - private ResourceTicket numRenders; + private ResourceTicket numLights; + private ResourceTicket ambient; + private ResourceTicket> probes; private TextureDef colorDef; private Material material; + private Texture2D[] lightTextures = new Texture2D[3]; private int maxLights = 1000; + private ColorRGBA ambientColor = new ColorRGBA(); + private List probeList; + + public DeferredPass() {} + public DeferredPass(boolean tiled) { + this.tiled = tiled; + } @Override protected void initialize(FrameGraph frameGraph) { - gbuffers = addInputGroup("GBufferData", 5); + // Lighting Arguments: + // IF LightTextures = undefined + // EITHER provide raw light list + // OR provide processed light list (without ambient or probes), ambient color, and probe list. + // ELSE provide 3 light textures, number of lights, ambient color, and probe list. + addInputGroup("GBufferData", 5); lights = addInput("Lights"); - numRenders = addInput("NumRenders"); + addInputGroup("LightTextures", 3); + numLights = addInput("NumLights"); + ambient = addInput("Ambient"); + probes = addInput("Probes"); outColor = addOutput("Color"); colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); colorDef.setFormatFlexible(true); - //colorDef.setUseExisting(false); assetManager = frameGraph.getAssetManager(); material = new Material(assetManager, "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); - for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { - t.setLogic(new DeferredSinglePassLightingLogic(t)); + if (defs == null) { + defs = new Defines(); + for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { + defs.config(t); + } } } @Override @@ -82,8 +128,10 @@ protected void prepare(FGRenderContext context) { colorDef.setSize(context.getWidth(), context.getHeight()); declare(colorDef, outColor); reserve(outColor); - reference(gbuffers); - referenceOptional(lights, numRenders); + // groups are stored by hashmap, which makes it absolutely fine to fetch every frame + reference(getGroup("GBufferData")); + referenceOptional(lights, numLights, ambient, probes); + referenceOptional(getGroup("LightTextures")); } @Override protected void execute(FGRenderContext context) { @@ -92,28 +140,174 @@ protected void execute(FGRenderContext context) { context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); - material.setTexture("Context_InGBuff0", resources.acquire(gbuffers[0])); - material.setTexture("Context_InGBuff1", resources.acquire(gbuffers[1])); - material.setTexture("Context_InGBuff2", resources.acquire(gbuffers[2])); - material.setTexture("Context_InGBuff3", resources.acquire(gbuffers[3])); - material.setTexture("Context_InGBuff4", resources.acquire(gbuffers[4])); + ResourceTicket[] gbuffers = getGroup("GBufferData"); + for (int i = 0; i < gbuffers.length; i++) { + material.setTexture("GBuffer"+i, resources.acquire(gbuffers[i])); + } material.selectTechnique("DeferredPass", context.getRenderManager()); - LightList lightList = resources.acquireOrElse(lights, null); - if (lightList != null) { - material.setInt("NBLights", lightList.size()); - context.getScreen().render(context.getRenderManager(), material, lightList); + material.getActiveTechnique().getDef().setLogic(this); + acquireGroupOrElse("LightTextures", lightTextures, null); + if (lightTextures[0] == null) { + context.getScreen().render(context.getRenderManager(), material, resources.acquire(lights)); } else { - material.setInt("NBLights", 0); + for (int i = 1; i <= lightTextures.length; i++) { + material.setTexture("LightTex"+i, lightTextures[i-1]); + } context.renderFullscreen(material); } + material.getActiveTechnique().getDef().setLogic(null); } @Override protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} @Override - public boolean isUsed() { - return true; + public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, + EnumSet rendererCaps, LightList lights, DefineList defines) { + // defines should only be set in this method + boolean useLightTex = lightTextures[0] != null; + defines.set(defs.useTextures, useLightTex); + if (!useLightTex) { + ColorRGBA amb = resources.acquireOrElse(ambient, null); + if (amb == null) { + probeList = localProbeList; + // extract ambient and probes from light list + SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes( + lights, ambientColor, probeList, true); + } else { + // lights are already processed: get ambient and probes from resources + ambientColor.set(amb); + probeList = resources.acquire(probes); + } + defines.set(defs.numLights, lights.size()*3); + } else { + // get resources for lighting with textures + ambientColor.set(resources.acquire(ambient)); + probeList = resources.acquire(probes); + defines.set(defs.numLights, resources.acquire(numLights)); + } + defines.set(defs.numProbes, Math.min(probeList.size(), 3)); + return material.getActiveTechnique().getDef().getShader(assetManager, rendererCaps, defines); + } + @Override + public void render(RenderManager rm, Shader shader, Geometry geometry, + LightList lights, Material.BindUnits lastBindUnits) { + Renderer renderer = rm.getRenderer(); + injectShaderGlobals(rm, shader, lastBindUnits.textureUnit); + if (lightTextures[0] == null) { + // pass light data by uniforms + injectLightBuffers(shader, lights); + } else { + // pass light data by textures + injectLightTextures(shader); + } + renderer.setShader(shader); + TechniqueDefLogic.renderMeshFromGeometry(renderer, geometry); + probeList = null; + } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + out.write(tiled, "tiled", false); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + tiled = in.readBoolean("tiled", false); + } + + private void injectShaderGlobals(RenderManager rm, Shader shader, int lastTexUnit) { + shader.getUniform("g_AmbientLightColor").setValue(VarType.Vector4, ambientColor); + if (probeList != null && !probeList.isEmpty()) { + int i = 0; + // inject light probes + for (LightProbe p : probeList) { + String num = (++i > 1 ? String.valueOf(i) : ""); + Uniform sky = shader.getUniform("g_SkyLightData"+num); + Uniform coeffs = shader.getUniform("g_ShCoeffs"+num); + Uniform env = shader.getUniform("g_ReflectionEnvMap"+num); + lastTexUnit = SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData( + rm, lastTexUnit, sky, coeffs, env, p); + // shaders only support up to 3 probes at once + if (i == 3) break; + } + } else { + // disable light probes + shader.getUniform("g_SkyLightData").setValue(VarType.Matrix4, LightProbe.FALLBACK_MATRIX); + } + } + private void injectLightBuffers(Shader shader, LightList lights) { + // ambient lights and probes should already have been extracted at this point + Uniform data = shader.getUniform("g_LightData"); + int n = lights.size()*3; + data.setVector4Length(n); + int i = 0; + for (Light l : lights) { + Light.Type type = l.getType(); + writeColorToUniform(data, l.getColor(), type.getId(), i++); + switch (type) { + case Directional: + DirectionalLight dl = (DirectionalLight)l; + writeVectorToUniform(data, dl.getDirection(), -1, i++); + data.setVector4InArray(0, 0, 0, 0, i++); + break; + case Point: + PointLight pl = (PointLight)l; + writeVectorToUniform(data, pl.getPosition(), pl.getInvRadius(), i++); + data.setVector4InArray(0, 0, 0, 0, i++); + break; + case Spot: + SpotLight sl = (SpotLight)l; + writeVectorToUniform(data, sl.getPosition(), sl.getInvSpotRange(), i++); + writeVectorToUniform(data, sl.getDirection(), sl.getPackedAngleCos(), i++); + break; + case Ambient: + case Probe: + throw new IllegalStateException("Internal: ambient and probe lights should not be present."); + default: + throw new UnsupportedOperationException("Light "+type+" not supported."); + } + } + // just in case, fill in the remaining elements + while (i < n) { + data.setVector4InArray(0, 0, 0, 0, i++); + } + } + private void injectLightTextures(Shader shader) { + int w = lightTextures[0].getImage().getWidth(); + shader.getUniform("m_LightTexInv").setValue(VarType.Vector2, new Vector2f(1f/w, 0)); + } + + private void writeVectorToUniform(Uniform uniform, Vector3f vec, float w, int i) { + uniform.setVector4InArray(vec.x, vec.y, vec.z, w, i); + } + private void writeColorToUniform(Uniform uniform, ColorRGBA color, float a, int i) { + uniform.setVector4InArray(color.r, color.g, color.b, a, i); + } + + /** + * Registers and tracks necessary define IDs for all deferred passes. + */ + private static class Defines { + + private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS"; + private static final String DEFINE_NB_PROBES = "NB_PROBES"; + private static final String DEFINE_USE_LIGHT_TEXTURES = "USE_LIGHT_TEXTURES"; + private static final String DEFINE_USE_AMBIENT_LIGHT = "USE_AMBIENT_LIGHT"; + + public int numLights, useTextures, numProbes, useAmbientLight; + + public Defines() {} + + public void config(TechniqueDef def) { + numLights = def.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int); + numProbes = def.addShaderUnmappedDefine(DEFINE_NB_PROBES, VarType.Int); + useTextures = def.addShaderUnmappedDefine(DEFINE_USE_LIGHT_TEXTURES, VarType.Boolean); + useAmbientLight = def.addShaderUnmappedDefine(DEFINE_USE_AMBIENT_LIGHT, VarType.Boolean); + } + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index b1b0488f7e..37d1a2c720 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -67,7 +67,6 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private ResourceTicket lights; private ResourceTicket numRendersTicket; private ValueDef lightDef; - private ValueDef numRendersDef; private final TextureDef[] texDefs = new TextureDef[5]; private final LinkedList accumulatedLights = new LinkedList<>(); private int numRenders = 0; @@ -85,9 +84,6 @@ protected void initialize(FrameGraph frameGraph) { texDefs[4] = new TextureDef<>(Texture2D.class, tex, Image.Format.Depth); lightDef = new ValueDef(LightList.class, n -> new LightList(null)); lightDef.setReviser(list -> list.clear()); - numRendersDef = new ValueDef(Boolean.class, n -> true); - numRendersDef.setUseExisting(false); - numRendersDef.setDisposeOnRelease(true); } @Override protected void prepare(FGRenderContext context) { @@ -97,7 +93,7 @@ protected void prepare(FGRenderContext context) { declare(texDefs[i], gbuffers[i]); } declare(lightDef, lights); - declare(numRendersDef, numRendersTicket); + declare(null, numRendersTicket); reserve(gbuffers); numRenders = 0; } @@ -106,7 +102,7 @@ protected void execute(FGRenderContext context) { // acquire texture targets FrameBuffer fb = getFrameBuffer(context, 1); fb.setMultiTarget(true); - //resources.setDirect(diffuse, diffuseTex); + //resources.setPrimitive(diffuse, diffuseTex); resources.acquireColorTargets(fb, gbuffers[0], gbuffers[1], gbuffers[2], gbuffers[3]); resources.acquireDepthTarget(fb, gbuffers[4]); context.getRenderer().setFrameBuffer(fb); @@ -120,7 +116,7 @@ protected void execute(FGRenderContext context) { while (!accumulatedLights.isEmpty()) { lightList.add(accumulatedLights.pollFirst()); } - resources.setDirect(numRendersTicket, numRenders); + resources.setPrimitive(numRendersTicket, numRenders); } @Override protected void reset(FGRenderContext context) {} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 8e7b163830..2135b8b35f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -52,7 +52,10 @@ */ public class Junction extends RenderPass { + private static final String INPUT = "Input"; + private int length; + private int groupSize; private ResourceTicket output; private GraphSource source; @@ -62,20 +65,60 @@ public Junction() { public Junction(int length) { setLength(length); } + public Junction(int length, int groupSize) { + setLength(length); + setGroupSize(groupSize); + } @Override protected void initialize(FrameGraph frameGraph) { for (int i = 0; i < length; i++) { - addInput("Input"+i); + if (groupSize > 1) { + addInputGroup(getInputName(i), groupSize); + } else { + addInput(getInputName(i)); + } + } + if (groupSize > 1) { + addOutputGroup("Value", groupSize); + } else { + output = addOutput("Value"); } - output = addOutput("Value"); } @Override protected void prepare(FGRenderContext context) { + int size; + if (groupSize > 1) { + size = getGroups().size(); + } else { + size = getInputTickets().size(); + } + // remove excess tickets + while (size > length) { + size--; + if (groupSize > 1) { + ResourceTicket[] array = removeGroup(getInputName(size)); + for (ResourceTicket t : array) { + t.setSource(null); + } + } else { + getInputTickets().removeLast().setSource(null); + } + } + // add deficit tickets + while (size < length) { + if (groupSize > 1) { + addInputGroup(getInputName(size), groupSize); + } else { + addInput(getInputName(size)); + } + size++; + } + // connect output to input if (source != null) { - output.setSource(getInputTickets().get(source.getGraphValue(context.getViewPort()))); + connect(source.getGraphValue(context.getViewPort())); } else { - output.setSource(getInputTickets().getFirst()); + connect(0); } } @Override @@ -86,19 +129,35 @@ protected void reset(FGRenderContext context) {} protected void cleanup(FrameGraph frameGraph) {} @Override public boolean isUsed() { - return true; + // This pass will never execute + return false; } @Override public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule out = ex.getCapsule(this); out.write(length, "length", 2); + out.write(groupSize, "groupSize", 1); } @Override public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule in = im.getCapsule(this); length = in.readInt("length", 2); + groupSize = in.readInt("groupSize", 1); + } + + private void connect(int i) { + boolean assignNull = i < 0 || i >= length; + if (groupSize > 1) { + ResourceTicket[] inArray = getGroup("Input"+i); + ResourceTicket[] outArray = getGroup("Value"); + for (int j = 0; j < groupSize; j++) { + outArray[j].setSource(assignNull ? null : inArray[j]); + } + } else { + output.setSource(assignNull ? null : getInputTickets().get(i)); + } } public final void setLength(int length) { @@ -107,6 +166,15 @@ public final void setLength(int length) { } this.length = length; } + public final void setGroupSize(int groupSize) { + if (isAssigned()) { + throw new IllegalStateException("Cannot alter group size after initialization."); + } + if (groupSize <= 0) { + throw new IllegalArgumentException("Group length must be greater than zero."); + } + this.groupSize = groupSize; + } public void setIndexSource(GraphSource source) { this.source = source; } @@ -114,8 +182,15 @@ public void setIndexSource(GraphSource source) { public int getLength() { return length; } + public int getGroupSize() { + return groupSize; + } public GraphSource getIndexSource() { return source; } + public static String getInputName(int i) { + return INPUT+i; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java index 861ec4185f..7ef6af2b25 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java @@ -4,7 +4,13 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; import com.jme3.light.LightList; +import com.jme3.light.LightProbe; +import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; @@ -13,6 +19,11 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; +import com.jme3.util.BufferUtils; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.List; /** * @@ -22,22 +33,25 @@ public class LightImagePass extends RenderPass { private LightImagePacker packer = new LightImagePacker(); private ResourceTicket lights; - private ResourceTicket[] textures = new ResourceTicket[3]; - private TextureDef texDef; - private int maxLights = 500; + private ResourceTicket[] textures; + private ResourceTicket numLights; + private ResourceTicket ambientColor; + private ResourceTicket> probes; + private final LightTextureDef texDef = new LightTextureDef(512); + private final ColorRGBA ambient = new ColorRGBA(); + private final LinkedList probeList = new LinkedList<>(); @Override protected void initialize(FrameGraph frameGraph) { lights = addInput("Lights"); - textures[0] = addOutput("Texture1"); - textures[1] = addOutput("Texture2"); - textures[2] = addOutput("Texture3"); - texDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); + textures = addOutputGroup("Textures", 3); + numLights = addOutput("NumLights"); + ambientColor = addOutput("Ambient"); + probes = addOutput("Probes"); texDef.setFormat(Image.Format.RGBA32F); texDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); texDef.setMagFilter(Texture.MagFilter.Nearest); texDef.setWrap(Texture.WrapMode.EdgeClamp); - texDef.setNumPixels(maxLights, true, true, false); } @Override protected void prepare(FGRenderContext context) { @@ -45,6 +59,9 @@ protected void prepare(FGRenderContext context) { declare(texDef, t); reserve(t); } + declare(null, numLights); + declare(null, ambientColor); + declare(null, probes); reference(lights); } @Override @@ -53,11 +70,59 @@ protected void execute(FGRenderContext context) { resources.acquire(textures[0]), resources.acquire(textures[1]), resources.acquire(textures[2])); - packer.packLightsToTextures(resources.acquire(lights)); + int n = packer.packLights(resources.acquire(lights), ambient, probeList); + resources.setPrimitive(numLights, n); + resources.setPrimitive(ambientColor, ambient); + resources.setPrimitive(probes, probeList); } @Override protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + out.write(texDef.getWidth(), "maxLights", 512); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + texDef.setWidth(in.readInt("maxLights", 512)); + } + + public int getMaxLights() { + return texDef.getWidth(); + } + + public void setMaxLights(int maxLights) { + texDef.setWidth(maxLights); + } + + private static class LightTextureDef extends TextureDef { + + public LightTextureDef(int maxLights) { + super(Texture2D.class, img -> new Texture2D(img)); + setWidth(maxLights); + super.setHeight(1); + super.setDepth(0); + } + + @Override + public Texture2D createResource() { + Image.Format format = getFormat(); + int width = getWidth(); + ByteBuffer data = BufferUtils.createByteBuffer((int)Math.ceil(format.getBitsPerPixel()/8)*width); + Image img = new Image(format, width, 1, data, null, getColorSpace()); + img.setMipmapsGenerated(false); + return createTexture(img); + } + @Override + public void setHeight(int height) {} + @Override + public void setDepth(int depth) {} + + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightListExtractPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightListExtractPass.java new file mode 100644 index 0000000000..9f8fe0128d --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightListExtractPass.java @@ -0,0 +1,77 @@ +/* + * 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.passes; + +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.light.LightProbe; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import java.util.LinkedList; +import java.util.List; + +/** + * Extracts ambient light and light probes from a LightList. + * + * @author codex + */ +public class LightListExtractPass extends RenderPass { + + private ResourceTicket inLights, outLights; + private ResourceTicket ambient; + private ResourceTicket> probes; + private final LightList outLightList = new LightList(null); + private final ColorRGBA ambColor = new ColorRGBA(0, 0, 0, 1); + private final List probeList = new LinkedList<>(); + + @Override + protected void initialize(FrameGraph frameGraph) { + inLights = addInput("Lights"); + outLights = addOutput("Lights"); + ambient = addOutput("Ambient"); + probes = addOutput("Probes"); + } + @Override + protected void prepare(FGRenderContext context) { + referenceOptional(inLights); + declare(null, outLights); + declare(null, ambient); + declare(null, probes); + } + @Override + protected void execute(FGRenderContext context) { + LightList list = resources.acquireOrElse(inLights, null); + if (list != null) { + ambColor.set(0, 0, 0, 1); + for (Light l : list) switch (l.getType()) { + case Ambient: + ambColor.addLocal(l.getColor()); + break; + case Probe: + probeList.add((LightProbe)l); + break; + default: + outLightList.add(l); + } + resources.setPrimitive(outLights, outLightList); + resources.setPrimitive(ambient, ambColor); + resources.setPrimitive(probes, probeList); + } else { + resources.setUndefined(outLights); + resources.setUndefined(ambient); + resources.setUndefined(probes); + } + } + @Override + protected void reset(FGRenderContext context) { + outLightList.clear(); + probeList.clear(); + } + @Override + protected void cleanup(FrameGraph frameGraph) {} + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index c33763f054..d31366047d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -279,6 +279,44 @@ protected void referenceOptional(ResourceTicket... tickets) { referenceOptional(t); } } + + /** + * Acquires a set of resources from a ticket group and stores them in + * the array. + * + * @param + * @param name + * @param array + * @return + */ + protected T[] acquireGroup(String name, T[] array) { + ResourceTicket[] tickets = Objects.requireNonNull(getGroup(name), "Ticket group cannot be null."); + int n = Math.min(array.length, tickets.length); + for (int i = 0; i < n; i++) { + array[i] = resources.acquire(tickets[i]); + } + return array; + } + /** + * Acquires a set of resources from a ticket group and stores them in + * the array. + *

      + * Tickets that are invalid will acquire {@code val}. + * + * @param + * @param name + * @param array + * @param val + * @return + */ + protected T[] acquireGroupOrElse(String name, T[] array, T val) { + ResourceTicket[] tickets = Objects.requireNonNull(getGroup(name), "Ticket group cannot be null."); + int n = Math.min(array.length, tickets.length); + for (int i = 0; i < n; i++) { + array[i] = resources.acquireOrElse(tickets[i], val); + } + return array; + } /** * Releases all reasources associated with any registered ticket. *

      @@ -376,7 +414,7 @@ protected ResourceTicket[] addOutputGroup(String name, ResourceTicket. /** * Creates and adds a ticket array as a group input of the specified length under the given name. *

      - * Each ticket is named the given name suffixed by the array index. + * Each ticket's name is formatted as the {@code groupName+"["+index+"]"}. * * @param * @param name @@ -386,7 +424,7 @@ protected ResourceTicket[] addOutputGroup(String name, ResourceTicket. protected ResourceTicket[] addInputGroup(String name, int length) { ResourceTicket[] array = new ResourceTicket[length]; for (int i = 0; i < length; i++) { - addInput(array[i] = new ResourceTicket<>(name+i)); + addInput(array[i] = new ResourceTicket<>(name+"["+i+"]")); } groups.put(name, array); return array; @@ -394,7 +432,7 @@ protected ResourceTicket[] addInputGroup(String name, int length) { /** * Creates and adds a ticket array as a group output of the specified length under the given name. *

      - * Each ticket is named the given name suffixed by the array index. + * Each ticket's name is formatted as the {@code groupName+"["+index+"]"}. * * @param * @param name @@ -404,12 +442,38 @@ protected ResourceTicket[] addInputGroup(String name, int length) { protected ResourceTicket[] addOutputGroup(String name, int length) { ResourceTicket[] array = new ResourceTicket[length]; for (int i = 0; i < length; i++) { - addOutput(array[i] = new ResourceTicket<>(name+i)); + addOutput(array[i] = new ResourceTicket<>(name+"["+i+"]")); } groups.put(name, array); return array; } + /** + * Removes all members of the named group from the input and output lists. + * + * @param + * @param name + * @return + */ + protected ResourceTicket[] removeGroup(String name) { + ResourceTicket[] array = groups.remove(name); + if (array == null) { + return null; + } + // Once we determine which list group members were added to, we only + // need to remove from that list for future members. + byte state = 0; + for (ResourceTicket t : array) { + if (state >= 0 && inputs.remove(t)) { + state = 1; + } + if (state <= 0 && outputs.remove(t)) { + state = -1; + } + } + return array; + } + /** * Gets the named input ticket, or null if none exists. * @@ -646,6 +710,13 @@ public int getIndex() { public boolean isAssigned() { return index >= 0; } + /** + * + * @return + */ + protected HashMap getGroups() { + return groups; + } @Override public int getExecutionIndex() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java index 39131b820a..1c7a9ce10a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java @@ -1434,6 +1434,7 @@ assert isValidNumber(fb) : "Invalid Matrix4f array value " gl.glUniform1i(loc, i.intValue()); break; default: + System.out.println("uniform value = "+uniform.getValue().toString()); throw new UnsupportedOperationException( "Unsupported uniform type: " + uniform.getVarType() + " for " + uniform.getBinding()); } 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 d4ee84fc51..f981fdd841 100644 --- a/jme3-core/src/main/java/com/jme3/shader/DefineList.java +++ b/jme3-core/src/main/java/com/jme3/shader/DefineList.java @@ -139,6 +139,10 @@ public float getFloat(int id) { public int getInt(int id) { return values[id]; } + + public int size() { + return values.length; + } @Override public int hashCode() { diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag index ada4c37dc5..a7a8b89eab 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag @@ -181,8 +181,8 @@ void main(){ #endif // pack - Context_OutGBuff3.xyz = normal; - Context_OutGBuff0.a = alpha; + outGBuffer3.xyz = normal; + outGBuffer0.a = alpha; // #ifdef USE_REFLECTION // vec4 refColor = Optics_GetEnvColor(m_EnvMap, refVec.xyz); @@ -203,10 +203,10 @@ void main(){ // 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; + outGBuffer0.rgb = diffuseColor.rgb * DiffuseSum.rgb; + outGBuffer1.rgb = specularColor.rgb * SpecularSum.rgb * 100.0f + AmbientSum * 0.01f; + outGBuffer1.a = m_Shininess; // shading model id - Context_OutGBuff2.a = PHONG_LIGHTING; + outGBuffer2.a = PHONG_LIGHTING; } 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 6ab4f2031d..a3ca3b1ac0 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -23,13 +23,10 @@ uniform vec3 g_CameraPosition; uniform int m_NBLights; #ifdef USE_LIGHT_TEXTURES - //uniform int g_LightCount; - uniform sampler2D m_NBLightss; uniform sampler2D m_LightTex1; uniform sampler2D m_LightTex2; uniform sampler2D m_LightTex3; - uniform vec2 m_LightTexSize; - uniform vec2 m_LightTexInv; + uniform float m_LightTexInv; #else uniform vec4 g_LightData[NB_LIGHTS]; #endif @@ -44,8 +41,7 @@ void main(){ // unpack m_GBuffer vec4 shadingInfo = texture2D(m_GBuffer2, innerTexCoord); int shadingModelId = int(floor(shadingInfo.a)); - - float depth = texture2D(m_DepthGBuffer, texCoord).r; + float depth = texture2D(m_GBuffer4, innerTexCoord).r; gl_FragDepth = depth; // Due to GPU architecture, each shading mode is performed for each pixel, which is very inefficient. // TODO: Remove these if statements if possible. @@ -59,24 +55,16 @@ void main(){ float shininess = buff1.a; float alpha = diffuseColor.a; vec3 normal = texture2D(m_GBuffer3, innerTexCoord).xyz; - vec3 viewDir = normalize(g_CameraPosition - vPos); + vec3 viewDir = normalize(g_CameraPosition - vPos); gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; gl_FragColor.a = alpha; //int lightNum = 0; - #ifdef USE_LIGHT_TEXTURES - float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f); - int x = 0; - int y = 0; - #endif - for (int i = 0; i < m_NBLights;) { + for (int i = 0; i < NB_LIGHTS;) { #ifdef USE_LIGHT_TEXTURES - vec2 pixel = vec2(x, y) * m_LightTexInv; + vec2 pixel = vec2(i, 0); + pixel.x *= m_LightTexInv; vec4 lightColor = texture2D(m_LightTex1, pixel); vec4 lightData1 = texture2D(m_LightTex2, pixel); - if (++x >= m_LightTexSize.x) { - x = 0; - y++; - } #else vec4 lightColor = g_LightData[i]; vec4 lightData1 = g_LightData[i+1]; @@ -91,38 +79,24 @@ void main(){ if (lightColor.w > 1.0) { #endif #ifdef USE_LIGHT_TEXTURES - spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); + spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); #else - spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); #endif #if __VERSION__ >= 110 } #endif #ifdef NORMALMAP - //Normal map -> lighting is computed in tangent space + // Normal map -> lighting is computed in tangent space lightDir.xyz = normalize(lightDir.xyz * tbnMat); #else - //no Normal map -> lighting is computed in view space + // 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); #ifdef USE_LIGHT_TEXTURES @@ -131,6 +105,9 @@ void main(){ i += 3; #endif } + if (NB_LIGHTS < 10) { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } } else if (shadingModelId == PBR_LIGHTING) { // PBR shading vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); @@ -147,25 +124,16 @@ void main(){ vec4 n1n2 = texture2D(m_GBuffer3, innerTexCoord); vec3 normal = octDecode(n1n2.xy); vec3 norm = octDecode(n1n2.zw); - vec3 viewDir = normalize(g_CameraPosition - vPos); + vec3 viewDir = normalize(g_CameraPosition - vPos); float ndotv = max( dot( normal, viewDir ),0.0); int lightNum = 0; - #ifdef USE_LIGHT_TEXTURES - float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f); - int x = 0; - int y = 0; - #else - #endif gl_FragColor.rgb = vec3(0.0); - for (int i = 0; i < m_NBLights;) { + for (int i = 0; i < NB_LIGHTS;) { #ifdef USE_LIGHT_TEXTURES - vec2 pixel = vec2(x, y) * m_LightTexInv; + vec2 pixel = vec2(i, 0); + pixel.x *= m_LightTexInv; vec4 lightColor = texture2D(m_LightTex1, pixel); vec4 lightData1 = texture2D(m_LightTex2, pixel); - if (++x >= m_LightTexSize.x) { - x = 0; - y++; - } #else vec4 lightColor = g_LightData[i]; vec4 lightData1 = g_LightData[i+1]; @@ -214,10 +182,10 @@ void main(){ #endif } // skyLight and reflectionProbe - vec3 skyLightAndReflection = renderSkyLightAndReflectionProbes( + vec3 skyLight = renderSkyLightAndReflectionProbes( indoorSunLightExposure, viewDir, vPos, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao); - gl_FragColor.rgb += skyLightAndReflection; + gl_FragColor.rgb += skyLight; gl_FragColor.rgb += emissive; gl_FragColor.a = alpha; gl_FragColor.rgb = vec3(1-lightNum); 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 4f80ed7f98..d7a46be786 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md @@ -1,10 +1,6 @@ MaterialDef DeferredShading { MaterialParameters { - - Int NBLights - Boolean UseLightsCullMode - Boolean UseLightTextures // GBuffer Data Texture2D GBuffer0 @@ -17,7 +13,7 @@ MaterialDef DeferredShading { Texture2D LightTex1 Texture2D LightTex2 Texture2D LightTex3 - Vector2 LightTexSize + Int LightTexSize Vector2 LightTexInv } @@ -34,12 +30,7 @@ MaterialDef DeferredShading { ViewProjectionMatrix ResolutionInverse } - - Defines { - USE_LIGHTS_CULL_MODE : UseLightsCullMode - USE_LIGHT_TEXTURES : UseLightTextures - NB_LIGHTS : NBLights - } + } } diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib index b81b1370b7..a3a5a14f4f 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib @@ -22,7 +22,7 @@ uniform sampler2D m_GBuffer0; uniform sampler2D m_GBuffer1; uniform sampler2D m_GBuffer2; uniform sampler2D m_GBuffer3; -uniform sampler2D m_DepthGBuffer; +uniform sampler2D m_GBuffer4; //#endif vec3 decodeNormal(in vec4 enc){ @@ -44,7 +44,7 @@ vec3 getPosition(in vec2 texCoord, in float depth, in mat4 matrixInverse){ } vec3 getPosition(in vec2 texCoord, in mat4 matrixInverse){ - return getPosition(texCoord, texture2D(depthGBuffer, texCoord).r, matrixInverse); + return getPosition(texCoord, texture2D(m_GBuffer4, texCoord).r, matrixInverse); } diff --git a/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib index 54a103f869..3b3326cb35 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib @@ -1,25 +1,27 @@ -// 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; +#if NB_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; +#if NB_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; +#if NB_PROBES == 3 + uniform samplerCube g_ReflectionEnvMap3; + uniform vec3 g_ShCoeffs3[9]; + uniform mat4 g_SkyLightData3; #endif -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 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); - #if NB_SKY_LIGHT_AND_REFLECTION_PROBES >= 1 + #if NB_PROBES >= 1 vec3 color1 = vec3(0.0); vec3 color2 = vec3(0.0); vec3 color3 = vec3(0.0); @@ -28,27 +30,27 @@ vec3 renderSkyLightAndReflectionProbes(in float indoorSunLightExposure, in vec3 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 + #if NB_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 + #if NB_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 + #if NB_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 + #if NB_PROBES == 3 float invNdf3 = max(1.0 - ndf3,0.0); sumNdf += ndf3; sumInvNdf += invNdf3; - weight3 = ((1.0 - (ndf3 / sumNdf)) / (NB_PROBES - 1)) * (invNdf3 / sumInvNdf); + 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); + 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; @@ -70,4 +72,3 @@ vec3 renderSkyLightAndReflectionProbes(in float indoorSunLightExposure, in vec3 #endif return result; } -// END@render skyLights and reflectionProbe \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 2ed6c3c113..785207773e 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -666,13 +666,13 @@ public void simpleInitApp() { FrameGraph forward = new FrameGraph(assetManager, "Common/FrameGraphs/Forward.j3g"); forward.setName("forward"); //FrameGraph deferred = new FrameGraph(assetManager, "Common/FrameGraphs/Deferred.j3g"); - FrameGraph deferred = FrameGraphFactory.deferred(assetManager, true); + FrameGraph deferred = FrameGraphFactory.deferred(assetManager, false); deferred.setName("deferred1"); - FrameGraph deferred2 = FrameGraphFactory.deferred(assetManager, false); - deferred2.setName("deferred2"); + //FrameGraph deferred2 = FrameGraphFactory.deferred(assetManager, false); + //deferred2.setName("deferred2"); //FrameGraph graph = FrameGraphFactory.forward(assetManager, renderManager); viewPort.setFrameGraph(deferred); - guiViewPort.setFrameGraph(deferred); + //guiViewPort.setFrameGraph(deferred); //renderManager.setFrameGraph(deferred); //renderManager.setFrameGraph(forward); @@ -696,11 +696,11 @@ public void simpleInitApp() { Material debugMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); //debugMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha); debugView.setMaterial(debugMat); - MatParamTargetControl texTarget = new MatParamTargetControl("ColorMap", VarType.Texture2D); - texTarget.setViewPorts(viewPort); - deferred.get(Attribute.class, "GBufferDebug").addTarget(texTarget); - debugView.addControl(texTarget); - guiNode.attachChild(debugView); + //MatParamTargetControl texTarget = new MatParamTargetControl("ColorMap", VarType.Texture2D); + //texTarget.setViewPorts(viewPort); + //deferred.get(Attribute.class, "GBufferDebug").addTarget(texTarget); + //debugView.addControl(texTarget); + //guiNode.attachChild(debugView); Geometry g = new Geometry("test", new Box(1, 1, 1)); g.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); From 8a969c90e7111e4b1c6ff6fc9d8d1c33c04fa9e7 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 14 Jun 2024 20:52:19 -0400 Subject: [PATCH 083/111] fixed light tex inverse type --- .../framegraph/light/LightImagePacker.java | 18 +++++++++-------- .../framegraph/passes/DeferredPass.java | 3 ++- .../framegraph/passes/LightImagePass.java | 2 +- .../ShadingCommon/DeferredShading.frag | 20 +++++++++---------- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java index 7a32cedd38..923db82336 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java @@ -50,9 +50,9 @@ public int packLights(LightList lights, ColorRGBA ambient, List prob if (lights.size() == 0) { return 0; } - int numLights = 0; int i = 0; - int limit = textures[0].getImage().getWidth(); + final int limit = textures[0].getImage().getWidth(); + boolean packedLight = false; boolean spotlight = false; hasAmbient = false; for (Light l : lights) { @@ -65,6 +65,7 @@ public int packLights(LightList lights, ColorRGBA ambient, List prob probes.add((LightProbe)l); continue; } + packedLight = true; tempColor.set(l.getColor()).setAlpha(l.getType().getId()); rasters[0].setPixel(i, 0, tempColor); switch (l.getType()) { @@ -90,17 +91,18 @@ public int packLights(LightList lights, ColorRGBA ambient, List prob spotlight = true; break; } - numLights++; if (++i >= limit) { break; } } - textures[0].getImage().setUpdateNeeded(); - textures[1].getImage().setUpdateNeeded(); - if (spotlight) { - textures[2].getImage().setUpdateNeeded(); + if (packedLight) { + textures[0].getImage().setUpdateNeeded(); + textures[1].getImage().setUpdateNeeded(); + if (spotlight) { + textures[2].getImage().setUpdateNeeded(); + } } - return numLights; + return i; } public boolean hasAmbientLight() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index c607aea0fd..694d7e1682 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -186,6 +186,7 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager probeList = resources.acquire(probes); defines.set(defs.numLights, resources.acquire(numLights)); } + //defines.set(defs.numLights, 1); defines.set(defs.numProbes, Math.min(probeList.size(), 3)); return material.getActiveTechnique().getDef().getShader(assetManager, rendererCaps, defines); } @@ -277,7 +278,7 @@ private void injectLightBuffers(Shader shader, LightList lights) { } private void injectLightTextures(Shader shader) { int w = lightTextures[0].getImage().getWidth(); - shader.getUniform("m_LightTexInv").setValue(VarType.Vector2, new Vector2f(1f/w, 0)); + shader.getUniform("m_LightTexInv").setValue(VarType.Float, 1f/w); } private void writeVectorToUniform(Uniform uniform, Vector3f vec, float w, int i) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java index 7ef6af2b25..9cec0b57b8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java @@ -115,7 +115,7 @@ public Texture2D createResource() { int width = getWidth(); ByteBuffer data = BufferUtils.createByteBuffer((int)Math.ceil(format.getBitsPerPixel()/8)*width); Image img = new Image(format, width, 1, data, null, getColorSpace()); - img.setMipmapsGenerated(false); + //img.setMipmapsGenerated(false); return createTexture(img); } @Override 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 a3ca3b1ac0..018e465774 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -61,8 +61,7 @@ void main(){ //int lightNum = 0; for (int i = 0; i < NB_LIGHTS;) { #ifdef USE_LIGHT_TEXTURES - vec2 pixel = vec2(i, 0); - pixel.x *= m_LightTexInv; + vec2 pixel = vec2(m_LightTexInv * i, 0); vec4 lightColor = texture2D(m_LightTex1, pixel); vec4 lightData1 = texture2D(m_LightTex2, pixel); #else @@ -95,19 +94,21 @@ void main(){ lightDir.xyz = normalize(lightDir.xyz); #endif - vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , shininess); - + vec2 light = computeLighting(normal, viewDir, lightDir.xyz, + lightDir.w * spotFallOff, shininess); + gl_FragColor.rgb += lightColor.rgb * diffuseColor.rgb * vec3(light.x) + - lightColor.rgb * specularColor.rgb * vec3(light.y); + lightColor.rgb * specularColor.rgb * vec3(light.y); + #ifdef USE_LIGHT_TEXTURES i++; #else i += 3; #endif } - if (NB_LIGHTS < 10) { - gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); - } + //if (NB_LIGHTS == 1) { + // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + //} } else if (shadingModelId == PBR_LIGHTING) { // PBR shading vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); @@ -130,8 +131,7 @@ void main(){ gl_FragColor.rgb = vec3(0.0); for (int i = 0; i < NB_LIGHTS;) { #ifdef USE_LIGHT_TEXTURES - vec2 pixel = vec2(i, 0); - pixel.x *= m_LightTexInv; + vec2 pixel = vec2(m_LightTexInv * i, 0); vec4 lightColor = texture2D(m_LightTex1, pixel); vec4 lightData1 = texture2D(m_LightTex2, pixel); #else From e1f5ae745db1b17c0f174fb6da8ae611ae86a833 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 15 Jun 2024 08:07:19 -0400 Subject: [PATCH 084/111] added light pack method junction --- .../framegraph/FrameGraphFactory.java | 19 +++++--- .../renderer/framegraph/passes/Junction.java | 9 ++-- .../framegraph/passes/RenderPass.java | 45 +++++++++++++++---- .../TestSimpleDeferredLighting.java | 9 ++-- 4 files changed, 61 insertions(+), 21 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 02f259c510..ffcd8def13 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -34,6 +34,7 @@ import com.jme3.asset.AssetManager; import com.jme3.renderer.framegraph.passes.DeferredPass; import com.jme3.renderer.framegraph.passes.GBufferPass; +import com.jme3.renderer.framegraph.passes.Junction; import com.jme3.renderer.framegraph.passes.LightImagePass; import com.jme3.renderer.framegraph.passes.OutputBucketPass; import com.jme3.renderer.framegraph.passes.OutputPass; @@ -77,6 +78,7 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { FrameGraph fg = new FrameGraph(assetManager); GBufferPass gbuf = fg.add(new GBufferPass()); LightImagePass lightImg = fg.add(new LightImagePass()); + Junction lightJunct = fg.add(new Junction(2, 7)); RenderPass deferred; if (!tiled) { deferred = fg.add(new DeferredPass()); @@ -92,11 +94,18 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { lightImg.makeInput(gbuf, "Lights", "Lights"); - deferred.makeInput(lightImg, "Textures", "LightTextures"); - deferred.makeInput(lightImg, "NumLights", "NumLights"); - deferred.makeInput(lightImg, "Ambient", "Ambient"); - deferred.makeInput(lightImg, "Probes", "Probes"); - //deferred.makeInput(gbuf, "Lights", "Lights"); + lightJunct.setName("LightPackMethod"); + lightJunct.makeInput(lightImg, "Textures", "Input[0]", 0, 3); + lightJunct.makeInput(lightImg, "NumLights", "Input[0][3]"); + lightJunct.makeInput(lightImg, "Ambient", "Input[0][4]"); + lightJunct.makeInput(lightImg, "Probes", "Input[0][5]"); + lightJunct.makeInput(gbuf, "Lights", "Input[1][6]"); + + deferred.makeInput(lightJunct, "Value", "LightTextures", 0, 3); + deferred.makeInput(lightJunct, "Value[3]", "NumLights"); + deferred.makeInput(lightJunct, "Value[4]", "Ambient"); + deferred.makeInput(lightJunct, "Value[5]", "Probes"); + deferred.makeInput(lightJunct, "Value[6]", "Lights"); deferred.makeInput(gbuf, "GBufferData", "GBufferData"); defOut.makeInput(deferred, "Color", "Color"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 2135b8b35f..cda95a641a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -52,8 +52,6 @@ */ public class Junction extends RenderPass { - private static final String INPUT = "Input"; - private int length; private int groupSize; private ResourceTicket output; @@ -89,7 +87,8 @@ protected void initialize(FrameGraph frameGraph) { protected void prepare(FGRenderContext context) { int size; if (groupSize > 1) { - size = getGroups().size(); + // output is also a group, so subtract one + size = getGroups().size()-1; } else { size = getInputTickets().size(); } @@ -150,7 +149,7 @@ public void read(JmeImporter im) throws IOException { private void connect(int i) { boolean assignNull = i < 0 || i >= length; if (groupSize > 1) { - ResourceTicket[] inArray = getGroup("Input"+i); + ResourceTicket[] inArray = getGroup(getInputName(i)); ResourceTicket[] outArray = getGroup("Value"); for (int j = 0; j < groupSize; j++) { outArray[j].setSource(assignNull ? null : inArray[j]); @@ -190,7 +189,7 @@ public GraphSource getIndexSource() { } public static String getInputName(int i) { - return INPUT+i; + return "Input["+i+"]"; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index d31366047d..e133c2a2bf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -519,28 +519,57 @@ public ResourceTicket[] getGroup(String name) { * If both the source name and target name correspond to ticket groups, the * groups will be connected. * - * @param pass + * @param sourcePass * @param sourceTicket * @param targetTicket + * @param start start index (inclusive) for connecting groups + * @param end end index (exclusive) for connecting groups */ - public void makeInput(RenderPass pass, String sourceTicket, String targetTicket) { - ResourceTicket[] sourceArray = pass.getGroup(sourceTicket); + public void makeInput(RenderPass sourcePass, String sourceTicket, String targetTicket, int start, int end) { + ResourceTicket[] sourceArray = sourcePass.getGroup(sourceTicket); if (sourceArray != null) { ResourceTicket[] targetArray = getGroup(targetTicket); if (targetArray != null) { - if (sourceArray.length < targetArray.length) { - throw new IllegalArgumentException("Source ticket array does not satisfy target ticket array."); - } - for (int i = 0; i < targetArray.length; i++) { + int n = Math.min(end, Math.min(targetArray.length, sourceArray.length)); + for (int i = start; i < n; i++) { targetArray[i].setSource(sourceArray[i]); } return; } } - ResourceTicket source = Objects.requireNonNull(pass.getOutput(sourceTicket), "Source ticket cannot be null."); + ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); ResourceTicket target = Objects.requireNonNull(getInput(targetTicket), "Target ticket cannot be null."); target.setSource(source); } + /** + * Makes the named source (output) ticket belonging to the given pass the source of + * the named target (input) ticket belonging to this pass. + *

      + * If both the source name and target name correspond to ticket groups, the + * groups will be connected. + * + * @param sourcePass + * @param sourceTicket + * @param targetTicket + * @param start start index (inclusive) for connecting groups + */ + public void makeInput(RenderPass sourcePass, String sourceTicket, String targetTicket, int start) { + makeInput(sourcePass, sourceTicket, targetTicket, start, Integer.MAX_VALUE); + } + /** + * Makes the named source (output) ticket belonging to the given pass the source of + * the named target (input) ticket belonging to this pass. + *

      + * If both the source name and target name correspond to ticket groups, the + * groups will be connected. + * + * @param pass + * @param sourceTicket + * @param targetTicket + */ + public void makeInput(RenderPass pass, String sourceTicket, String targetTicket) { + makeInput(pass, sourceTicket, targetTicket, 0, Integer.MAX_VALUE); + } /** * Nullifies all sources belonging to the given pass. * diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 785207773e..b6619cf6d8 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -52,11 +52,12 @@ import com.jme3.math.*; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; +import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.renderer.framegraph.debug.GraphEventCapture; -import com.jme3.renderer.framegraph.io.MatParamTargetControl; -import com.jme3.renderer.framegraph.passes.Attribute; +import com.jme3.renderer.framegraph.io.GraphSource; +import com.jme3.renderer.framegraph.passes.Junction; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -66,7 +67,6 @@ import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; -import com.jme3.shader.VarType; import com.jme3.shadow.DirectionalLightShadowFilter; import com.jme3.system.AppSettings; import com.jme3.texture.Texture; @@ -676,6 +676,9 @@ public void simpleInitApp() { //renderManager.setFrameGraph(deferred); //renderManager.setFrameGraph(forward); + Junction lightingMethod = deferred.get(Junction.class, "LightPackMethod"); + lightingMethod.setIndexSource(vp -> 0); + File capTarget = new File(System.getProperty("user.home")+"/earlyFrameCapture.txt"); GraphEventCapture cap = new GraphEventCapture(capTarget); cap.setIncludeNanos(false); From 3c18f2fe3174d784a16250c9ab815bfb6f9d8b6f Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 15 Jun 2024 08:14:42 -0400 Subject: [PATCH 085/111] deleted deferred lighting logic --- .../DeferredSinglePassLightingLogic.java | 531 ------------------ .../framegraph/FrameGraphFactory.java | 3 + .../TestSimpleDeferredLighting.java | 2 +- 3 files changed, 4 insertions(+), 532 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.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 deleted file mode 100644 index bac906cf3e..0000000000 --- a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java +++ /dev/null @@ -1,531 +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.material.logic; - -import com.jme3.asset.AssetManager; -import com.jme3.light.*; -import com.jme3.material.Material.BindUnits; -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; - -/** - * 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 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_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(); - - private final Texture2D[] lightTextures = new Texture2D[3]; - private final ImageRaster[] lightTexRasters = new ImageRaster[3]; - private final boolean useLightTextures; - private int lightNum; - private boolean useAmbientLight; - private final ColorRGBA ambientColor = new ColorRGBA(0, 0, 0, 1); - private final List probes = 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 textureModeDefine; - private final int probeDefine; - private final int ambientDefines; - - public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) { - super(techniqueDef); - this.useLightTextures = true; - singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean); - if (this.useLightTextures) { - packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int); - textureModeDefine = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean); - prepareLightData(1024); - } else { - nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int); - } - probeDefine = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES, VarType.Int); - ambientDefines = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_AMBIENT_LIGHT, VarType.Boolean); - } - - private void cleanupLightData() { - if (lightTextures[0] != null) { - lightTextures[0].getImage().dispose(); - } - if (lightTextures[1] != null) { - lightTextures[1].getImage().dispose(); - } - if (lightTextures[2] != null) { - lightTextures[2].getImage().dispose(); - } - } - - /** - * Creates textures to accomodate light data. - *

      - * Currently, a large amount of light information is stored in textures, divided into three texture1d, - * lightData[0] stores lightColor (rgb stores lightColor, a stores lightType), lightData[1] stores lightPosition + - * invRange/lightDir, lightData[2] 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 - lightTextures[0] = new Texture2D(lightNum, 1, Image.Format.RGBA32F); - lightTextures[0].setMinFilter(Texture.MinFilter.NearestNoMipMaps); - lightTextures[0].setMagFilter(Texture.MagFilter.Nearest); - lightTextures[0].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); - lightTextures[0].setImage(convertedImage); - lightTextures[0].getImage().setMipmapsGenerated(false); - lightTexRasters[0] = ImageRaster.create(lightTextures[0].getImage()); - - lightTextures[1] = new Texture2D(lightNum, 1, Image.Format.RGBA32F); - lightTextures[1].setMinFilter(Texture.MinFilter.NearestNoMipMaps); - lightTextures[1].setMagFilter(Texture.MagFilter.Nearest); - lightTextures[1].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); - lightTextures[1].setImage(convertedImage2); - lightTextures[1].getImage().setMipmapsGenerated(false); - lightTexRasters[1] = ImageRaster.create(lightTextures[1].getImage()); - - lightTextures[2] = new Texture2D(lightNum, 1, Image.Format.RGBA32F); - lightTextures[2].setMinFilter(Texture.MinFilter.NearestNoMipMaps); - lightTextures[2].setMagFilter(Texture.MagFilter.Nearest); - lightTextures[2].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); - lightTextures[2].setImage(convertedImage3); - lightTextures[2].getImage().setMipmapsGenerated(false); - lightTexRasters[2] = ImageRaster.create(lightTextures[2].getImage()); - } - - @Override - public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, - EnumSet rendererCaps, LightList lights, DefineList defines) { - if(useLightTextures){ - defines.set(packNbLightsDefineId, this.lightNum); - defines.set(textureModeDefine, 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) { - useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientColor, probes, false); - defines.set(probeDefine, probes.size()); - defines.set(ambientDefines, useAmbientLight); - } - return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines); - } - - /** - * Packs light data into textures. - *

      - * lightData[0]:
      - * - rgb stores lightColor
      - * - a stores lightTypeId
      - * lightData[1]:
      - * - directionalLightDirection
      - * - pointLightPosition + invRadius
      - * - spotLightPosition + invRadius
      - * lightData[2]:
      - * - 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 - */ - private 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 ambClr = shader.getUniform("g_AmbientLightColor"); - - //skyLightAndReflectionProbes.clear(); - if (startIndex != 0 || isLightCullStageDraw) { - // apply additive blending for 2nd and future passes - rm.getRenderer().applyRenderState(ADDITIVE_LIGHT); - ambClr.setValue(VarType.Vector4, ColorRGBA.Black); - } else { - //extractSkyLightAndReflectionProbes(lightList,true); - ambClr.setValue(VarType.Vector4, ambientColor); - } - - // render skyLights and reflectionProbes - if(!probes.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 = probes.get(0); - lastTexUnit = SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData( - rm, lastTexUnit, skyLightData, shCoeffs, reflectionProbePemMap, skyLight); - if (probes.size() > 1) { - skyLight = probes.get(1); - lastTexUnit = SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData( - rm, lastTexUnit, skyLightData2, shCoeffs2, reflectionProbePemMap2, skyLight); - } - if (probes.size() > 2) { - skyLight = probes.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(); - lightTexRasters[0].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; - lightTexRasters[1].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; - lightTexRasters[1].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; - lightTexRasters[1].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; - lightTexRasters[2].setPixel(curIndex, 0, temp); - break; - default: - 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 = lightTexRasters[0].getPixel(curIndex, 0); - // if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break; - // lightTexRasters[0].setPixel(curIndex, 0, temp); - // lightTexRasters[1].setPixel(curIndex, 0, temp); - // lightTexRasters[2].setPixel(curIndex, 0, temp); - //} - vars.release(); - lightTextures[0].getImage().setUpdateNeeded(); - lightTextures[1].getImage().setUpdateNeeded(); - lightTextures[2].getImage().setUpdateNeeded(); - g.getMaterial().setTexture("LightPackData1", lightTextures[0]); - g.getMaterial().setTexture("LightPackData2", lightTextures[1]); - g.getMaterial().setTexture("LightPackData3", lightTextures[2]); - 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 - */ - private 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, ambientColor); - } - - 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, BindUnits lastBindUnit) { - int numLights = 0; - Renderer renderer = renderManager.getRenderer(); - boolean isLightCullStageDraw = false; - if (geometry.getUserData(LIGHT_CULL_DRAW_STAGE) != null) { - isLightCullStageDraw = geometry.getUserData(LIGHT_CULL_DRAW_STAGE); - } - // 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(useLightTextures){ - int max = 1024; - if (lightNum != max) { - cleanupLightData(); - prepareLightData(max); - } - // 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) - useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientColor, probes, 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); - // Note: setting the light count here makes the new value miss the render - //geometry.getMaterial().setInt("NBLight", count); - if (count == 0) { - updateLightListPackToTexture(shader, geometry, lights, count, - renderManager, numLights, isLightCullStageDraw, lastBindUnit.textureUnit); - renderer.setShader(shader); - renderMeshFromGeometry(renderer, geometry); - } else while (numLights < 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) - numLights = updateLightListPackToTexture(shader, geometry, lights, count, - renderManager, numLights, isLightCullStageDraw, lastBindUnit.textureUnit); - 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 (numLights < lights.size()) { - numLights = updateLightListUniforms(shader, geometry, lights, batchSize, - renderManager, numLights, isLightCullStageDraw); - renderer.setShader(shader); - renderMeshFromGeometry(renderer, geometry); - } - } - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index ffcd8def13..96f4011307 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -58,6 +58,7 @@ public class FrameGraphFactory { */ public static FrameGraph forward(AssetManager assetManager) { FrameGraph fg = new FrameGraph(assetManager); + fg.setName("Forward"); fg.add(new OutputBucketPass(RenderQueue.Bucket.Opaque)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); @@ -81,8 +82,10 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { Junction lightJunct = fg.add(new Junction(2, 7)); RenderPass deferred; if (!tiled) { + fg.setName("Deferred"); deferred = fg.add(new DeferredPass()); } else { + fg.setName("TiledDeferred"); deferred = fg.add(new TileDeferredPass()); } OutputPass defOut = fg.add(new OutputPass(0f)); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index b6619cf6d8..c7c91ebea2 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -672,7 +672,7 @@ public void simpleInitApp() { //deferred2.setName("deferred2"); //FrameGraph graph = FrameGraphFactory.forward(assetManager, renderManager); viewPort.setFrameGraph(deferred); - //guiViewPort.setFrameGraph(deferred); + guiViewPort.setFrameGraph(deferred); //renderManager.setFrameGraph(deferred); //renderManager.setFrameGraph(forward); From 39cb0bd53ed964cabe368c20177f0e22bd1e70ba Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 15 Jun 2024 08:16:05 -0400 Subject: [PATCH 086/111] deleted draft files --- FrameGraphComponents | 36 ------------------------------------ FrameGraphTutorial.md | 36 ------------------------------------ frameGraphSrcFileDraft.txt | 19 ------------------- 3 files changed, 91 deletions(-) delete mode 100644 FrameGraphComponents delete mode 100644 FrameGraphTutorial.md delete mode 100644 frameGraphSrcFileDraft.txt diff --git a/FrameGraphComponents b/FrameGraphComponents deleted file mode 100644 index a6e534435f..0000000000 --- a/FrameGraphComponents +++ /dev/null @@ -1,36 +0,0 @@ -What is a render resource? - -A render resource is a wrapper for a render object. It also tracks references and lifetime, and knows its producer and resource definition. When a resource is not - -What is a resource ticket? - -A resource ticket points to a resource. It is used to tell the resource manager which resource various operations should be performed on. - -What does declaring a resource do? - -Declaring a resource makes the resource manager create a new virtual resource that does not yet hold an actual value. Passes should declare all resources they plan on creating during execution in the preperation step. - -What does referencing a resource do? - -Referencing is similar to declaring, except it acts on an existing resource. It tells the resource manager that that resource will be used in the future. This is used by passes referencing resources produced by other passes. - -What does acquiring a resource do? - -Acquiring a resource either returns the actual object held by the resource if the resource is not virtual, otherwise creates and returns a new object or returns an existing unused object. - -What does releasing a resource do? - -Releasing indicates that the resource is not used by a pass anymore. Resources track how many passes are using them using declarations and references. Once a resource finds that all passes that declared or referenced it have also released it, the resource will be deleted, and the object held by the resource will be posted for reallocation. - -What does setting a resource as constant do? - -This command does not actually change the resource, but it does set a flag on the object held by the resource (if the resource is not virtual) indicating that the object should not be reallocated for the remainder of rendering. The Attribute pass uses this to ensure that user-provided or user-consumed objects do not change unexpectedly. - -What does setting a resource as undefined do? - -Setting a resource as undefined makes it real (not virtual) but unable to hold an actual object. This is used by the Attribute pass when no (non-null) value is provided for output. Exceptions can occur if a pass attempts to acquire (without using an optional acquire) an undefined resource. - -What is a resource definition? - -A resource definition determines how new objects should be built or how existing objects should be adapted for the resource the definition is assigned to. It also defines how the resource and object should be handled in various situations. - diff --git a/FrameGraphTutorial.md b/FrameGraphTutorial.md deleted file mode 100644 index f1d600ce56..0000000000 --- a/FrameGraphTutorial.md +++ /dev/null @@ -1,36 +0,0 @@ - -/** - * For this tutorial, we will create a simple FrameGraph that renders - * the opaque, sky, and transparent buckets in that order, followed - * by a pass that renders the result to the screen. - */ - -// Begin by declaring a new FrameGraph. -FrameGraph fg = new FrameGraph(); - -// Add the passes we will use, in the correct order. -// Make sure to specify the correct bucket on each pass. -BucketPass opaque = fg.add(new BucketPass(Bucket.Opaque)); -BucketPass sky = fg.add(new BucketPass(Bucket.Sky)); -BucketPass transparent = fg.add(new BucketPass(Bucket.Transparent)); -OutputPass output = fg.add(new OutputPass()); - -// Now, each pass needs to pass its resulting color and depth to the next pass. -// We will do that by connecting certain tickets belonging to the passes. -sky.makeInput(opaque, "Color", "Color"); -sky.makeInput(opaque, "Depth", "Depth"); -transparent.makeInput(sky, "Color", "Color"); -transparent.makeInput(sky, "Depth", "Depth"); -output.makeInput(transparent, "Color", "Color"); -output.makeInput(transparent, "Depth", "Depth"); - -// The graph now, visually, looks like this: -// -// Opaque: Sky: Transparent: Output: -// color -> color -> color -------> color -// depth -> depth -> depth -------> depth - -// Finally, assign the FrameGraph to the ViewPort. -viewPort.setFrameGraph(fg); - - diff --git a/frameGraphSrcFileDraft.txt b/frameGraphSrcFileDraft.txt deleted file mode 100644 index 27c03d5467..0000000000 --- a/frameGraphSrcFileDraft.txt +++ /dev/null @@ -1,19 +0,0 @@ - -nextId=4 - -define jme_Attr = com.jme3.renderer.framegraph.passes.Attribute -define jme_Bucket = com.jme3.renderer.framegraph.passes.BucketPass -define jme_Output = com.jme3.renderer.framegraph.passes.OutputPass -define jme_Junction = com.jme3.renderer.framegraph.passes.Junction - -pass{src=jme_Attr; id=0; name=Attribute} -pass{src=jme_Attr; id=2; name=Attribute} -pass{src=jme_Junction; id=4; name=Junction; length=2} -pass{src=jme_Bucket; id=1; name=Opaque Bucket; bucket=Opaque} -pass{src=jme_Output; id=3; name=Output} - -connection{out=0:Value; in=4:Input0} -connection{out=2:Value; in=4:Input1} -connection{out=4:Value; in=1:Color} -connection{out=1:Color; in=3:Color} - From 6499b8b2f760b17a3fc48e2cb84c3d9c570f1777 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 15 Jun 2024 17:44:36 -0400 Subject: [PATCH 087/111] added group attribute pass --- .../java/com/jme3/material/MaterialDef.java | 1 - .../java/com/jme3/material/Technique.java | 7 +- .../java/com/jme3/material/TechniqueDef.java | 16 -- .../com/jme3/material/logic/RenderLogic.java | 57 ------ .../jme3/material/logic/TiledRenderGrid.java | 21 ++- .../java/com/jme3/renderer/RenderManager.java | 23 --- .../renderer/framegraph/FGRenderContext.java | 4 - .../jme3/renderer/framegraph/FrameGraph.java | 47 ++++- .../framegraph/FrameGraphFactory.java | 65 ++++--- .../renderer/framegraph/RenderResource.java | 7 +- .../framegraph/client/GraphClient.java | 54 ++++++ .../{io => client}/GraphSource.java | 2 +- .../{io => client}/GraphTarget.java | 2 +- .../{io => client}/MatParamTargetControl.java | 2 +- .../framegraph/client/ViewPortFilter.java | 17 ++ .../framegraph/definitions/TextureDef.java | 21 +++ .../framegraph/light/LightFrustum.java | 170 ++++++++++++++++++ .../framegraph/light/LightImagePacker.java | 101 ++++++++++- .../renderer/framegraph/passes/Attribute.java | 89 ++++----- .../framegraph/passes/DeferredPass.java | 30 +++- .../framegraph/passes/GroupAttribute.java | 121 +++++++++++++ .../renderer/framegraph/passes/Junction.java | 49 +++-- .../framegraph/passes/LightImagePass.java | 72 ++++++-- .../framegraph/passes/RenderPass.java | 57 +++--- .../ShadingCommon/DeferredShading.frag | 57 +++++- .../com/jme3/material/plugins/J3MLoader.java | 6 - .../TestSimpleDeferredLighting.java | 3 +- 27 files changed, 822 insertions(+), 279 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/material/logic/RenderLogic.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphClient.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{io => client}/GraphSource.java (97%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{io => client}/GraphTarget.java (97%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{io => client}/MatParamTargetControl.java (98%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/client/ViewPortFilter.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java diff --git a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java index 1035acabdd..8c3755548c 100644 --- a/jme3-core/src/main/java/com/jme3/material/MaterialDef.java +++ b/jme3-core/src/main/java/com/jme3/material/MaterialDef.java @@ -32,7 +32,6 @@ package com.jme3.material; import com.jme3.asset.AssetManager; -import com.jme3.material.logic.RenderLogic; import com.jme3.shader.VarType; import com.jme3.texture.image.ColorSpace; diff --git a/jme3-core/src/main/java/com/jme3/material/Technique.java b/jme3-core/src/main/java/com/jme3/material/Technique.java index bc9608e3b7..437ef785b5 100644 --- a/jme3-core/src/main/java/com/jme3/material/Technique.java +++ b/jme3-core/src/main/java/com/jme3/material/Technique.java @@ -35,7 +35,6 @@ import com.jme3.light.LightList; import com.jme3.material.Material.BindUnits; import com.jme3.material.TechniqueDef.LightMode; -import com.jme3.material.logic.RenderLogic; import com.jme3.material.logic.TechniqueDefLogic; import com.jme3.renderer.Caps; import com.jme3.renderer.RenderManager; @@ -165,11 +164,7 @@ Shader makeCurrent(RenderManager renderManager, SafeArrayList * @param lastTexUnit the index of the most recently used texture unit */ void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, BindUnits lastBindUnits) { - if (renderManager.getRenderLogic() != null) { - renderManager.getRenderLogic().render(renderManager, shader, geometry, lights, lastBindUnits); - } else { - def.getLogic().render(renderManager, shader, geometry, lights, lastBindUnits); - } + def.getLogic().render(renderManager, shader, geometry, lights, lastBindUnits); } /** 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 b1baa5300b..40d1df9612 100644 --- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java +++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java @@ -102,22 +102,6 @@ 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 */ diff --git a/jme3-core/src/main/java/com/jme3/material/logic/RenderLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/RenderLogic.java deleted file mode 100644 index e7e78c09a6..0000000000 --- a/jme3-core/src/main/java/com/jme3/material/logic/RenderLogic.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.material.logic; - -import com.jme3.asset.AssetManager; -import com.jme3.light.LightList; -import com.jme3.material.Material; -import com.jme3.material.TechniqueDef; -import com.jme3.renderer.Caps; -import com.jme3.renderer.RenderManager; -import com.jme3.renderer.Renderer; -import com.jme3.scene.Geometry; -import com.jme3.scene.Mesh; -import com.jme3.scene.instancing.InstancedGeometry; -import com.jme3.shader.DefineList; -import com.jme3.shader.Shader; -import java.util.EnumSet; - -/** - * - * - * @author codex - */ -public interface RenderLogic { - - /** - * - * @param def - */ - public void initTechniqueDef(TechniqueDef def); - - /** - * - * @param assetManager - * @param renderManager - * @param rendererCaps - * @param lights - * @param defines - * @return - */ - public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, - EnumSet rendererCaps, LightList lights, DefineList defines); - - /** - * - * @param rm - * @param shader - * @param geometry - * @param lights - * @param lastBindUnits - */ - public void render(RenderManager rm, Shader shader, Geometry geometry, - LightList lights, Material.BindUnits lastBindUnits); - -} diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java b/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java index ebf7862828..07b7402c4c 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java +++ b/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java @@ -31,13 +31,19 @@ */ package com.jme3.material.logic; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.renderer.Camera; +import java.io.IOException; /** * * @author codex */ -public class TiledRenderGrid { +public class TiledRenderGrid implements Savable { private int divisions = 4; private int forcedTileSize = 64; @@ -112,5 +118,18 @@ public void verifyUpdated() { public boolean needsUpdate() { return tileSize <= 0 || gridWidth <= 0 || gridHeight <= 0; } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(divisions, "divisions", 4); + out.write(forcedTileSize, "forcedTileSize", 64); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + divisions = in.readInt("divisions", 4); + forcedTileSize = in.readInt("forcedTileSize", 64); + } } 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 f949d59b16..24fd3137d4 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -31,7 +31,6 @@ */ package com.jme3.renderer; -import com.jme3.material.logic.RenderLogic; import com.jme3.light.DefaultLightFilter; import com.jme3.light.LightFilter; import com.jme3.light.LightList; @@ -103,7 +102,6 @@ public class RenderManager { private RenderState forcedRenderState = null; private final SafeArrayList forcedOverrides = new SafeArrayList<>(MatParamOverride.class); - private RenderLogic logic; private GeometryRenderHandler renderGeometry; private int viewX; private int viewY; @@ -208,27 +206,6 @@ public GeometryRenderHandler getGeometryRenderHandler() { return renderGeometry; } - /** - * Sets the technique rendering logic. - *

      - * If not null, the rendering logic is used in place of a rendered technique's - * normal logic. This feature is highly experimental. - * - * @param logic - */ - public void setRenderLogic(RenderLogic logic) { - this.logic = logic; - } - - /** - * Gets the technique rendering logic. - * - * @return - */ - public RenderLogic getRenderLogic() { - return logic; - } - /** * Returns the pre ViewPort with the given name. * 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 9e57130707..2618a04b56 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 @@ -46,7 +46,6 @@ import com.jme3.texture.Texture2D; import java.util.function.Predicate; import com.jme3.renderer.GeometryRenderHandler; -import com.jme3.material.logic.RenderLogic; /** * Contains necessary context for framegraph rendering. @@ -70,7 +69,6 @@ public class FGRenderContext { private Material forcedMat; private FrameBuffer frameBuffer; private GeometryRenderHandler geomRender; - private RenderLogic logic; private Predicate geomFilter; private RenderState renderState; @@ -117,7 +115,6 @@ public void pushRenderSettings() { forcedMat = renderManager.getForcedMaterial(); frameBuffer = renderManager.getRenderer().getCurrentFrameBuffer(); geomRender = renderManager.getGeometryRenderHandler(); - logic = renderManager.getRenderLogic(); geomFilter = renderManager.getRenderFilter(); renderState = renderManager.getForcedRenderState(); } @@ -129,7 +126,6 @@ public void popRenderSettings() { renderManager.setForcedMaterial(forcedMat); renderManager.getRenderer().setFrameBuffer(frameBuffer); renderManager.setGeometryRenderHandler(geomRender); - renderManager.setRenderLogic(logic); renderManager.setRenderFilter(geomFilter); renderManager.setForcedRenderState(renderState); renderManager.getRenderer().setDepthRange(0, 1); 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 f2246aab45..0ac5d853c5 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 @@ -43,6 +43,7 @@ import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.passes.Attribute; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -90,6 +91,7 @@ public class FrameGraph { private final ResourceList resources; private final FGRenderContext context; private final LinkedList passes = new LinkedList<>(); + private final HashMap blackboard = new HashMap<>(); private String name = "FrameGraph"; private boolean rendered = false; @@ -284,7 +286,7 @@ public T add(T pass, int index) { */ public Attribute addAttribute(ResourceTicket ticket) { Attribute attr = add(new Attribute<>()); - attr.getInput(Attribute.VALUE).setSource(ticket); + attr.getInput(Attribute.OUTPUT).setSource(ticket); return attr; } @@ -407,6 +409,49 @@ public void clear() { passes.clear(); } + /** + * Posts an object to the blackboard. + * + * @param + * @param name + * @param object + * @return given object + */ + public T post(String name, T object) { + blackboard.put(name, object); + return object; + } + /** + * Reads an object from the blackboard. + * + * @param + * @param name + * @return + */ + public T fetch(String name) { + Object obj = blackboard.get(name); + if (obj != null) { + return (T)obj; + } else { + return null; + } + } + /** + * Removes an object from the blackboard. + * + * @param + * @param name + * @return + */ + public T remove(String name) { + Object obj = blackboard.remove(name); + if (obj != null) { + return (T)obj; + } else { + return null; + } + } + /** * Sets the name of this framegraph. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 96f4011307..a6451dcebf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -32,6 +32,9 @@ package com.jme3.renderer.framegraph; import com.jme3.asset.AssetManager; +import com.jme3.material.logic.TiledRenderGrid; +import com.jme3.renderer.framegraph.client.GraphClient; +import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.framegraph.passes.DeferredPass; import com.jme3.renderer.framegraph.passes.GBufferPass; import com.jme3.renderer.framegraph.passes.Junction; @@ -39,8 +42,6 @@ import com.jme3.renderer.framegraph.passes.OutputBucketPass; import com.jme3.renderer.framegraph.passes.OutputPass; import com.jme3.renderer.framegraph.passes.PostProcessingPass; -import com.jme3.renderer.framegraph.passes.RenderPass; -import com.jme3.renderer.framegraph.passes.TileDeferredPass; import com.jme3.renderer.queue.RenderQueue; /** @@ -57,15 +58,19 @@ public class FrameGraphFactory { * @return forward framegraph */ public static FrameGraph forward(AssetManager assetManager) { + FrameGraph fg = new FrameGraph(assetManager); fg.setName("Forward"); + fg.add(new OutputBucketPass(RenderQueue.Bucket.Opaque)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); fg.add(new PostProcessingPass()); fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); + return fg; + } /** @@ -76,18 +81,17 @@ public static FrameGraph forward(AssetManager assetManager) { * @return deferred framegraph */ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { + FrameGraph fg = new FrameGraph(assetManager); + fg.setName(tiled ? "TiledDeferred" : "Deferred"); + GBufferPass gbuf = fg.add(new GBufferPass()); + Attribute tileInfoAttr = fg.add(new Attribute()); + Junction tileJunct1 = fg.add(new Junction(1, 1)); LightImagePass lightImg = fg.add(new LightImagePass()); - Junction lightJunct = fg.add(new Junction(2, 7)); - RenderPass deferred; - if (!tiled) { - fg.setName("Deferred"); - deferred = fg.add(new DeferredPass()); - } else { - fg.setName("TiledDeferred"); - deferred = fg.add(new TileDeferredPass()); - } + Junction lightJunct = fg.add(new Junction(1, 6)); + Junction tileJunct2 = fg.add(new Junction(1, 2)); + DeferredPass deferred = fg.add(new DeferredPass()); OutputPass defOut = fg.add(new OutputPass(0f)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); @@ -95,21 +99,38 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { fg.add(new PostProcessingPass()); fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); + GraphClient tileInfo = fg.post("TileInfo", new GraphClient()); + tileInfo.setValue(new TiledRenderGrid()); + tileInfoAttr.setName("TileInfo"); + tileInfoAttr.setSource(tileInfo); + + GraphClient tileToggle = fg.post("TileToggle", new GraphClient()); + tileToggle.setValue(tiled ? 0 : -1); + tileJunct1.makeInput(tileInfoAttr, Attribute.OUTPUT, Junction.getInput(0)); + tileJunct1.setIndexSource(tileToggle); + lightImg.makeInput(gbuf, "Lights", "Lights"); + lightImg.makeInput(tileInfoAttr, Attribute.OUTPUT, "TileInfo"); + GraphClient lightPackMethod = fg.post("LightPackMethod", new GraphClient()); + lightPackMethod.setValue(tiled ? 0 : -1); lightJunct.setName("LightPackMethod"); - lightJunct.makeInput(lightImg, "Textures", "Input[0]", 0, 3); - lightJunct.makeInput(lightImg, "NumLights", "Input[0][3]"); - lightJunct.makeInput(lightImg, "Ambient", "Input[0][4]"); - lightJunct.makeInput(lightImg, "Probes", "Input[0][5]"); - lightJunct.makeInput(gbuf, "Lights", "Input[1][6]"); + lightJunct.makeGroupInput(lightImg, "Textures", Junction.getInput(0), 0, 0, 3); + lightJunct.makeInput(lightImg, "NumLights", Junction.getInput(0, 3)); + lightJunct.makeInput(lightImg, "Ambient", Junction.getInput(0, 4)); + lightJunct.makeInput(lightImg, "Probes", Junction.getInput(0, 5)); + lightJunct.setIndexSource(lightPackMethod); + + tileJunct2.makeGroupInput(lightImg, "TileTextures", Junction.getInput(0)); + tileJunct2.setIndexSource(tileToggle); - deferred.makeInput(lightJunct, "Value", "LightTextures", 0, 3); - deferred.makeInput(lightJunct, "Value[3]", "NumLights"); - deferred.makeInput(lightJunct, "Value[4]", "Ambient"); - deferred.makeInput(lightJunct, "Value[5]", "Probes"); - deferred.makeInput(lightJunct, "Value[6]", "Lights"); - deferred.makeInput(gbuf, "GBufferData", "GBufferData"); + deferred.makeGroupInput(gbuf, "GBufferData", "GBufferData"); + deferred.makeInput(gbuf, "Lights", "Lights"); + deferred.makeGroupInput(lightJunct, Junction.getOutput(), "LightTextures", 0, 0, 3); + deferred.makeInput(lightJunct, Junction.getOutput(3), "NumLights"); + deferred.makeInput(lightJunct, Junction.getOutput(4), "Ambient"); + deferred.makeInput(lightJunct, Junction.getOutput(5), "Probes"); + deferred.makeGroupInput(tileJunct2, Junction.getOutput(), "TileTextures"); defOut.makeInput(deferred, "Color", "Color"); defOut.makeInput(gbuf, "GBufferData[4]", "Depth"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 00ea15d994..5c64e6e811 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -123,6 +123,9 @@ public void setObject(RenderObject object, T resource) { * @param resource */ public void setPrimitive(T resource) { + if (undefined) { + throw new IllegalStateException("Resource is already marked as undefined."); + } object = null; this.resource = resource; } @@ -130,8 +133,8 @@ public void setPrimitive(T resource) { * Marks this resource as undefined. */ public void setUndefined() { - if (object != null) { - throw new IllegalArgumentException("Resource is already defined."); + if (resource != null) { + throw new IllegalStateException("Resource is already defined."); } undefined = true; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphClient.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphClient.java new file mode 100644 index 0000000000..8aa6b9ad4b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphClient.java @@ -0,0 +1,54 @@ +/* + * 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.client; + +import com.jme3.renderer.ViewPort; + +/** + * + * @author codex + * @param + */ +public class GraphClient implements GraphSource, GraphTarget { + + private T value; + private ViewPortFilter filter; + + public GraphClient() {} + public GraphClient(T value) { + this.value = value; + } + + @Override + public T getGraphValue(ViewPort viewPort) { + if (filter == null || filter.confirm(viewPort)) { + return value; + } + return null; + } + @Override + public boolean setGraphValue(ViewPort viewPort, T value) { + if (filter == null || filter.confirm(viewPort)) { + this.value = value; + return true; + } + return false; + } + + public void setValue(T value) { + this.value = value; + } + public void setFilter(ViewPortFilter filter) { + this.filter = filter; + } + + public T getValue() { + return value; + } + public ViewPortFilter getFilter() { + return filter; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java similarity index 97% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java index cbf6cd46fa..1327700e3f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphSource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.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.framegraph.io; +package com.jme3.renderer.framegraph.client; import com.jme3.renderer.ViewPort; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java similarity index 97% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java index fbc43a2781..57b9d2d4e6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/GraphTarget.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.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.framegraph.io; +package com.jme3.renderer.framegraph.client; import com.jme3.renderer.ViewPort; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java similarity index 98% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java index a12993c11c..a10af2ff5e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/io/MatParamTargetControl.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.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.framegraph.io; +package com.jme3.renderer.framegraph.client; import com.jme3.material.Material; import com.jme3.renderer.RenderManager; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/ViewPortFilter.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/ViewPortFilter.java new file mode 100644 index 0000000000..8598484925 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/ViewPortFilter.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.client; + +import com.jme3.renderer.ViewPort; + +/** + * + * @author codex + */ +public interface ViewPortFilter { + + public boolean confirm(ViewPort vp); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 13761da2bf..5dde5bd00c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -34,6 +34,8 @@ import com.jme3.texture.Image; import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; +import com.jme3.texture.Texture3D; +import com.jme3.texture.TextureArray; import com.jme3.texture.image.ColorSpace; import java.util.ArrayList; import java.util.Objects; @@ -51,6 +53,9 @@ */ public class TextureDef extends AbstractResourceDef implements Consumer { + public static final Function TEXTURE_2D = img -> new Texture2D(img); + public static final Function TEXTURE_3D = img -> new Texture3D(img); + private final Class type; private Function textureBuilder; private Function imageExtractor; @@ -430,6 +435,15 @@ public int getHeight() { public int getDepth() { return depth; } + /** + * Returns the number of pixels contained in the texture. + * + * @return + */ + public int getNumPixels() { + if (depth > 0) return width*height*depth; + else return width*height; + } /** * * @return @@ -494,4 +508,11 @@ public Texture.WrapMode getWrap(Texture.WrapAxis axis) { } } + public static TextureDef texture2D() { + return new TextureDef<>(Texture2D.class, TEXTURE_2D); + } + public static TextureDef texture3D() { + return new TextureDef<>(Texture3D.class, TEXTURE_3D); + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java new file mode 100644 index 0000000000..36693f3508 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java @@ -0,0 +1,170 @@ +/* + * 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.light; + +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.logic.TiledRenderGrid; +import com.jme3.math.Matrix4f; +import com.jme3.math.Vector3f; +import com.jme3.math.Vector4f; +import com.jme3.renderer.Camera; +import java.util.ArrayList; +import java.util.LinkedList; + +/** + * + * @author codex + */ +public class LightFrustum { + + private float left, right, top, bottom; + + private Matrix4f vp; + private float camLeftCoeff = -1; + private float camTopCoeff = -1; + private float viewPortWidth = -1; + private float viewPortHeight = -1; + private final float[] matArray1 = new float[16]; + private final Vector3f tempVec3 = new Vector3f(); + private final Vector3f tempVec3_2 = new Vector3f(); + private final Vector4f tempVec4 = new Vector4f(); + private final Vector4f tempvec4_2 = new Vector4f(); + private final Vector4f tempVec4_3 = new Vector4f(); + private final Vector4f camUp = new Vector4f(); + private final Vector4f camLeft = new Vector4f(); + private final Vector4f lightLeft = new Vector4f(); + private final Vector4f lightUp = new Vector4f(); + private final Vector4f lightCenter = new Vector4f(); + + public LightFrustum calculateCamera(Camera cam) { + viewPortWidth = cam.getWidth() * 0.5f; + viewPortHeight = cam.getHeight() * 0.5f; + vp = cam.getViewProjectionMatrix(); + Matrix4f v = cam.getViewMatrix(); + v.get(matArray1); + tempVec3.set(matArray1[0], matArray1[1], matArray1[2]); + camLeftCoeff = 1.0f / cam.getWorldPlane(1).getNormal().dot(tempVec3); + tempVec3.set(matArray1[4], matArray1[5], matArray1[6]); + camTopCoeff = 1.0f / cam.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); + return this; + } + + public LightFrustum fromLight(Light l) { + switch (l.getType()) { + case Directional: + return fromDirectional((DirectionalLight)l); + case Point: + return fromPoint((PointLight)l); + case Spot: + return fromSpot((SpotLight)l); + case Ambient: + return fromAmbient((AmbientLight)l); + default: + throw new UnsupportedOperationException("Light type "+l.getType()+" is not supported."); + } + } + public LightFrustum fromDirectional(DirectionalLight dl) { + return fullscreen(); + } + public LightFrustum fromPoint(PointLight pl) { + + 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 l, b; + if(lightCenter.z < -lightCenter.w){ + l = -lightCenter.x - lw; + b = -lightCenter.y + lh; + } else { + l = lightCenter.x - lw; + b = lightCenter.y + lh; + } + b = viewPortHeight * 2.0f - b; + this.left = l; + this.right = lw * 2.0f + l; + this.top = lh * 2.0f + b; + this.bottom = b; + + return this; + + } + public LightFrustum fromSpot(SpotLight sl) { + return fullscreen(); + } + public LightFrustum fromAmbient(AmbientLight al) { + return fullscreen(); + } + public LightFrustum fullscreen() { + left = bottom = 0; + right = viewPortWidth; + top = viewPortHeight; + return this; + } + + public void write(ArrayList> tileIndices, TiledRenderGrid tileInfo, int lightIndex) { + int width = tileInfo.getGridWidth(); + int numTiles = tileInfo.getNumTiles(); + int tileLeft = (int)Math.max(Math.floor(left / tileInfo.getTileSize()), 0); + int tileRight = (int)Math.min(Math.ceil(right / tileInfo.getTileSize()), width); + int tileBottom = (int)Math.max(Math.floor(bottom / tileInfo.getTileSize()), 0); + int tileTop = (int)Math.min(Math.ceil(top / tileInfo.getTileSize()), tileInfo.getGridHeight()); + for (int b = tileBottom; b < tileTop; b++) { + int base = b*width; + for (int l = tileLeft; l < tileRight; l++) { + int tileId = l+base; + if (tileId >= 0 && tileId < numTiles) { + tileIndices.get(tileId).add(lightIndex); + } + } + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java index 923db82336..2e1c23cc56 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java @@ -10,11 +10,15 @@ import com.jme3.light.LightProbe; import com.jme3.light.PointLight; import com.jme3.light.SpotLight; +import com.jme3.material.logic.TiledRenderGrid; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; import com.jme3.texture.image.ImageRaster; +import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; /** @@ -23,19 +27,23 @@ */ public class LightImagePacker { - private final Texture2D[] textures = new Texture2D[3]; - private final ImageRaster[] rasters = new ImageRaster[3]; + private final Texture2D[] textures = new Texture2D[5]; + private final ImageRaster[] rasters = new ImageRaster[5]; private final ColorRGBA tempColor = new ColorRGBA(); + private final LightFrustum frustum = new LightFrustum(); private boolean hasAmbient = false; + private ArrayList> tileIndices = new ArrayList<>(); public LightImagePacker() {} - public void setTextures(Texture2D tex1, Texture2D tex2, Texture2D tex3) { + public void setTextures(Texture2D tex1, Texture2D tex2, Texture2D tex3, Texture2D tiles, Texture2D indices) { validateSize(tex1, tex2); validateSize(tex1, tex3); updateTexture(0, tex1); updateTexture(1, tex2); updateTexture(2, tex3); + updateTexture(3, tiles); + updateTexture(4, indices); } public Texture2D[] getTextures() { return textures; @@ -44,7 +52,8 @@ public Texture2D getTexture(int i) { return textures[i]; } - public int packLights(LightList lights, ColorRGBA ambient, List probes) { + public int packLights(LightList lights, ColorRGBA ambient, + List probes, Camera cam, TiledRenderGrid tileInfo) { ambient.set(0, 0, 0, 1); probes.clear(); if (lights.size() == 0) { @@ -52,6 +61,19 @@ public int packLights(LightList lights, ColorRGBA ambient, List prob } int i = 0; final int limit = textures[0].getImage().getWidth(); + final boolean useTiles = textures[3] != null && textures[4] != null && cam != null && tileInfo != null; + if (useTiles) { + tempColor.set(ColorRGBA.BlackNoAlpha); + frustum.calculateCamera(cam); + // match tile index lists to number of tiles + int n = tileInfo.getNumTiles(); + while (tileIndices.size() > n) { + tileIndices.remove(tileIndices.size()-1); + } + while (tileIndices.size() < n) { + tileIndices.add(new LinkedList<>()); + } + } boolean packedLight = false; boolean spotlight = false; hasAmbient = false; @@ -73,12 +95,18 @@ public int packLights(LightList lights, ColorRGBA ambient, List prob DirectionalLight dl = (DirectionalLight)l; vectorToColor(dl.getDirection(), tempColor).a = 0; rasters[1].setPixel(i, 0, tempColor); + if (useTiles) { + frustum.fromDirectional(dl).write(tileIndices, tileInfo, i); + } break; case Point: PointLight pl = (PointLight)l; vectorToColor(pl.getPosition(), tempColor); tempColor.a = pl.getInvRadius(); rasters[1].setPixel(i, 0, tempColor); + if (useTiles) { + frustum.fromPoint(pl).write(tileIndices, tileInfo, i); + } break; case Spot: SpotLight sl = (SpotLight)l; @@ -89,6 +117,9 @@ public int packLights(LightList lights, ColorRGBA ambient, List prob tempColor.a = sl.getPackedAngleCos(); rasters[2].setPixel(i, 0, tempColor); spotlight = true; + if (useTiles) { + frustum.fromSpot(sl).write(tileIndices, tileInfo, i); + } break; } if (++i >= limit) { @@ -101,9 +132,58 @@ public int packLights(LightList lights, ColorRGBA ambient, List prob if (spotlight) { textures[2].getImage().setUpdateNeeded(); } + if (useTiles) { + packLightIndices(); + } } return i; } + private void packLightIndices() { + int componentIndex = 0; + int xIndex = 0, yIndex = 0; + int tileX = 0, tileY = 0; + final int indexWidth = textures[4].getImage().getWidth(); + final int tileWidth = textures[3].getImage().getWidth(); + final int tileHeight = textures[3].getImage().getHeight(); + final ColorRGBA tileInfoColor = new ColorRGBA(); + for (LinkedList l : tileIndices) { + // raster tile info to texture + tileInfoColor.r = xIndex; + tileInfoColor.g = yIndex; + tileInfoColor.b = componentIndex; + tileInfoColor.a = l.size(); + // flip Y index, because tiles are computed from bottom to top + rasters[3].setPixel(tileX, tileHeight-tileY, tileInfoColor); + if (++tileX >= tileWidth) { + tileX = 0; + tileY++; + } + // raster light indices to texture + for (int index : l) { + // pack 4 indices per pixel + switch (componentIndex++) { + case 0: tempColor.r = index; break; + case 1: tempColor.g = index; break; + case 2: tempColor.b = index; break; + case 3: tempColor.a = index; break; + } + if (componentIndex > 3) { + componentIndex = 0; + rasters[4].setPixel(xIndex, yIndex, tempColor); + if (++xIndex >= indexWidth) { + xIndex = 0; + yIndex++; + } + } + } + l.clear(); + } + if (componentIndex != 0) { + rasters[4].setPixel(xIndex, yIndex, tempColor); + } + textures[3].getImage().setUpdateNeeded(); + textures[4].getImage().setUpdateNeeded(); + } public boolean hasAmbientLight() { return hasAmbient; @@ -122,10 +202,15 @@ private void validateSize(Texture2D base, Texture2D target) { } } private void updateTexture(int i, Texture2D tex) { - validateSamples(tex); - if (textures[i] != tex) { - textures[i] = tex; - rasters[i] = ImageRaster.create(tex.getImage()); + if (tex == null) { + textures[i] = null; + rasters[i] = null; + } else { + validateSamples(tex); + if (textures[i] != tex) { + textures[i] = tex; + rasters[i] = ImageRaster.create(tex.getImage()); + } } } private ColorRGBA vectorToColor(Vector3f vec, ColorRGBA color) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index 8d1e63809c..169c7f2ffe 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -33,15 +33,13 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; -import com.jme3.renderer.framegraph.io.GraphTarget; -import com.jme3.renderer.framegraph.io.GraphSource; +import com.jme3.renderer.framegraph.client.GraphTarget; +import com.jme3.renderer.framegraph.client.GraphSource; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; -import com.jme3.renderer.framegraph.definitions.ValueDef; import java.io.IOException; import java.util.LinkedList; -import java.util.function.Function; /** * Interface pass between the framegraph and game logic, allowing them to communicate. @@ -55,29 +53,23 @@ * @author codex * @param */ -public class Attribute extends RenderPass implements Function { +public class Attribute extends RenderPass { - public static final String VALUE = "Value"; + public static final String INPUT = "Input", OUTPUT = "Output"; private ResourceTicket in, out; - private T value; - private ValueDef def; - private final LinkedList> targets = new LinkedList<>(); + private T defaultValue = null; private GraphSource source; - private boolean constantOutput = false; + private final LinkedList> targets = new LinkedList<>(); @Override protected void initialize(FrameGraph frameGraph) { - in = addInput(VALUE); - out = addOutput(VALUE); - def = new ValueDef<>(null, this); - def.setDisposeOnRelease(true); - def.setUseExisting(false); - def.setDisposalMethod(object -> {}); + in = addInput(INPUT); + out = addOutput(OUTPUT); } @Override protected void prepare(FGRenderContext context) { - declare(def, out); + declare(null, out); referenceOptional(in); } @Override @@ -94,14 +86,14 @@ protected void execute(FGRenderContext context) { resources.setConstant(in); } } + T outVal; if (source != null) { - value = source.getGraphValue(context.getViewPort()); + outVal = source.getGraphValue(context.getViewPort()); } else { - value = null; + outVal = defaultValue; } - if (value != null) { - resources.acquire(out); - if (constantOutput) resources.setConstant(out); + if (outVal != null) { + resources.setPrimitive(out, outVal); } else { resources.setUndefined(out); } @@ -117,20 +109,6 @@ protected void cleanup(FrameGraph frameGraph) { public boolean isUsed() { return super.isUsed() || in.hasSource(); } - @Override - public T apply(Object t) { - return value; - } - @Override - public void write(JmeExporter ex) throws IOException { - super.write(ex); - ex.getCapsule(this).write(constantOutput, "constantOutput", false); - } - @Override - public void read(JmeImporter im) throws IOException { - super.read(im); - constantOutput = im.getCapsule(this).readBoolean("constantOutput", false); - } /** * Adds the graph target. @@ -160,27 +138,50 @@ public void setSource(GraphSource source) { this.source = source; } /** - * If true, the outgoing object is set as constant. * - * @param constantOutput + * @param defaultValue + */ + public void setDefaultValue(T defaultValue) { + this.defaultValue = defaultValue; + } + + /** + * + * @return */ - public void setConstantOutput(boolean constantOutput) { - this.constantOutput = constantOutput; + public T getDefaultValue() { + return defaultValue; } /** * * @return */ - public ValueDef getOutputDef() { - return def; + public static String getInput() { + return "Value"; + } + /** + * + * @param i + * @return + */ + public static String getInput(int i) { + return "Value["+i+"]"; + } + /** + * + * @return + */ + public static String getOutput() { + return "Value"; } /** * + * @param i * @return */ - public boolean isConstantOutput() { - return constantOutput; + public static String getOutput(int i) { + return "Value["+i+"]"; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 694d7e1682..dfca865fa1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -88,9 +88,9 @@ public class DeferredPass extends RenderPass implements TechniqueDefLogic { private ResourceTicket> probes; private TextureDef colorDef; private Material material; - private Texture2D[] lightTextures = new Texture2D[3]; - private int maxLights = 1000; - private ColorRGBA ambientColor = new ColorRGBA(); + private final Texture2D[] lightTextures = new Texture2D[3]; + private final Texture2D[] tileTextures = new Texture2D[2]; + private final ColorRGBA ambientColor = new ColorRGBA(); private List probeList; public DeferredPass() {} @@ -108,6 +108,7 @@ protected void initialize(FrameGraph frameGraph) { addInputGroup("GBufferData", 5); lights = addInput("Lights"); addInputGroup("LightTextures", 3); + addInputGroup("TileTextures", 2); numLights = addInput("NumLights"); ambient = addInput("Ambient"); probes = addInput("Probes"); @@ -153,6 +154,12 @@ protected void execute(FGRenderContext context) { for (int i = 1; i <= lightTextures.length; i++) { material.setTexture("LightTex"+i, lightTextures[i-1]); } + // get textures used for screenspace light tiling + acquireGroupOrElse("TileTextures", tileTextures, null); + if (tileTextures[0] != null) { + material.setTexture("m_Tiles", tileTextures[0]); + material.setTexture("m_LightIndex", tileTextures[1]); + } context.renderFullscreen(material); } material.getActiveTechnique().getDef().setLogic(null); @@ -165,9 +172,7 @@ protected void cleanup(FrameGraph frameGraph) {} public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { // defines should only be set in this method - boolean useLightTex = lightTextures[0] != null; - defines.set(defs.useTextures, useLightTex); - if (!useLightTex) { + if (lightTextures[0] == null) { ColorRGBA amb = resources.acquireOrElse(ambient, null); if (amb == null) { probeList = localProbeList; @@ -184,7 +189,11 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager // get resources for lighting with textures ambientColor.set(resources.acquire(ambient)); probeList = resources.acquire(probes); + defines.set(defs.useTextures, true); defines.set(defs.numLights, resources.acquire(numLights)); + if (tileTextures[0] != null) { + defines.set(defs.useTiles, true); + } } //defines.set(defs.numLights, 1); defines.set(defs.numProbes, Math.min(probeList.size(), 3)); @@ -279,6 +288,11 @@ private void injectLightBuffers(Shader shader, LightList lights) { private void injectLightTextures(Shader shader) { int w = lightTextures[0].getImage().getWidth(); shader.getUniform("m_LightTexInv").setValue(VarType.Float, 1f/w); + if (tileTextures[0] != null) { + w = tileTextures[1].getImage().getWidth(); + int h = tileTextures[1].getImage().getHeight(); + shader.getUniform("m_LightIndexSize").setValue(VarType.Vector3, new Vector3f(w, 1f/w, 1f/h)); + } } private void writeVectorToUniform(Uniform uniform, Vector3f vec, float w, int i) { @@ -297,8 +311,9 @@ private static class Defines { private static final String DEFINE_NB_PROBES = "NB_PROBES"; private static final String DEFINE_USE_LIGHT_TEXTURES = "USE_LIGHT_TEXTURES"; private static final String DEFINE_USE_AMBIENT_LIGHT = "USE_AMBIENT_LIGHT"; + private static final String DEFINE_TILED_LIGHTS = "TILED_LIGHTS"; - public int numLights, useTextures, numProbes, useAmbientLight; + public int numLights, useTextures, numProbes, useAmbientLight, useTiles; public Defines() {} @@ -307,6 +322,7 @@ public void config(TechniqueDef def) { numProbes = def.addShaderUnmappedDefine(DEFINE_NB_PROBES, VarType.Int); useTextures = def.addShaderUnmappedDefine(DEFINE_USE_LIGHT_TEXTURES, VarType.Boolean); useAmbientLight = def.addShaderUnmappedDefine(DEFINE_USE_AMBIENT_LIGHT, VarType.Boolean); + useTiles = def.addShaderUnmappedDefine(DEFINE_TILED_LIGHTS, VarType.Boolean); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java new file mode 100644 index 0000000000..6c17ca259a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java @@ -0,0 +1,121 @@ +/* + * 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.passes; + +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.client.GraphSource; +import com.jme3.renderer.framegraph.client.GraphTarget; +import java.util.ArrayList; + +/** + * + * @author codex + */ +public class GroupAttribute extends RenderPass { + + public static final String INPUT = "Input", OUTPUT = "Output"; + + private int groupSize = 2; + private final ArrayList sources = new ArrayList<>(5); + private final ArrayList targets = new ArrayList<>(5); + + public GroupAttribute() {} + public GroupAttribute(int groupSize) { + this.groupSize = groupSize; + } + + @Override + protected void initialize(FrameGraph frameGraph) { + addInputGroup(INPUT, groupSize); + addOutputGroup(OUTPUT, groupSize); + } + @Override + protected void prepare(FGRenderContext context) { + for (ResourceTicket t : getGroup(OUTPUT)) { + declare(null, t); + } + referenceOptional(getGroup(INPUT)); + } + @Override + protected void execute(FGRenderContext context) { + ViewPort vp = context.getViewPort(); + ResourceTicket[] inTickets = getGroup(INPUT); + for (int i = 0, n = Math.min(groupSize, targets.size()); i < n; i++) { + Object value = resources.acquireOrElse(inTickets[i], null); + GraphTarget t = targets.get(i); + if (t != null && t.setGraphValue(vp, value)) { + resources.setConstant(inTickets[i]); + } + } + int i = 0; + ResourceTicket[] outTickets = getGroup(OUTPUT); + for (int n = Math.min(groupSize, sources.size()); i < n; i++) { + GraphSource s = sources.get(i); + if (s != null) { + Object value = s.getGraphValue(vp); + if (value != null) { + resources.setPrimitive(outTickets[i], value); + continue; + } + } + resources.setUndefined(outTickets[i]); + } + for (; i < groupSize; i++) { + resources.setUndefined(outTickets[i]); + } + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + + public void setGroupSize(int groupSize) { + if (isAssigned()) { + throw new IllegalStateException("Cannot alter group size while assigned to a framegraph."); + } + this.groupSize = groupSize; + } + public void setSource(int i, GraphSource source) { + while (sources.size() <= i) { + sources.add(null); + } + sources.set(i, source); + } + public void setTarget(int i, GraphTarget target) { + while (targets.size() <= i) { + targets.add(null); + } + targets.set(i, target); + } + + public int getGroupSize() { + return groupSize; + } + public GraphSource getSource(int i) { + if (i < sources.size()) { + return sources.get(i); + } else { + return null; + } + } + public GraphTarget getTarget(int i) { + if (i < targets.size()) { + return targets.get(i); + } else { + return null; + } + } + + public static String getInput(int i) { + return INPUT+'['+i+']'; + } + public static String getOutput(int i) { + return OUTPUT+'['+i+']'; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index cda95a641a..78f731dd5b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -35,7 +35,7 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.renderer.framegraph.io.GraphSource; +import com.jme3.renderer.framegraph.client.GraphSource; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; @@ -52,10 +52,13 @@ */ public class Junction extends RenderPass { + private static final int EXTRA_INPUTS = 0; + private int length; private int groupSize; private ResourceTicket output; private GraphSource source; + private int defaultIndex = 0; public Junction() { this(2); @@ -72,31 +75,30 @@ public Junction(int length, int groupSize) { protected void initialize(FrameGraph frameGraph) { for (int i = 0; i < length; i++) { if (groupSize > 1) { - addInputGroup(getInputName(i), groupSize); + addInputGroup(Junction.getInput(i), groupSize); } else { - addInput(getInputName(i)); + addInput(Junction.getInput(i)); } } if (groupSize > 1) { - addOutputGroup("Value", groupSize); + addOutputGroup(Junction.getOutput(), groupSize); } else { - output = addOutput("Value"); + output = addOutput(Junction.getOutput()); } } @Override protected void prepare(FGRenderContext context) { int size; if (groupSize > 1) { - // output is also a group, so subtract one size = getGroups().size()-1; } else { - size = getInputTickets().size(); + size = getInputTickets().size()-EXTRA_INPUTS; } // remove excess tickets while (size > length) { size--; if (groupSize > 1) { - ResourceTicket[] array = removeGroup(getInputName(size)); + ResourceTicket[] array = removeGroup(Junction.getInput(size)); for (ResourceTicket t : array) { t.setSource(null); } @@ -107,9 +109,9 @@ protected void prepare(FGRenderContext context) { // add deficit tickets while (size < length) { if (groupSize > 1) { - addInputGroup(getInputName(size), groupSize); + addInputGroup(Junction.getInput(size), groupSize); } else { - addInput(getInputName(size)); + addInput(Junction.getInput(size)); } size++; } @@ -117,7 +119,7 @@ protected void prepare(FGRenderContext context) { if (source != null) { connect(source.getGraphValue(context.getViewPort())); } else { - connect(0); + connect(defaultIndex); } } @Override @@ -137,6 +139,7 @@ public void write(JmeExporter ex) throws IOException { OutputCapsule out = ex.getCapsule(this); out.write(length, "length", 2); out.write(groupSize, "groupSize", 1); + out.write(defaultIndex, "defaultIndex", 0); } @Override public void read(JmeImporter im) throws IOException { @@ -144,13 +147,14 @@ public void read(JmeImporter im) throws IOException { InputCapsule in = im.getCapsule(this); length = in.readInt("length", 2); groupSize = in.readInt("groupSize", 1); + defaultIndex = in.readInt("defaultIndex", 0); } private void connect(int i) { boolean assignNull = i < 0 || i >= length; if (groupSize > 1) { - ResourceTicket[] inArray = getGroup(getInputName(i)); - ResourceTicket[] outArray = getGroup("Value"); + ResourceTicket[] inArray = getGroup(Junction.getInput(i)); + ResourceTicket[] outArray = getGroup(Junction.getOutput()); for (int j = 0; j < groupSize; j++) { outArray[j].setSource(assignNull ? null : inArray[j]); } @@ -167,7 +171,7 @@ public final void setLength(int length) { } public final void setGroupSize(int groupSize) { if (isAssigned()) { - throw new IllegalStateException("Cannot alter group size after initialization."); + throw new IllegalStateException("Cannot alter group size while assigned to a framegraph."); } if (groupSize <= 0) { throw new IllegalArgumentException("Group length must be greater than zero."); @@ -177,6 +181,9 @@ public final void setGroupSize(int groupSize) { public void setIndexSource(GraphSource source) { this.source = source; } + public void setDefaultIndex(int defaultIndex) { + this.defaultIndex = defaultIndex; + } public int getLength() { return length; @@ -187,9 +194,21 @@ public int getGroupSize() { public GraphSource getIndexSource() { return source; } + public int getDefaultIndex() { + return defaultIndex; + } - public static String getInputName(int i) { + public static String getInput(int i) { return "Input["+i+"]"; } + public static String getInput(int i, int j) { + return "Input["+i+"]["+j+"]"; + } + public static String getOutput() { + return "Value"; + } + public static String getOutput(int i) { + return "Value["+i+"]"; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java index 9cec0b57b8..4f658c83fb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java @@ -10,7 +10,9 @@ import com.jme3.export.OutputCapsule; import com.jme3.light.LightList; import com.jme3.light.LightProbe; +import com.jme3.material.logic.TiledRenderGrid; import com.jme3.math.ColorRGBA; +import com.jme3.renderer.Camera; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; @@ -31,46 +33,82 @@ */ public class LightImagePass extends RenderPass { - private LightImagePacker packer = new LightImagePacker(); + private final LightImagePacker packer = new LightImagePacker(); private ResourceTicket lights; + private ResourceTicket tileInfo; private ResourceTicket[] textures; + private ResourceTicket[] tileTextures; private ResourceTicket numLights; private ResourceTicket ambientColor; private ResourceTicket> probes; - private final LightTextureDef texDef = new LightTextureDef(512); + private final LightTextureDef lightTexDef = new LightTextureDef(512); + private final TextureDef tileDef = TextureDef.texture2D(); + private final TextureDef indexDef = TextureDef.texture2D(); private final ColorRGBA ambient = new ColorRGBA(); private final LinkedList probeList = new LinkedList<>(); @Override protected void initialize(FrameGraph frameGraph) { lights = addInput("Lights"); + tileInfo = addInput("TileInfo"); textures = addOutputGroup("Textures", 3); + tileTextures = addOutputGroup("TileTextures", 2); numLights = addOutput("NumLights"); ambientColor = addOutput("Ambient"); probes = addOutput("Probes"); - texDef.setFormat(Image.Format.RGBA32F); - texDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); - texDef.setMagFilter(Texture.MagFilter.Nearest); - texDef.setWrap(Texture.WrapMode.EdgeClamp); + lightTexDef.setFormat(Image.Format.RGBA32F); + lightTexDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); + lightTexDef.setMagFilter(Texture.MagFilter.Nearest); + lightTexDef.setWrap(Texture.WrapMode.EdgeClamp); + tileDef.setFormat(Image.Format.RGBA32I); + tileDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); + tileDef.setMagFilter(Texture.MagFilter.Nearest); + tileDef.setWrap(Texture.WrapMode.EdgeClamp); + indexDef.setFormat(Image.Format.RGBA32I); + indexDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); + indexDef.setMagFilter(Texture.MagFilter.Nearest); + indexDef.setWrap(Texture.WrapMode.EdgeClamp); } @Override protected void prepare(FGRenderContext context) { for (ResourceTicket t : textures) { - declare(texDef, t); + declare(lightTexDef, t); reserve(t); } + declare(tileDef, tileTextures[0]); + declare(indexDef, tileTextures[1]); declare(null, numLights); declare(null, ambientColor); declare(null, probes); reference(lights); + referenceOptional(tileInfo); } @Override protected void execute(FGRenderContext context) { - packer.setTextures( - resources.acquire(textures[0]), - resources.acquire(textures[1]), - resources.acquire(textures[2])); - int n = packer.packLights(resources.acquire(lights), ambient, probeList); + LightList lightList = resources.acquire(lights); + TiledRenderGrid grid = resources.acquireOrElse(tileInfo, null); + Camera cam = context.getViewPort().getCamera(); + Texture2D tiles = null; + Texture2D indices = null; + if (grid != null) { + grid.update(cam); + tileDef.setSize(grid.getGridWidth(), grid.getGridHeight()); + // four indices are stored per pixel + int reqPixels = lightTexDef.getWidth()*grid.getNumTiles()/4; + if (indexDef.getNumPixels() < reqPixels) { + indexDef.setNumPixels(reqPixels, true, true, false); + } + tiles = resources.acquire(tileTextures[0]); + indices = resources.acquire(tileTextures[1]); + } else { + resources.setUndefined(tileTextures[0]); + resources.setUndefined(tileTextures[1]); + } + packer.setTextures(resources.acquire(textures[0]), + resources.acquire(textures[1]), + resources.acquire(textures[2]), + tiles, indices); + int n = packer.packLights(lightList, ambient, probeList, cam, grid); resources.setPrimitive(numLights, n); resources.setPrimitive(ambientColor, ambient); resources.setPrimitive(probes, probeList); @@ -83,21 +121,21 @@ protected void cleanup(FrameGraph frameGraph) {} public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule out = ex.getCapsule(this); - out.write(texDef.getWidth(), "maxLights", 512); + out.write(lightTexDef.getWidth(), "maxLights", 512); } @Override public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule in = im.getCapsule(this); - texDef.setWidth(in.readInt("maxLights", 512)); + lightTexDef.setWidth(in.readInt("maxLights", 512)); } - + public int getMaxLights() { - return texDef.getWidth(); + return lightTexDef.getWidth(); } public void setMaxLights(int maxLights) { - texDef.setWidth(maxLights); + lightTexDef.setWidth(maxLights); } private static class LightTextureDef extends TextureDef { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index e133c2a2bf..b50927eb20 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -513,48 +513,33 @@ public ResourceTicket[] getGroup(String name) { } /** - * Makes the named source (output) ticket belonging to the given pass the source of - * the named target (input) ticket belonging to this pass. - *

      - * If both the source name and target name correspond to ticket groups, the - * groups will be connected. + * Makes the named source (output) group belonging to the given pass the source of + * the named target (input) group belonging to this pass. * * @param sourcePass * @param sourceTicket * @param targetTicket - * @param start start index (inclusive) for connecting groups - * @param end end index (exclusive) for connecting groups - */ - public void makeInput(RenderPass sourcePass, String sourceTicket, String targetTicket, int start, int end) { - ResourceTicket[] sourceArray = sourcePass.getGroup(sourceTicket); - if (sourceArray != null) { - ResourceTicket[] targetArray = getGroup(targetTicket); - if (targetArray != null) { - int n = Math.min(end, Math.min(targetArray.length, sourceArray.length)); - for (int i = start; i < n; i++) { - targetArray[i].setSource(sourceArray[i]); - } - return; - } + * @param sourceStart start index (inclusive) for the source group + * @param targetStart start index (inclusive) for the target group + * @param length number of tickets to connect (clamped to group lengths) + */ + public void makeGroupInput(RenderPass sourcePass, String sourceTicket, String targetTicket, int sourceStart, int targetStart, int length) { + ResourceTicket[] sourceArray = Objects.requireNonNull(sourcePass.getGroup(sourceTicket), "Source group cannot be null."); + ResourceTicket[] targetArray = Objects.requireNonNull(getGroup(targetTicket), "Target group cannot be null."); + int n = Math.min(sourceStart+length, sourceArray.length); + int m = Math.min(targetStart+length, targetArray.length); + for (int i = sourceStart, j = targetStart; i < n && j < m; i++, j++) { + targetArray[j].setSource(sourceArray[i]); } - ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); - ResourceTicket target = Objects.requireNonNull(getInput(targetTicket), "Target ticket cannot be null."); - target.setSource(source); } /** - * Makes the named source (output) ticket belonging to the given pass the source of - * the named target (input) ticket belonging to this pass. - *

      - * If both the source name and target name correspond to ticket groups, the - * groups will be connected. * * @param sourcePass - * @param sourceTicket - * @param targetTicket - * @param start start index (inclusive) for connecting groups + * @param sourceGroup + * @param targetGroup */ - public void makeInput(RenderPass sourcePass, String sourceTicket, String targetTicket, int start) { - makeInput(sourcePass, sourceTicket, targetTicket, start, Integer.MAX_VALUE); + public void makeGroupInput(RenderPass sourcePass, String sourceGroup, String targetGroup) { + makeGroupInput(sourcePass, sourceGroup, targetGroup, 0, 0, Integer.MAX_VALUE); } /** * Makes the named source (output) ticket belonging to the given pass the source of @@ -563,12 +548,14 @@ public void makeInput(RenderPass sourcePass, String sourceTicket, String targetT * If both the source name and target name correspond to ticket groups, the * groups will be connected. * - * @param pass + * @param sourcePass * @param sourceTicket * @param targetTicket */ - public void makeInput(RenderPass pass, String sourceTicket, String targetTicket) { - makeInput(pass, sourceTicket, targetTicket, 0, Integer.MAX_VALUE); + public void makeInput(RenderPass sourcePass, String sourceTicket, String targetTicket) { + ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); + ResourceTicket target = Objects.requireNonNull(getInput(targetTicket), "Target ticket cannot be null."); + target.setSource(source); } /** * Nullifies all sources belonging to the given pass. 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 018e465774..7c154244ba 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -27,6 +27,12 @@ uniform int m_NBLights; uniform sampler2D m_LightTex2; uniform sampler2D m_LightTex3; uniform float m_LightTexInv; + #ifdef TILED_LIGHTS + uniform sampler2D m_Tiles; + uniform sampler2D m_LightIndex; + uniform vec3 m_LightIndexSize; // x=width, yz=size inverse + #define TILES true + #endif #else uniform vec4 g_LightData[NB_LIGHTS]; #endif @@ -59,9 +65,42 @@ void main(){ gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; gl_FragColor.a = alpha; //int lightNum = 0; + #ifdef TILES + // fetch index info from tile this fragment is contained by + vec4 tileInfo = texture2D(m_Tiles, innerTexCoord); + int x = int(tileInfo.x); + int y = int(tileInfo.y); + int componentIndex = int(tileInfo.z); + int lightCount = int(tileInfo.w); + vec4 lightIndex = vec4(-1.0); + for (int i = 0; i < lightCount;) { + #else for (int i = 0; i < NB_LIGHTS;) { + #endif #ifdef USE_LIGHT_TEXTURES - vec2 pixel = vec2(m_LightTexInv * i, 0); + #ifdef TILED_LIGHTS + if (componentIndex == 0 || lightIndex.x < 0) { + // get indices from next pixel + lightIndex = texture2D(m_LightIndex, vec2(x, y) * m_LightIndexSize.yz); + if (componentIndex == 0 && ++x >= m_LightIndexSize.x) { + x = 0; + y++; + } + } + // apply index from each component in order + vec2 pixel = vec2(m_LightTexInv, 0); + switch (componentIndex) { + case 0: pixel.x *= lightIndex.x; break; + case 1: pixel.x *= lightIndex.y; break; + case 2: pixel.x *= lightIndex.z; break; + case 3: pixel.x *= lightIndex.w; break; + } + if (++componentIndex > 3) { + componentIndex = 0; + } + #else + vec2 pixel = vec2(m_LightTexInv * i, 0); + #endif vec4 lightColor = texture2D(m_LightTex1, pixel); vec4 lightData1 = texture2D(m_LightTex2, pixel); #else @@ -74,16 +113,16 @@ void main(){ float spotFallOff = 1.0; #if __VERSION__ >= 110 - // allow use of control flow - if (lightColor.w > 1.0) { + // allow use of control flow + if (lightColor.w > 1.0) { #endif - #ifdef USE_LIGHT_TEXTURES - spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); - #else - spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); - #endif + #ifdef USE_LIGHT_TEXTURES + spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); + #else + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + #endif #if __VERSION__ >= 110 - } + } #endif #ifdef NORMALMAP 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 dc37bd9cb4..a5afea5e03 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 @@ -655,12 +655,6 @@ 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, null)); - break; case StaticPass: technique.setLogic(new StaticPassLightingLogic(technique)); break; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index c7c91ebea2..cfd4bb4262 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -52,11 +52,10 @@ import com.jme3.math.*; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; -import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.renderer.framegraph.debug.GraphEventCapture; -import com.jme3.renderer.framegraph.io.GraphSource; +import com.jme3.renderer.framegraph.client.GraphClient; import com.jme3.renderer.framegraph.passes.Junction; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; From f470edda16ea2536464d0cc299ef7b37bb82348f Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:19:25 -0400 Subject: [PATCH 088/111] added indefinite ticket groups --- .../java/com/jme3/export/InputCapsule.java | 11 +- .../java/com/jme3/export/NullSavable.java | 10 +- .../java/com/jme3/export/OutputCapsule.java | 15 +- .../main/java/com/jme3/export/Savable.java | 2 + .../com/jme3/export/SavableClassUtil.java | 1 + .../java/com/jme3/export/SavableObject.java | 154 +++++++++++++++ .../java/com/jme3/renderer/RenderManager.java | 43 +++-- .../jme3/renderer/framegraph/FrameGraph.java | 73 ++++++-- .../renderer/framegraph/FrameGraphData.java | 27 ++- .../framegraph/FrameGraphFactory.java | 11 +- .../renderer/framegraph/ResourceTicket.java | 21 ++- .../framegraph/client/GraphClient.java | 54 ------ .../framegraph/client/GraphSetting.java | 87 +++++++++ .../framegraph/client/GraphSource.java | 4 +- .../framegraph/client/GraphTarget.java | 4 +- .../client/MatParamTargetControl.java | 2 +- .../renderer/framegraph/passes/Attribute.java | 28 ++- .../framegraph/passes/DeferredPass.java | 6 +- .../framegraph/passes/GroupAttribute.java | 35 +++- .../renderer/framegraph/passes/Junction.java | 12 +- .../framegraph/passes/RenderPass.java | 176 +++++++++++------- .../framegraph/passes/SceneEnqueuePass.java | 151 +++++++++++++++ .../TestSimpleDeferredLighting.java | 4 +- 23 files changed, 739 insertions(+), 192 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/export/SavableObject.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphClient.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java diff --git a/jme3-core/src/main/java/com/jme3/export/InputCapsule.java b/jme3-core/src/main/java/com/jme3/export/InputCapsule.java index fd9cbff26a..dbe7a58fcc 100644 --- a/jme3-core/src/main/java/com/jme3/export/InputCapsule.java +++ b/jme3-core/src/main/java/com/jme3/export/InputCapsule.java @@ -39,6 +39,7 @@ import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.BitSet; +import java.util.Collection; import java.util.Map; /** @@ -109,7 +110,7 @@ public interface InputCapsule { // BinarySavable - + public Savable readSavable(String name, Savable defVal) throws IOException; public Savable[] readSavableArray(String name, Savable[] defVal) throws IOException; public Savable[][] readSavableArray2D(String name, Savable[][] defVal) throws IOException; @@ -125,6 +126,14 @@ public default T readSavable(String name, Class type, T d // ArrayLists + public default Collection readToCollection(String name, Collection target) throws IOException { + ArrayList list = readSavableArrayList(name, new ArrayList()); + for (Object obj : list) { + target.add(obj); + } + return target; + } + public ArrayList readSavableArrayList(String name, ArrayList defVal) throws IOException; public ArrayList[] readSavableArrayListArray(String name, ArrayList[] defVal) throws IOException; public ArrayList[][] readSavableArrayListArray2D(String name, ArrayList[][] defVal) throws IOException; diff --git a/jme3-core/src/main/java/com/jme3/export/NullSavable.java b/jme3-core/src/main/java/com/jme3/export/NullSavable.java index e3384a4ca7..4893d9e9ba 100644 --- a/jme3-core/src/main/java/com/jme3/export/NullSavable.java +++ b/jme3-core/src/main/java/com/jme3/export/NullSavable.java @@ -41,10 +41,12 @@ * @author Kirill Vainer */ public class NullSavable implements Savable { + + public static final NullSavable INSTANCE = new NullSavable(); + @Override - public void write(JmeExporter ex) throws IOException { - } + public void write(JmeExporter ex) throws IOException {} @Override - public void read(JmeImporter im) throws IOException { - } + public void read(JmeImporter im) throws IOException {} + } diff --git a/jme3-core/src/main/java/com/jme3/export/OutputCapsule.java b/jme3-core/src/main/java/com/jme3/export/OutputCapsule.java index 1612a61c13..35ac81b8d3 100644 --- a/jme3-core/src/main/java/com/jme3/export/OutputCapsule.java +++ b/jme3-core/src/main/java/com/jme3/export/OutputCapsule.java @@ -39,13 +39,14 @@ import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.BitSet; +import java.util.Collection; import java.util.Map; /** * @author Joshua Slack */ public interface OutputCapsule { - + // byte primitive public void write(byte value, String name, byte defVal) throws IOException; @@ -115,7 +116,17 @@ public interface OutputCapsule { // ArrayLists - + + public default void writeFromCollection(Collection collection, String name, boolean checkSavable) throws IOException { + ArrayList list = new ArrayList(collection.size()); + for (Object obj : collection) { + if (!checkSavable || obj instanceof Savable) { + list.add(obj); + } + } + writeSavableArrayList(list, name, new ArrayList()); + } + public void writeSavableArrayList(ArrayList array, String name, ArrayList defVal) throws IOException; public void writeSavableArrayListArray(ArrayList[] array, String name, ArrayList[] defVal) throws IOException; public void writeSavableArrayListArray2D(ArrayList[][] array, String name, ArrayList[][] defVal) throws IOException; diff --git a/jme3-core/src/main/java/com/jme3/export/Savable.java b/jme3-core/src/main/java/com/jme3/export/Savable.java index 85957fc24f..004f381a12 100644 --- a/jme3-core/src/main/java/com/jme3/export/Savable.java +++ b/jme3-core/src/main/java/com/jme3/export/Savable.java @@ -40,6 +40,8 @@ * @author Kirill Vainer */ public interface Savable { + void write(JmeExporter ex) throws IOException; void read(JmeImporter im) throws IOException; + } diff --git a/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java b/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java index 2c63050a4d..42d5bc896c 100644 --- a/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java +++ b/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java @@ -252,4 +252,5 @@ private static Constructor findNoArgConstructor(String className) return result; } + } diff --git a/jme3-core/src/main/java/com/jme3/export/SavableObject.java b/jme3-core/src/main/java/com/jme3/export/SavableObject.java new file mode 100644 index 0000000000..cd8b281294 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/export/SavableObject.java @@ -0,0 +1,154 @@ +/* + * 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.export; + +import com.jme3.util.IntMap; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Map; + +/** + * + * @author codex + */ +public class SavableObject implements Savable { + + private Object object; + private final String name = "object"; + + public SavableObject() {} + public SavableObject(Object object) { + this.object = object; + } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + if (object instanceof Savable) { + out.write((Savable)object, name, (Savable)object); + out.write("Savable", "type", ""); + } else if (object instanceof Integer) { + out.write((int)object, name, (int)object); + out.write("Integer", "type", ""); + } else if (object instanceof Float) { + out.write((float)object, name, (float)object); + out.write("Float", "type", ""); + } else if (object instanceof Double) { + out.write((double)object, name, (double)object); + out.write("Double", "type", ""); + } else if (object instanceof Boolean) { + out.write((boolean)object, name, (boolean)object); + out.write("Boolean", "type", ""); + } else if (object instanceof Byte) { + out.write((byte)object, name, (byte)object); + out.write("Byte", "type", ""); + } else if (object instanceof String) { + out.write((String)object, name, (String)object); + out.write("String", "type", ""); + } else if (object instanceof Long) { + out.write((Long)object, name, (Long)object); + out.write("Long", "type", ""); + } else if (object instanceof Short) { + out.write((short)object, name, (short)object); + out.write("Short", "type", ""); + } else if (object instanceof BitSet) { + out.write((BitSet)object, name, (BitSet)object); + out.write("BitSet", "type", ""); + } else if (object instanceof FloatBuffer) { + out.write((FloatBuffer)object, name, (FloatBuffer)object); + out.write("FloatBuffer", "type", ""); + } else if (object instanceof IntBuffer) { + out.write((IntBuffer)object, name, (IntBuffer)object); + out.write("IntBuffer", "type", ""); + } else if (object instanceof ByteBuffer) { + out.write((ByteBuffer)object, name, (ByteBuffer)object); + out.write("ByteBuffer", "type", ""); + } else if (object instanceof ShortBuffer) { + out.write((ShortBuffer)object, name, (ShortBuffer)object); + out.write("ShortBuffer", "type", ""); + } else if (object instanceof ArrayList) { + out.writeSavableArrayList((ArrayList)object, name, (ArrayList)object); + out.write("ArrayList", "type", ""); + } else if (object instanceof Map) { + out.writeStringSavableMap((Map)object, name, (Map)object); + out.write("StringMap", "type", ""); + } else if (object instanceof IntMap) { + out.writeIntSavableMap((IntMap)object, name, (IntMap)object); + out.write("IntMap", "type", ""); + } + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + String type = in.readString("type", ""); + switch (type) { + case "Savable": + object = in.readSavable(name, null); + break; + case "Integer": + object = in.readInt(name, 0); + break; + case "Float": + object = in.readFloat(name, 0); + break; + case "Double": + object = in.readDouble(name, 0); + break; + case "Boolean": + object = in.readBoolean(name, false); + break; + case "Byte": + object = in.readByte(name, (byte)0); + break; + case "String": + object = in.readString(name, null); + break; + case "Long": + object = in.readLong(name, 0); + break; + case "Short": + object = in.readShort(name, (short)0); + break; + case "BitSet": + object = in.readBitSet(name, null); + break; + case "FloatBuffer": + object = in.readFloatBuffer(name, null); + break; + case "IntBuffer": + object = in.readIntBuffer(name, null); + break; + case "ByteBuffer": + object = in.readByteBuffer(name, null); + break; + case "ShortBuffer": + object = in.readShortBuffer(name, null); + break; + case "ArrayList": + object = in.readSavableArrayList(name, null); + break; + case "StringMap": + object = in.readStringSavableMap(name, null); + break; + case "IntMap": + object = in.readIntSavableMap(name, null); + break; + } + } + + public void setObject(Object object) { + this.object = object; + } + + public Object getObject() { + return object; + } + +} 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 24fd3137d4..f6132bf919 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -1303,7 +1303,7 @@ public void renderViewPort(ViewPort vp, float tpf) { } if (fg != null) { fg.configure(this, vp, prof, tpf); - fg.preFrame(); + //fg.preFrame(); } else if (processors != null) { for (SceneProcessor p : processors.getArray()) { if (!p.isInitialized()) { @@ -1326,26 +1326,25 @@ public void renderViewPort(ViewPort vp, float tpf) { renderer.clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); } - if (prof != null) { - prof.vpStep(VpStep.RenderScene, vp, null); - } - // flatten scenes into render queue - List scenes = vp.getScenes(); - for (int i = scenes.size() - 1; i >= 0; i--) { - renderScene(scenes.get(i), vp); - } - - if (prof != null && (fg != null || processors != null)) { - prof.vpStep(VpStep.PostQueue, vp, null); - } - if (fg != null) { - fg.postQueue(); - } else if (processors != null) { - for (SceneProcessor p : processors.getArray()) { + if (fg == null) { + if (prof != null) { + prof.vpStep(VpStep.RenderScene, vp, null); + } + // flatten scenes into render queue + 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.spStep(SpStep.ProcPostQueue, p.getClass().getSimpleName()); + 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()); } - p.postQueue(vp.getQueue()); } } @@ -1378,12 +1377,12 @@ public void renderViewPort(ViewPort vp, float tpf) { // render 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 (fg != null) { renderObjects.clearReservations(); } 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 0ac5d853c5..00a70f993a 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 @@ -41,6 +41,7 @@ import com.jme3.profile.VpStep; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.client.GraphSetting; import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.passes.Attribute; import java.util.HashMap; @@ -91,7 +92,7 @@ public class FrameGraph { private final ResourceList resources; private final FGRenderContext context; private final LinkedList passes = new LinkedList<>(); - private final HashMap blackboard = new HashMap<>(); + private final HashMap settings = new HashMap<>(); private String name = "FrameGraph"; private boolean rendered = false; @@ -286,7 +287,7 @@ public T add(T pass, int index) { */ public Attribute addAttribute(ResourceTicket ticket) { Attribute attr = add(new Attribute<>()); - attr.getInput(Attribute.OUTPUT).setSource(ticket); + attr.getInput(Attribute.INPUT).setSource(ticket); return attr; } @@ -356,7 +357,7 @@ public RenderPass remove(int i) { for (Iterator it = passes.iterator(); it.hasNext();) { RenderPass p = it.next(); if (removed != null) { - p.disconnectFrom(removed); + p.disconnectInputsFrom(removed); p.shiftExecutionIndex(i, false); } else if (j++ == i) { removed = p; @@ -383,7 +384,7 @@ public boolean remove(RenderPass pass) { RenderPass p = it.next(); if (found) { // shift execution indices down - p.disconnectFrom(pass); + p.disconnectInputsFrom(pass); p.shiftExecutionIndex(i, false); continue; } @@ -410,26 +411,58 @@ public void clear() { } /** - * Posts an object to the blackboard. + * Sets the setting under the name. * * @param * @param name * @param object * @return given object */ - public T post(String name, T object) { - blackboard.put(name, object); + public T setSetting(String name, T object) { + settings.put(name, object); return object; } /** - * Reads an object from the blackboard. + * Sets the setting under the name and creates a GraphSetting + * of the same name. + * + * @param + * @param name + * @param object + * @param create + * @return created graph setting + */ + public GraphSetting setSetting(String name, T object, boolean create) { + setSetting(name, object); + if (create) { + return new GraphSetting<>(name); + } else { + return null; + } + } + /** + * Sets an integer setting based on a boolean value. + *

      + * If the boolean is true, 0 is written, otherwise -1 is written. This is + * used primarily for Junction sources: 0 points to the first input, and -1 + * points to no input. + * + * @param name + * @param value + * @return + */ + public int setJunctionSetting(String name, boolean value) { + return setSetting(name, value ? 0 : -1); + } + /** + * Gets the setting under the name, or null. * * @param * @param name * @return */ - public T fetch(String name) { - Object obj = blackboard.get(name); + public T getSetting(String name) { + Object obj = settings.get(name); if (obj != null) { return (T)obj; } else { @@ -437,20 +470,30 @@ public T fetch(String name) { } } /** - * Removes an object from the blackboard. + * Removes the setting under the name. * * @param * @param name - * @return + * @return removed setting, or null */ - public T remove(String name) { - Object obj = blackboard.remove(name); + public T removeSetting(String name) { + Object obj = settings.remove(name); if (obj != null) { return (T)obj; } else { return null; } } + /** + * Gets the settings map. + *

      + * The returned map may be modified. + * + * @return + */ + public HashMap getSettingsMap() { + return settings; + } /** * Sets the name of this framegraph. @@ -579,7 +622,7 @@ public FrameGraph loadData(String assetPath) { * @return */ public FrameGraphData createData() { - return new FrameGraphData(this, passes); + return new FrameGraphData(this, passes, settings); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java index 47ec099b20..bf2ce78120 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java @@ -36,11 +36,13 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; +import com.jme3.export.SavableObject; import com.jme3.renderer.framegraph.passes.RenderPass; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; /** * Holds framegraph data ready for import or export. @@ -51,17 +53,27 @@ */ public class FrameGraphData implements Savable { + private static final String DEF_NAME = "FrameGraph"; + private static final RenderPass[] DEF_PASSES = new RenderPass[0]; + private static final SavablePassConnection[] DEF_CONNECTIONS = new SavablePassConnection[0]; + private static final HashMap DEF_SETTINGS = new HashMap<>(); + private final boolean export; private String name; private RenderPass[] passes; private SavablePassConnection[] connections; + private Map settings; public FrameGraphData() { export = false; } - public FrameGraphData(FrameGraph fg, Collection passes) { + public FrameGraphData(FrameGraph fg, Collection passes, Map settings) { this.name = fg.getName(); this.passes = passes.toArray(RenderPass[]::new); + this.settings = new HashMap<>(); + for (String key : settings.keySet()) { + this.settings.put(key, new SavableObject(settings.get(key))); + } export = true; } @@ -89,9 +101,10 @@ public void write(JmeExporter ex) throws IOException { } } OutputCapsule out = ex.getCapsule(this); - out.write(name, "name", "FrameGraph"); - out.write(passes, "passes", new RenderPass[0]); - out.write(list.toArray(SavablePassConnection[]::new), "connections", new SavablePassConnection[0]); + out.write(name, "name", DEF_NAME); + out.write(passes, "passes", DEF_PASSES); + out.write(list.toArray(SavablePassConnection[]::new), "connections", DEF_CONNECTIONS); + out.writeStringSavableMap(settings, "settings", DEF_SETTINGS); // reset export ids for (RenderPass p : passes) { p.setExportId(-1); @@ -99,6 +112,7 @@ public void write(JmeExporter ex) throws IOException { idMap.clear(); list.clear(); passes = null; + settings.clear(); } @Override public void read(JmeImporter im) throws IOException { @@ -120,6 +134,7 @@ public void read(JmeImporter im) throws IOException { SavablePassConnection c = connections[i] = (SavablePassConnection)array[i]; c.shiftIds(baseId); } + settings = (Map)in.readStringSavableMap("settings", DEF_SETTINGS); } /** @@ -151,6 +166,10 @@ public void apply(FrameGraph fg) { RenderPass output = cache.get(c.getOutputId()); input.makeInput(output, c.getOutputTicket(), c.getInputTicket()); } + // transfer settings + for (String key : settings.keySet()) { + fg.setSetting(key, settings.get(key).getObject()); + } cache.clear(); passes = null; connections = null; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index a6451dcebf..14f267c9bc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -33,7 +33,7 @@ import com.jme3.asset.AssetManager; import com.jme3.material.logic.TiledRenderGrid; -import com.jme3.renderer.framegraph.client.GraphClient; +import com.jme3.renderer.framegraph.client.GraphSetting; import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.framegraph.passes.DeferredPass; import com.jme3.renderer.framegraph.passes.GBufferPass; @@ -99,21 +99,18 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { fg.add(new PostProcessingPass()); fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); - GraphClient tileInfo = fg.post("TileInfo", new GraphClient()); - tileInfo.setValue(new TiledRenderGrid()); + GraphSetting tileInfo = fg.setSetting("TileInfo", new TiledRenderGrid(), true); tileInfoAttr.setName("TileInfo"); tileInfoAttr.setSource(tileInfo); - GraphClient tileToggle = fg.post("TileToggle", new GraphClient()); - tileToggle.setValue(tiled ? 0 : -1); + GraphSetting tileToggle = fg.setSetting("TileToggle", tiled ? 0 : -1, true); tileJunct1.makeInput(tileInfoAttr, Attribute.OUTPUT, Junction.getInput(0)); tileJunct1.setIndexSource(tileToggle); lightImg.makeInput(gbuf, "Lights", "Lights"); lightImg.makeInput(tileInfoAttr, Attribute.OUTPUT, "TileInfo"); - GraphClient lightPackMethod = fg.post("LightPackMethod", new GraphClient()); - lightPackMethod.setValue(tiled ? 0 : -1); + GraphSetting lightPackMethod = fg.setSetting("LightPackMethod", tiled ? 0 : -1, true); lightJunct.setName("LightPackMethod"); lightJunct.makeGroupInput(lightImg, "Textures", Junction.getInput(0), 0, 0, 3); lightJunct.makeInput(lightImg, "NumLights", Junction.getInput(0, 3)); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index 0148f52f29..4a62344272 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -45,7 +45,7 @@ */ public class ResourceTicket { - private String name; + private String name, groupName; private int passId = -1; private int localIndex; private long objectId = -1; @@ -65,6 +65,17 @@ public ResourceTicket() { public ResourceTicket(String name) { this(name, -1); } + /** + * Creates a ticket with the name, belonging to the named group, + * and with a negative local index. + * + * @param name + * @param groupName + */ + public ResourceTicket(String name, String groupName) { + this(name, -1); + this.groupName = groupName; + } /** * Creates a ticket with the local index. * @@ -165,6 +176,14 @@ public void setObjectId(long objectId) { public String getName() { return name; } + /** + * Gets the name of the group this ticket is a member of, if any. + * + * @return group name, or null + */ + public String getGroupName() { + return groupName; + } /** * * @return diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphClient.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphClient.java deleted file mode 100644 index 8aa6b9ad4b..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphClient.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.client; - -import com.jme3.renderer.ViewPort; - -/** - * - * @author codex - * @param - */ -public class GraphClient implements GraphSource, GraphTarget { - - private T value; - private ViewPortFilter filter; - - public GraphClient() {} - public GraphClient(T value) { - this.value = value; - } - - @Override - public T getGraphValue(ViewPort viewPort) { - if (filter == null || filter.confirm(viewPort)) { - return value; - } - return null; - } - @Override - public boolean setGraphValue(ViewPort viewPort, T value) { - if (filter == null || filter.confirm(viewPort)) { - this.value = value; - return true; - } - return false; - } - - public void setValue(T value) { - this.value = value; - } - public void setFilter(ViewPortFilter filter) { - this.filter = filter; - } - - public T getValue() { - return value; - } - public ViewPortFilter getFilter() { - return filter; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java new file mode 100644 index 0000000000..9511696270 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java @@ -0,0 +1,87 @@ +/* + * 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.client; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FrameGraph; +import java.io.IOException; + +/** + * + * @author codex + * @param + */ +public class GraphSetting implements GraphSource, GraphTarget, Savable { + + private String name; + private ViewPortFilter filter; + + public GraphSetting() { + this(""); + } + public GraphSetting(String name) { + this.name = name; + } + + @Override + public T getGraphValue(FrameGraph frameGraph, ViewPort viewPort) { + if (filter == null || filter.confirm(viewPort)) { + return frameGraph.getSetting(name); + } + return null; + } + @Override + public boolean setGraphValue(FrameGraph frameGraph, ViewPort viewPort, T value) { + if (filter == null || filter.confirm(viewPort)) { + frameGraph.setSetting(name, value); + return true; + } + return false; + } + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(name, "name", ""); + if (filter != null && filter instanceof Savable) { + out.write((Savable)filter, "filter", new DefaultSavableFilter()); + } + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + name = in.readString("name", ""); + filter = (ViewPortFilter)in.readSavable("filter", new DefaultSavableFilter()); + } + + public void setFilter(ViewPortFilter filter) { + this.filter = filter; + } + + public String getName() { + return name; + } + public ViewPortFilter getFilter() { + return filter; + } + + public static class DefaultSavableFilter implements ViewPortFilter, Savable { + + @Override + public boolean confirm(ViewPort vp) { + return true; + } + @Override + public void write(JmeExporter ex) throws IOException {} + @Override + public void read(JmeImporter im) throws IOException {} + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java index 1327700e3f..25dd46dffe 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java @@ -32,6 +32,7 @@ package com.jme3.renderer.framegraph.client; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FrameGraph; /** * Provides values to a framegraph from game logic. @@ -44,9 +45,10 @@ public interface GraphSource { /** * Gets the value provided to the framegraph. * + * @param frameGraph framegraph currently rendering * @param viewPort viewport currently being rendered * @return value (may be null in some circumstances) */ - public T getGraphValue(ViewPort viewPort); + public T getGraphValue(FrameGraph frameGraph, ViewPort viewPort); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java index 57b9d2d4e6..67285ae13d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java @@ -32,6 +32,7 @@ package com.jme3.renderer.framegraph.client; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FrameGraph; /** * Receives values from a FrameGraph. @@ -44,10 +45,11 @@ public interface GraphTarget { /** * Sets the value recieved from the framegraph. * + * @param frameGraph framegraph currently rendering * @param viewPort viewport currently being rendered * @param value value from framegraph * @return true if value is used */ - public boolean setGraphValue(ViewPort viewPort, T value); + public boolean setGraphValue(FrameGraph frameGraph, ViewPort viewPort, T value); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java index a10af2ff5e..10b89167f6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java @@ -82,7 +82,7 @@ public void setSpatial(Spatial spat) { } } @Override - public boolean setGraphValue(ViewPort viewPort, T value) { + public boolean setGraphValue(FrameGraph frameGraph, ViewPort viewPort, T value) { if (containsViewPort(viewPort)) { this.value = value; if (this.value != null) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index 169c7f2ffe..160883689b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -31,8 +31,12 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; +import com.jme3.export.NullSavable; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.renderer.framegraph.client.GraphTarget; import com.jme3.renderer.framegraph.client.GraphSource; import com.jme3.renderer.framegraph.FGRenderContext; @@ -78,7 +82,7 @@ protected void execute(FGRenderContext context) { if (inVal != null && !targets.isEmpty()) { boolean used = false; for (GraphTarget t : targets) { - if (t.setGraphValue(context.getViewPort(), inVal)) { + if (t.setGraphValue(frameGraph, context.getViewPort(), inVal)) { used = true; } } @@ -88,7 +92,7 @@ protected void execute(FGRenderContext context) { } T outVal; if (source != null) { - outVal = source.getGraphValue(context.getViewPort()); + outVal = source.getGraphValue(frameGraph, context.getViewPort()); } else { outVal = defaultValue; } @@ -109,6 +113,26 @@ protected void cleanup(FrameGraph frameGraph) { public boolean isUsed() { return super.isUsed() || in.hasSource(); } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + out.writeFromCollection(targets, "targets", true); + if (source != null && source instanceof Savable) { + out.write((Savable)source, "source", NullSavable.INSTANCE); + } + if (defaultValue != null && defaultValue instanceof Savable) { + out.write((Savable)defaultValue, "default", NullSavable.INSTANCE); + } + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + in.readToCollection("targets", targets); + source = (GraphSource)in.readSavable("source", null); + defaultValue = (T)in.readSavable("default", null); + } /** * Adds the graph target. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index dfca865fa1..437832475f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -130,9 +130,9 @@ protected void prepare(FGRenderContext context) { declare(colorDef, outColor); reserve(outColor); // groups are stored by hashmap, which makes it absolutely fine to fetch every frame - reference(getGroup("GBufferData")); + reference(getGroupArray("GBufferData")); referenceOptional(lights, numLights, ambient, probes); - referenceOptional(getGroup("LightTextures")); + referenceOptional(getGroupArray("LightTextures")); } @Override protected void execute(FGRenderContext context) { @@ -141,7 +141,7 @@ protected void execute(FGRenderContext context) { context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); - ResourceTicket[] gbuffers = getGroup("GBufferData"); + ResourceTicket[] gbuffers = getGroupArray("GBufferData"); for (int i = 0; i < gbuffers.length; i++) { material.setTexture("GBuffer"+i, resources.acquire(gbuffers[i])); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java index 6c17ca259a..d47f672fd5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java @@ -4,12 +4,19 @@ */ package com.jme3.renderer.framegraph.passes; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.NullSavable; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.client.GraphSource; import com.jme3.renderer.framegraph.client.GraphTarget; +import java.io.IOException; import java.util.ArrayList; /** @@ -36,28 +43,28 @@ protected void initialize(FrameGraph frameGraph) { } @Override protected void prepare(FGRenderContext context) { - for (ResourceTicket t : getGroup(OUTPUT)) { + for (ResourceTicket t : getGroupArray(OUTPUT)) { declare(null, t); } - referenceOptional(getGroup(INPUT)); + referenceOptional(getGroupArray(INPUT)); } @Override protected void execute(FGRenderContext context) { ViewPort vp = context.getViewPort(); - ResourceTicket[] inTickets = getGroup(INPUT); + ResourceTicket[] inTickets = getGroupArray(INPUT); for (int i = 0, n = Math.min(groupSize, targets.size()); i < n; i++) { Object value = resources.acquireOrElse(inTickets[i], null); GraphTarget t = targets.get(i); - if (t != null && t.setGraphValue(vp, value)) { + if (t != null && t.setGraphValue(frameGraph, vp, value)) { resources.setConstant(inTickets[i]); } } int i = 0; - ResourceTicket[] outTickets = getGroup(OUTPUT); + ResourceTicket[] outTickets = getGroupArray(OUTPUT); for (int n = Math.min(groupSize, sources.size()); i < n; i++) { GraphSource s = sources.get(i); if (s != null) { - Object value = s.getGraphValue(vp); + Object value = s.getGraphValue(frameGraph, vp); if (value != null) { resources.setPrimitive(outTickets[i], value); continue; @@ -73,6 +80,22 @@ protected void execute(FGRenderContext context) { protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + out.write(groupSize, "groupSize", 2); + out.writeFromCollection(sources, "sources", true); + out.writeFromCollection(targets, "targets", true); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + groupSize = in.readInt("groupSize", 2); + in.readToCollection("sources", sources); + in.readToCollection("targets", targets); + } public void setGroupSize(int groupSize) { if (isAssigned()) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 78f731dd5b..d632ff624d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -34,7 +34,9 @@ import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; +import com.jme3.export.NullSavable; import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.renderer.framegraph.client.GraphSource; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; @@ -117,7 +119,7 @@ protected void prepare(FGRenderContext context) { } // connect output to input if (source != null) { - connect(source.getGraphValue(context.getViewPort())); + connect(source.getGraphValue(frameGraph, context.getViewPort())); } else { connect(defaultIndex); } @@ -140,6 +142,9 @@ public void write(JmeExporter ex) throws IOException { out.write(length, "length", 2); out.write(groupSize, "groupSize", 1); out.write(defaultIndex, "defaultIndex", 0); + if (source != null && source instanceof Savable) { + out.write((Savable)source, "source", NullSavable.INSTANCE); + } } @Override public void read(JmeImporter im) throws IOException { @@ -148,13 +153,14 @@ public void read(JmeImporter im) throws IOException { length = in.readInt("length", 2); groupSize = in.readInt("groupSize", 1); defaultIndex = in.readInt("defaultIndex", 0); + source = (GraphSource)in.readSavable("source", null); } private void connect(int i) { boolean assignNull = i < 0 || i >= length; if (groupSize > 1) { - ResourceTicket[] inArray = getGroup(Junction.getInput(i)); - ResourceTicket[] outArray = getGroup(Junction.getOutput()); + ResourceTicket[] inArray = getGroupArray(Junction.getInput(i)); + ResourceTicket[] outArray = getGroupArray(Junction.getOutput()); for (int j = 0; j < groupSize; j++) { outArray[j].setSource(assignNull ? null : inArray[j]); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index b50927eb20..3bf00e77fc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -45,7 +45,7 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import java.io.IOException; -import java.util.Collection; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -63,12 +63,13 @@ public abstract class RenderPass implements ResourceProducer, Savable { private int id = nextId++; private int exportId = -1; private String name; + protected FrameGraph frameGraph; private int index = -1; private int refs = 0; private final LinkedList inputs = new LinkedList<>(); private final LinkedList outputs = new LinkedList<>(); private final LinkedList frameBuffers = new LinkedList<>(); - private final HashMap groups = new HashMap<>(); + private final HashMap groups = new HashMap<>(); protected ResourceList resources; protected boolean autoTicketRelease = true; @@ -79,6 +80,7 @@ public abstract class RenderPass implements ResourceProducer, Savable { * @param index execution index */ public void initializePass(FrameGraph frameGraph, int index) { + this.frameGraph = frameGraph; this.index = index; this.resources = frameGraph.getResources(); if (name == null) { @@ -135,6 +137,7 @@ public void cleanupPass(FrameGraph frameGraph) { outputs.clear(); groups.clear(); index = -1; + this.frameGraph = null; } /** @@ -290,7 +293,7 @@ protected void referenceOptional(ResourceTicket... tickets) { * @return */ protected T[] acquireGroup(String name, T[] array) { - ResourceTicket[] tickets = Objects.requireNonNull(getGroup(name), "Ticket group cannot be null."); + ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); int n = Math.min(array.length, tickets.length); for (int i = 0; i < n; i++) { array[i] = resources.acquire(tickets[i]); @@ -310,7 +313,7 @@ protected T[] acquireGroup(String name, T[] array) { * @return */ protected T[] acquireGroupOrElse(String name, T[] array, T val) { - ResourceTicket[] tickets = Objects.requireNonNull(getGroup(name), "Ticket group cannot be null."); + ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); int n = Math.min(array.length, tickets.length); for (int i = 0; i < n; i++) { array[i] = resources.acquireOrElse(tickets[i], val); @@ -375,42 +378,6 @@ protected ResourceTicket addInput(String name) { protected ResourceTicket addOutput(String name) { return addOutput(new ResourceTicket<>(name)); } - /** - * Adds the ticket array as a group input under the given name. - * - * @param - * @param name - * @param array - * @return ticket array - */ - protected ResourceTicket[] addInputGroup(String name, ResourceTicket... array) { - for (ResourceTicket t : array) { - if (t == null) { - throw new NullPointerException("Ticket cannot be null in group."); - } - addInput(t); - } - groups.put(name, array); - return array; - } - /** - * Adds the ticket array as a group output under the given name. - * - * @param - * @param name - * @param array - * @return ticket array - */ - protected ResourceTicket[] addOutputGroup(String name, ResourceTicket... array) { - for (ResourceTicket t : array) { - if (t == null) { - throw new NullPointerException("Ticket cannot be null in group."); - } - addOutput(t); - } - groups.put(name, array); - return array; - } /** * Creates and adds a ticket array as a group input of the specified length under the given name. *

      @@ -424,9 +391,9 @@ protected ResourceTicket[] addOutputGroup(String name, ResourceTicket. protected ResourceTicket[] addInputGroup(String name, int length) { ResourceTicket[] array = new ResourceTicket[length]; for (int i = 0; i < length; i++) { - addInput(array[i] = new ResourceTicket<>(name+"["+i+"]")); + addInput(array[i] = new ResourceTicket<>(groupTicketName(name, i), name)); } - groups.put(name, array); + groups.put(name, new TicketGroup(name, array)); return array; } /** @@ -442,11 +409,19 @@ protected ResourceTicket[] addInputGroup(String name, int length) { protected ResourceTicket[] addOutputGroup(String name, int length) { ResourceTicket[] array = new ResourceTicket[length]; for (int i = 0; i < length; i++) { - addOutput(array[i] = new ResourceTicket<>(name+"["+i+"]")); + addOutput(array[i] = new ResourceTicket<>(groupTicketName(name, i), name)); } - groups.put(name, array); + groups.put(name, new TicketGroup(name, array)); return array; } + /** + * Creates an input group of indefinite size. + * + * @param name + */ + protected void addInputGroup(String name) { + groups.put(name, new TicketGroup(name)); + } /** * Removes all members of the named group from the input and output lists. @@ -456,14 +431,14 @@ protected ResourceTicket[] addOutputGroup(String name, int length) { * @return */ protected ResourceTicket[] removeGroup(String name) { - ResourceTicket[] array = groups.remove(name); - if (array == null) { + TicketGroup group = groups.remove(name); + if (group == null) { return null; } // Once we determine which list group members were added to, we only // need to remove from that list for future members. byte state = 0; - for (ResourceTicket t : array) { + for (ResourceTicket t : group.array) { if (state >= 0 && inputs.remove(t)) { state = 1; } @@ -471,7 +446,7 @@ protected ResourceTicket[] removeGroup(String name) { state = -1; } } - return array; + return group.array; } /** @@ -508,8 +483,13 @@ public ResourceTicket getOutput(String name) { * @param name * @return */ - public ResourceTicket[] getGroup(String name) { - return groups.get(name); + public ResourceTicket[] getGroupArray(String name) { + TicketGroup group = groups.get(name); + if (group != null) { + return group.array; + } else { + return null; + } } /** @@ -517,15 +497,15 @@ public ResourceTicket[] getGroup(String name) { * the named target (input) group belonging to this pass. * * @param sourcePass - * @param sourceTicket - * @param targetTicket + * @param sourceGroup + * @param targetGroup * @param sourceStart start index (inclusive) for the source group * @param targetStart start index (inclusive) for the target group * @param length number of tickets to connect (clamped to group lengths) */ - public void makeGroupInput(RenderPass sourcePass, String sourceTicket, String targetTicket, int sourceStart, int targetStart, int length) { - ResourceTicket[] sourceArray = Objects.requireNonNull(sourcePass.getGroup(sourceTicket), "Source group cannot be null."); - ResourceTicket[] targetArray = Objects.requireNonNull(getGroup(targetTicket), "Target group cannot be null."); + public void makeGroupInput(RenderPass sourcePass, String sourceGroup, String targetGroup, int sourceStart, int targetStart, int length) { + ResourceTicket[] sourceArray = Objects.requireNonNull(sourcePass.getGroupArray(sourceGroup), "Source group cannot be null."); + ResourceTicket[] targetArray = Objects.requireNonNull(getGroupArray(targetGroup), "Target group cannot be null."); int n = Math.min(sourceStart+length, sourceArray.length); int m = Math.min(targetStart+length, targetArray.length); for (int i = sourceStart, j = targetStart; i < n && j < m; i++, j++) { @@ -557,15 +537,36 @@ public void makeInput(RenderPass sourcePass, String sourceTicket, String targetT ResourceTicket target = Objects.requireNonNull(getInput(targetTicket), "Target ticket cannot be null."); target.setSource(source); } + /** + * Adds the indicated source ticket as an input to the target indefinite group. + * + * @param sourcePass + * @param sourceTicket + * @param targetGroup + */ + public void addInputToGroup(RenderPass sourcePass, String sourceTicket, String targetGroup) { + ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); + TicketGroup target = Objects.requireNonNull(groups.get(targetGroup), "Target group cannot be null."); + if (!target.indefinite) { + throw new IllegalStateException("Target group must be indefinite."); + } + target.add().setSource(source); + } /** * Nullifies all sources belonging to the given pass. * * @param pass */ - public void disconnectFrom(RenderPass pass) { + public void disconnectInputsFrom(RenderPass pass) { for (ResourceTicket in : inputs) { if (pass.getOutputTickets().contains(in.getSource())) { in.setSource(null); + if (in.getGroupName() != null) { + TicketGroup g = groups.get(in.getGroupName()); + if (g != null && g.indefinite) { + g.remove(in); + } + } } } } @@ -726,13 +727,6 @@ public int getIndex() { public boolean isAssigned() { return index >= 0; } - /** - * - * @return - */ - protected HashMap getGroups() { - return groups; - } @Override public int getExecutionIndex() { @@ -781,6 +775,16 @@ public static int getNextId() { return nextId; } + /** + * + * @param group + * @param i + * @return + */ + public static String groupTicketName(String group, int i) { + return group+'['+i+']'; + } + private static class PassFrameBuffer { public final FrameBuffer frameBuffer; @@ -806,5 +810,51 @@ public void dispose() { } } + private static class TicketGroup { + + public final String name; + public ResourceTicket[] array; + public boolean indefinite = false; + + public TicketGroup(String name) { + this.name = name; + this.indefinite = true; + } + public TicketGroup(String name, ResourceTicket... array) { + this.name = name; + this.array = array; + } + + public ResourceTicket add() { + if (!indefinite) { + throw new IllegalStateException("Group must be indefinite to alter ticket array."); + } + ResourceTicket[] temp = new ResourceTicket[array.length+1]; + System.arraycopy(array, 0, temp, 0, array.length); + array = temp; + return (array[array.length-1] = new ResourceTicket<>(groupTicketName(name, array.length-1), name)); + } + public int remove(ResourceTicket t) { + if (!indefinite) { + throw new IllegalStateException("Group must be indefinite to alter ticket array."); + } + int i = array.length-1; + for (; i >= 0; i--) { + if (array[i] == t) break; + } + if (i >= 0) { + ResourceTicket[] temp = new ResourceTicket[array.length-1]; + if (i > 0) { + System.arraycopy(array, 0, temp, 0, i); + } + if (i < array.length-1) { + System.arraycopy(array, i+1, temp, i, array.length-i-1); + } + array = temp; + } + return i; + } + + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java new file mode 100644 index 0000000000..79e321ca7a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java @@ -0,0 +1,151 @@ +/* + * 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.passes; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.renderer.Camera; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.queue.GeometryComparator; +import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.GuiComparator; +import com.jme3.renderer.queue.NullComparator; +import com.jme3.renderer.queue.OpaqueComparator; +import com.jme3.renderer.queue.RenderQueue; +import static com.jme3.renderer.queue.RenderQueue.Bucket.Opaque; +import com.jme3.renderer.queue.TransparentComparator; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import java.io.IOException; +import java.util.List; + +/** + * + * @author codex + */ +public class SceneEnqueuePass extends RenderPass { + + private final Bucket[] buckets = { + new Bucket("Opaque", new OpaqueComparator()), + new Bucket("Gui", new GuiComparator()), + new Bucket("Transparent", new TransparentComparator()), + new Bucket("Translucent", new TransparentComparator()), + new Bucket("Sky", new NullComparator()), + }; + + private boolean runControlRender = true; + + public SceneEnqueuePass() {} + public SceneEnqueuePass(boolean runControlRender) { + this.runControlRender = runControlRender; + } + + @Override + protected void initialize(FrameGraph frameGraph) { + for (Bucket b : buckets) { + b.ticket = addOutput(b.name); + } + } + @Override + protected void prepare(FGRenderContext context) { + for (Bucket b : buckets) { + declare(null, b.ticket); + } + } + @Override + protected void execute(FGRenderContext context) { + ViewPort vp = context.getViewPort(); + List scenes = vp.getScenes(); + for (int i = scenes.size(); i >= 0; i--) { + vp.getCamera().setPlaneState(0); + queueSubScene(context, scenes.get(i), null); + } + for (Bucket b : buckets) { + resources.setPrimitive(b.ticket, b.queue); + } + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + out.write(runControlRender, "runControlRender", true); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + runControlRender = in.readBoolean("runControlRender", true); + } + + private void queueSubScene(FGRenderContext context, Spatial scene, RenderQueue.Bucket parentBucket) { + // check culling + Camera cam = context.getViewPort().getCamera(); + if (!scene.checkCulling(cam)) { + return; + } + // render controls + if (runControlRender) { + scene.runControlRender(context.getRenderManager(), context.getViewPort()); + } + // get target bucket + RenderQueue.Bucket b = scene.getLocalQueueBucket(); + if (b == RenderQueue.Bucket.Inherit) { + b = parentBucket; + if (b == null) { + b = scene.getQueueBucket(); + } + } + if (scene instanceof Node) { + Node n = (Node)scene; + int camState = cam.getPlaneState(); + for (Spatial s : n.getChildren()) { + // restore cam state before queueing children + cam.setPlaneState(camState); + queueSubScene(context, s, b); + } + } else if (scene instanceof Geometry) { + // add to the render queue + Geometry g = (Geometry)scene; + if (g.getMaterial() == null) { + throw new IllegalStateException("No material is set for Geometry: " + g.getName()); + } + getBucket(b).queue.add(g); + } + } + private Bucket getBucket(RenderQueue.Bucket bucket) { + switch (bucket) { + case Opaque: return buckets[0]; + case Gui: return buckets[1]; + case Transparent: return buckets[2]; + case Translucent: return buckets[3]; + case Sky: return buckets[4]; + default: throw new IllegalArgumentException(bucket+" does not have a corresponding geometry list."); + } + } + + private static class Bucket { + + public final String name; + public final GeometryList queue; + public ResourceTicket ticket; + + public Bucket(String name, GeometryComparator comparator) { + this.name = name; + this.queue = new GeometryList(comparator); + } + + } + +} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index cfd4bb4262..9faa09c8be 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -55,7 +55,7 @@ import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.renderer.framegraph.debug.GraphEventCapture; -import com.jme3.renderer.framegraph.client.GraphClient; +import com.jme3.renderer.framegraph.client.GraphSetting; import com.jme3.renderer.framegraph.passes.Junction; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; @@ -676,7 +676,7 @@ public void simpleInitApp() { //renderManager.setFrameGraph(forward); Junction lightingMethod = deferred.get(Junction.class, "LightPackMethod"); - lightingMethod.setIndexSource(vp -> 0); + lightingMethod.setIndexSource((fg, vp) -> 0); File capTarget = new File(System.getProperty("user.home")+"/earlyFrameCapture.txt"); GraphEventCapture cap = new GraphEventCapture(capTarget); From a62b144e3499bac1d6fe91edea73c5687f333d32 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:12:49 -0400 Subject: [PATCH 089/111] finalized ticket lists --- .../framegraph/passes/DeferredPass.java | 4 +- .../framegraph/passes/RenderPass.java | 140 ++++++++++++++---- 2 files changed, 112 insertions(+), 32 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 437832475f..1d2faf89d7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -147,7 +147,7 @@ protected void execute(FGRenderContext context) { } material.selectTechnique("DeferredPass", context.getRenderManager()); material.getActiveTechnique().getDef().setLogic(this); - acquireGroupOrElse("LightTextures", lightTextures, null); + acquireArrayOrElse("LightTextures", lightTextures, null); if (lightTextures[0] == null) { context.getScreen().render(context.getRenderManager(), material, resources.acquire(lights)); } else { @@ -155,7 +155,7 @@ protected void execute(FGRenderContext context) { material.setTexture("LightTex"+i, lightTextures[i-1]); } // get textures used for screenspace light tiling - acquireGroupOrElse("TileTextures", tileTextures, null); + acquireArrayOrElse("TileTextures", tileTextures, null); if (tileTextures[0] != null) { material.setTexture("m_Tiles", tileTextures[0]); material.setTexture("m_LightIndex", tileTextures[1]); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 3bf00e77fc..17264b6d66 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -45,10 +45,10 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.Objects; /** @@ -58,6 +58,7 @@ */ public abstract class RenderPass implements ResourceProducer, Savable { + private static final String LIST_PREFIX = "#ElementOfList:"; private static int nextId = 0; private int id = nextId++; @@ -292,7 +293,7 @@ protected void referenceOptional(ResourceTicket... tickets) { * @param array * @return */ - protected T[] acquireGroup(String name, T[] array) { + protected T[] acquireArray(String name, T[] array) { ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); int n = Math.min(array.length, tickets.length); for (int i = 0; i < n; i++) { @@ -312,7 +313,7 @@ protected T[] acquireGroup(String name, T[] array) { * @param val * @return */ - protected T[] acquireGroupOrElse(String name, T[] array, T val) { + protected T[] acquireArrayOrElse(String name, T[] array, T val) { ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); int n = Math.min(array.length, tickets.length); for (int i = 0; i < n; i++) { @@ -320,6 +321,26 @@ protected T[] acquireGroupOrElse(String name, T[] array, T val) { } return array; } + /** + * Acquires a list of resources from a ticket group and stores them in the given list. + * + * @param + * @param name group name + * @param list list to store resources in (or null to create a new {@link LinkedList}). + * @return given list + */ + protected List acquireList(String name, List list) { + if (list == null) { + list = new LinkedList<>(); + } + ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); + for (ResourceTicket t : tickets) { + T res = resources.acquireOrElse(t, null); + if (res != null) list.add(res); + } + return list; + } + /** * Releases all reasources associated with any registered ticket. *

      @@ -341,7 +362,7 @@ protected void releaseAll() { * @param input * @return given ticket */ - protected ResourceTicket addInput(ResourceTicket input) { + private ResourceTicket addInput(ResourceTicket input) { inputs.add(input); input.setPassId(id); return input; @@ -353,7 +374,7 @@ protected ResourceTicket addInput(ResourceTicket input) { * @param output * @return given ticket */ - protected ResourceTicket addOutput(ResourceTicket output) { + private ResourceTicket addOutput(ResourceTicket output) { outputs.add(output); output.setPassId(id); return output; @@ -366,6 +387,7 @@ protected ResourceTicket addOutput(ResourceTicket output) { * @return created ticket */ protected ResourceTicket addInput(String name) { + validateUserTicketName(name); return addInput(new ResourceTicket<>(name)); } /** @@ -376,6 +398,7 @@ protected ResourceTicket addInput(String name) { * @return created ticket */ protected ResourceTicket addOutput(String name) { + validateUserTicketName(name); return addOutput(new ResourceTicket<>(name)); } /** @@ -389,12 +412,13 @@ protected ResourceTicket addOutput(String name) { * @return created ticket array */ protected ResourceTicket[] addInputGroup(String name, int length) { - ResourceTicket[] array = new ResourceTicket[length]; + validateUserTicketName(name); + TicketGroup group = new TicketGroup(name, length); for (int i = 0; i < length; i++) { - addInput(array[i] = new ResourceTicket<>(groupTicketName(name, i), name)); + group.array[i] = addInput(group.create(i)); } - groups.put(name, new TicketGroup(name, array)); - return array; + groups.put(name, group); + return group.array; } /** * Creates and adds a ticket array as a group output of the specified length under the given name. @@ -407,22 +431,30 @@ protected ResourceTicket[] addInputGroup(String name, int length) { * @return create ticket array */ protected ResourceTicket[] addOutputGroup(String name, int length) { - ResourceTicket[] array = new ResourceTicket[length]; + validateUserTicketName(name); + TicketGroup group = new TicketGroup(name, length); for (int i = 0; i < length; i++) { - addOutput(array[i] = new ResourceTicket<>(groupTicketName(name, i), name)); + group.array[i] = addOutput(group.create(i)); } - groups.put(name, new TicketGroup(name, array)); - return array; + groups.put(name, group); + return group.array; } /** * Creates an input group of indefinite size. * * @param name */ - protected void addInputGroup(String name) { + protected void addInputList(String name) { + validateUserTicketName(name); groups.put(name, new TicketGroup(name)); } + private void validateUserTicketName(String name) { + if (name.startsWith("#")) { + throw new IllegalArgumentException("Cannot start ticket name with reserved '#' symbol."); + } + } + /** * Removes all members of the named group from the input and output lists. * @@ -438,6 +470,7 @@ protected ResourceTicket[] removeGroup(String name) { // Once we determine which list group members were added to, we only // need to remove from that list for future members. byte state = 0; + if (group.list) state = 1; for (ResourceTicket t : group.array) { if (state >= 0 && inputs.remove(t)) { state = 1; @@ -534,8 +567,16 @@ public void makeGroupInput(RenderPass sourcePass, String sourceGroup, String tar */ public void makeInput(RenderPass sourcePass, String sourceTicket, String targetTicket) { ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); - ResourceTicket target = Objects.requireNonNull(getInput(targetTicket), "Target ticket cannot be null."); - target.setSource(source); + if (targetTicket.startsWith(LIST_PREFIX)) { + TicketGroup g = Objects.requireNonNull(groups.get(targetTicket.substring(LIST_PREFIX.length())), "List group cannot be null."); + if (!g.list) { + throw new IllegalStateException("Group must be a list."); + } + g.add().setSource(source); + } else { + ResourceTicket target = Objects.requireNonNull(getInput(targetTicket), "Target ticket cannot be null."); + target.setSource(source); + } } /** * Adds the indicated source ticket as an input to the target indefinite group. @@ -544,14 +585,34 @@ public void makeInput(RenderPass sourcePass, String sourceTicket, String targetT * @param sourceTicket * @param targetGroup */ - public void addInputToGroup(RenderPass sourcePass, String sourceTicket, String targetGroup) { + public void makeInputToList(RenderPass sourcePass, String sourceTicket, String targetGroup) { ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); TicketGroup target = Objects.requireNonNull(groups.get(targetGroup), "Target group cannot be null."); - if (!target.indefinite) { + if (!target.list) { throw new IllegalStateException("Target group must be indefinite."); } target.add().setSource(source); } + + /** + * Disconnects all input tickets in this pass that have the given ticket as + * their source. + * + * @param ticket + */ + public void disconnectInputsFrom(ResourceTicket ticket) { + for (ResourceTicket in : inputs) { + if (in.getSource() == ticket) { + in.setSource(null); + if (in.getGroupName() != null) { + TicketGroup g = groups.get(in.getGroupName()); + if (g != null && g.list) { + g.remove(in); + } + } + } + } + } /** * Nullifies all sources belonging to the given pass. * @@ -563,7 +624,7 @@ public void disconnectInputsFrom(RenderPass pass) { in.setSource(null); if (in.getGroupName() != null) { TicketGroup g = groups.get(in.getGroupName()); - if (g != null && g.indefinite) { + if (g != null && g.list) { g.remove(in); } } @@ -784,6 +845,15 @@ public static int getNextId() { public static String groupTicketName(String group, int i) { return group+'['+i+']'; } + /** + * + * @param group + * @param i + * @return + */ + public static String listTicketName(String group) { + return LIST_PREFIX+group; + } private static class PassFrameBuffer { @@ -814,30 +884,34 @@ private static class TicketGroup { public final String name; public ResourceTicket[] array; - public boolean indefinite = false; + public boolean list = false; public TicketGroup(String name) { this.name = name; - this.indefinite = true; + this.array = new ResourceTicket[0]; + this.list = true; } - public TicketGroup(String name, ResourceTicket... array) { + public TicketGroup(String name, int length) { this.name = name; - this.array = array; + this.array = new ResourceTicket[length]; + } + + public ResourceTicket create(int i) { + return new ResourceTicket<>(groupTicketName(name, i), name); + } + private ResourceTicket create() { + return new ResourceTicket<>(listTicketName(name), name); } public ResourceTicket add() { - if (!indefinite) { - throw new IllegalStateException("Group must be indefinite to alter ticket array."); - } + requireAsList(); ResourceTicket[] temp = new ResourceTicket[array.length+1]; System.arraycopy(array, 0, temp, 0, array.length); array = temp; - return (array[array.length-1] = new ResourceTicket<>(groupTicketName(name, array.length-1), name)); + return (array[array.length-1] = create()); } public int remove(ResourceTicket t) { - if (!indefinite) { - throw new IllegalStateException("Group must be indefinite to alter ticket array."); - } + requireAsList(); int i = array.length-1; for (; i >= 0; i--) { if (array[i] == t) break; @@ -855,6 +929,12 @@ public int remove(ResourceTicket t) { return i; } + private void requireAsList() { + if (!list) { + throw new IllegalStateException("Group must be a list to alter ticket array."); + } + } + } } From 39d659830a78cccb9125122a5daba73156e3f43b Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:37:06 -0400 Subject: [PATCH 090/111] porting filters --- .../src/main/java/com/jme3/post/Filter.java | 64 ++++- .../jme3/renderer/GeometryRenderHandler.java | 5 + .../java/com/jme3/renderer/RenderManager.java | 19 +- .../renderer/framegraph/FGRenderContext.java | 24 ++ .../framegraph/FrameGraphFactory.java | 35 ++- .../renderer/framegraph/FullScreenQuad.java | 6 + .../framegraph/passes/FilterPass.java | 15 ++ .../framegraph/passes/GBufferPass.java | 7 +- .../renderer/framegraph/passes/Junction.java | 2 +- .../framegraph/passes/LegacyFilterPass.java | 142 ++++++++++ ...tBucketPass.java => OutputRenderPass.java} | 48 ++-- ...ass.java => PostProcessingRenderPass.java} | 4 +- .../framegraph/passes/RenderPass.java | 8 + .../com/jme3/renderer/queue/GeometryList.java | 38 ++- .../jme3/post/filters/DepthOfFieldFilter.java | 22 -- .../jme3/post/framegraph/CartoonEdgePass.java | 253 ++++++++++++++++++ .../post/framegraph/DepthOfFieldPass.java | 217 +++++++++++++++ 17 files changed, 822 insertions(+), 87 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/FilterPass.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LegacyFilterPass.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/{OutputBucketPass.java => OutputRenderPass.java} (75%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/{PostProcessingPass.java => PostProcessingRenderPass.java} (98%) create mode 100644 jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java create mode 100644 jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java diff --git a/jme3-core/src/main/java/com/jme3/post/Filter.java b/jme3-core/src/main/java/com/jme3/post/Filter.java index efdb19b04a..dc71f0deae 100644 --- a/jme3-core/src/main/java/com/jme3/post/Filter.java +++ b/jme3-core/src/main/java/com/jme3/post/Filter.java @@ -248,7 +248,7 @@ protected Filter() { * @param w the width * @param h the height */ - protected final void init(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { + public final void init(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { // cleanup(renderManager.getRenderer()); defaultPass = new Pass(); defaultPass.init(renderManager.getRenderer(), w, h, getDefaultPassTextureFormat(), getDefaultPassDepthFormat()); @@ -260,7 +260,7 @@ protected final void init(AssetManager manager, RenderManager renderManager, Vie * * @param r the Renderer */ - protected final void cleanup(Renderer r) { + public final void cleanup(Renderer r) { processor = null; if (defaultPass != null) { defaultPass.cleanup(r); @@ -301,6 +301,15 @@ protected void cleanUpFilter(Renderer r) { */ protected abstract Material getMaterial(); + /** + * Public mirror of {@link #getMaterial()}. + * + * @return + */ + public Material getPassMaterial() { + return getMaterial(); + } + /** * Override if you want to do something special with the depth texture; * @@ -326,7 +335,16 @@ protected void postQueue(RenderQueue queue) { */ protected void preFrame(float tpf) { } - + + /** + * Public mirror of {@link #preFrame(float)}. + * + * @param tpf + */ + public void filterPreFrame(float tpf) { + + } + /** * Override this method if you want to make a pass just after the frame has been rendered and just before the filter rendering * @@ -445,11 +463,38 @@ protected boolean isRequiresBilinear() { return false; } + /** + * Returns true if this filter can be used by framegraph passes. + * + * @return + */ + public boolean isFrameGraphCompatible() { + return false; + } + + /** + * Public mirror of {@link #isRequiresSceneTexture()} + * + * @return + */ + public boolean isReqSceneTex() { + return isRequiresSceneTexture(); + } + + /** + * Public mirror of {@link #isRequiresDepthTexture()} + * + * @return + */ + public boolean isReqDepthTex() { + return isRequiresDepthTexture(); + } + /** * returns the list of the postRender passes * @return the pre-existing List */ - protected List getPostRenderPasses() { + public List getPostRenderPasses() { return postRenderPasses; } @@ -492,4 +537,15 @@ protected void setProcessor(FilterPostProcessor proc) { */ protected void postFilter(Renderer r, FrameBuffer buffer){ } + + /** + * Public mirror of {@link #postFilter(com.jme3.renderer.Renderer, com.jme3.texture.FrameBuffer)} + * + * @param r + * @param buffer + */ + public void filterPostRender(Renderer r, FrameBuffer buffer) { + postFilter(r, buffer); + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java b/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java index 21e57d1237..c1f35b8cea 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java +++ b/jme3-core/src/main/java/com/jme3/renderer/GeometryRenderHandler.java @@ -40,6 +40,11 @@ */ public interface GeometryRenderHandler { + public static final GeometryRenderHandler DEFAULT = (rm, geom) -> { + rm.renderGeometry(geom); + return true; + }; + /** * Renders the given geometry, or returns false. * 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 f6132bf919..d22cbdf47e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -1326,7 +1326,13 @@ public void renderViewPort(ViewPort vp, float tpf) { renderer.clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); } - if (fg == null) { + if (fg != null) { + // returns true on first execution this frame + if (fg.execute()) { + executedFrameGraphs.add(fg); + } + } else { + if (prof != null) { prof.vpStep(VpStep.RenderScene, vp, null); } @@ -1346,15 +1352,7 @@ public void renderViewPort(ViewPort vp, float tpf) { p.postQueue(vp.getQueue()); } } - } - - if (fg != null) { - // returns true on first execution this frame - if (fg.execute()) { - executedFrameGraphs.add(fg); - } - } else { - + if (prof != null) { prof.vpStep(VpStep.FlushQueue, vp, null); } @@ -1383,6 +1381,7 @@ public void renderViewPort(ViewPort vp, float tpf) { } + // clear all reservations made if (fg != null) { renderObjects.clearReservations(); } 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 2618a04b56..73eb61542f 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 @@ -36,6 +36,7 @@ import com.jme3.opencl.CommandQueue; import com.jme3.opencl.Context; import com.jme3.profile.AppProfiler; +import com.jme3.renderer.Camera; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.ViewPort; @@ -46,6 +47,7 @@ import com.jme3.texture.Texture2D; import java.util.function.Predicate; import com.jme3.renderer.GeometryRenderHandler; +import com.jme3.renderer.queue.GeometryList; /** * Contains necessary context for framegraph rendering. @@ -149,6 +151,28 @@ public void popFrameBuffer() { public void renderViewPortQueue(RenderQueue.Bucket bucket, boolean clear) { viewPort.getQueue().renderQueue(bucket, renderManager, viewPort.getCamera(), clear); } + /** + * Renders the given geometry list with the camera and render handler. + * + * @param list list of geometry to render (not null) + * @param cam camera to render with (or null to render with the current viewport camera) + * @param handler handler to render with (or null to render with {@link GeometryRenderHandler#DEFAULT}) + */ + public void renderGeometryList(GeometryList list, Camera cam, GeometryRenderHandler handler) { + if (cam == null) { + cam = viewPort.getCamera(); + } + if (handler == null) { + handler = GeometryRenderHandler.DEFAULT; + } + list.setCamera(cam); + list.sort(); + for (Geometry g : list) { + assert g != null; + handler.renderGeometry(renderManager, g); + g.queueDistance = Float.NEGATIVE_INFINITY; + } + } /** * Renders the material on a fullscreen quad. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 14f267c9bc..8fa1b717a6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -39,9 +39,10 @@ import com.jme3.renderer.framegraph.passes.GBufferPass; import com.jme3.renderer.framegraph.passes.Junction; import com.jme3.renderer.framegraph.passes.LightImagePass; -import com.jme3.renderer.framegraph.passes.OutputBucketPass; +import com.jme3.renderer.framegraph.passes.OutputRenderPass; import com.jme3.renderer.framegraph.passes.OutputPass; -import com.jme3.renderer.framegraph.passes.PostProcessingPass; +import com.jme3.renderer.framegraph.passes.PostProcessingRenderPass; +import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; import com.jme3.renderer.queue.RenderQueue; /** @@ -62,12 +63,12 @@ public static FrameGraph forward(AssetManager assetManager) { FrameGraph fg = new FrameGraph(assetManager); fg.setName("Forward"); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Opaque)); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); - fg.add(new PostProcessingPass()); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); + fg.add(new OutputRenderPass(RenderQueue.Bucket.Opaque)); + fg.add(new OutputRenderPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); + fg.add(new OutputRenderPass(RenderQueue.Bucket.Transparent)); + fg.add(new OutputRenderPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); + fg.add(new PostProcessingRenderPass()); + fg.add(new OutputRenderPass(RenderQueue.Bucket.Translucent)); return fg; @@ -85,6 +86,7 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { FrameGraph fg = new FrameGraph(assetManager); fg.setName(tiled ? "TiledDeferred" : "Deferred"); + SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass()); GBufferPass gbuf = fg.add(new GBufferPass()); Attribute tileInfoAttr = fg.add(new Attribute()); Junction tileJunct1 = fg.add(new Junction(1, 1)); @@ -93,11 +95,13 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { Junction tileJunct2 = fg.add(new Junction(1, 2)); DeferredPass deferred = fg.add(new DeferredPass()); OutputPass defOut = fg.add(new OutputPass(0f)); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Transparent)); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); - fg.add(new PostProcessingPass()); - fg.add(new OutputBucketPass(RenderQueue.Bucket.Translucent)); + OutputRenderPass sky = fg.add(new OutputRenderPass(DepthRange.REAR)); + OutputRenderPass transparent = fg.add(new OutputRenderPass()); + OutputRenderPass gui = fg.add(new OutputRenderPass(DepthRange.FRONT, false)); + fg.add(new PostProcessingRenderPass()); + OutputRenderPass translucent = fg.add(new OutputRenderPass()); + + gbuf.makeInput(enqueue, "Opaque", "Geometry"); GraphSetting tileInfo = fg.setSetting("TileInfo", new TiledRenderGrid(), true); tileInfoAttr.setName("TileInfo"); @@ -132,6 +136,11 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { defOut.makeInput(deferred, "Color", "Color"); defOut.makeInput(gbuf, "GBufferData[4]", "Depth"); + sky.makeInput(enqueue, "Sky", "Geometry"); + transparent.makeInput(enqueue, "Transparent", "Geometry"); + gui.makeInput(enqueue, "Gui", "Geometry"); + translucent.makeInput(enqueue, "Translucent", "Geometry"); + return fg; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java index 831d5ae247..e467260f7d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java @@ -67,6 +67,12 @@ public FullScreenQuad(AssetManager assetManager) { 0, 1, 2, 1, 3, 2 )); + mesh.setBuffer(VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer( + 1, 0, + 1, 1, + 0, 0, + 0, 1 + )); mesh.updateBound(); mesh.updateCounts(); mesh.setStatic(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/FilterPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/FilterPass.java new file mode 100644 index 0000000000..164cbe2fe5 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/FilterPass.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.passes; + +/** + * + * @author codex + */ +public abstract class FilterPass extends RenderPass { + + + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 37d1a2c720..3f5ffab461 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -45,11 +45,11 @@ import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; -import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; import java.util.LinkedList; import java.util.function.Function; import com.jme3.renderer.GeometryRenderHandler; +import com.jme3.renderer.queue.GeometryList; /** * Renders diffuse, specular, emissive, normal, and depth information to a set of @@ -63,6 +63,7 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private final static String GBUFFER_PASS = "GBufferPass"; + private ResourceTicket geometry; private ResourceTicket[] gbuffers; private ResourceTicket lights; private ResourceTicket numRendersTicket; @@ -73,6 +74,7 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { @Override protected void initialize(FrameGraph frameGraph) { + geometry = addInput("Geometry"); gbuffers = addOutputGroup("GBufferData", 5); lights = addOutput("Lights"); numRendersTicket = addOutput("NumRenders"); @@ -95,6 +97,7 @@ protected void prepare(FGRenderContext context) { declare(lightDef, lights); declare(null, numRendersTicket); reserve(gbuffers); + reference(geometry); numRenders = 0; } @Override @@ -111,7 +114,7 @@ protected void execute(FGRenderContext context) { context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); context.getRenderManager().setForcedTechnique(GBUFFER_PASS); context.getRenderManager().setGeometryRenderHandler(this); - context.renderViewPortQueue(RenderQueue.Bucket.Opaque, true); + context.renderGeometryList(resources.acquire(geometry), null, this); // add accumulated lights while (!accumulatedLights.isEmpty()) { lightList.add(accumulatedLights.pollFirst()); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index d632ff624d..4dd77ac2ca 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -92,7 +92,7 @@ protected void initialize(FrameGraph frameGraph) { protected void prepare(FGRenderContext context) { int size; if (groupSize > 1) { - size = getGroups().size()-1; + size = getNumGroups()-1; } else { size = getInputTickets().size()-EXTRA_INPUTS; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LegacyFilterPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LegacyFilterPass.java new file mode 100644 index 0000000000..8ea7feb5fd --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LegacyFilterPass.java @@ -0,0 +1,142 @@ +/* + * 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.passes; + +import com.jme3.export.JmeExporter; +import com.jme3.export.OutputCapsule; +import com.jme3.material.Material; +import com.jme3.post.Filter; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.client.GraphSource; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +/** + * FrameGraph adapter for traditional filters. + * + * @author codex + */ +public class LegacyFilterPass extends RenderPass { + + private ResourceTicket inColor, inDepth, outColor; + private TextureDef texDef = TextureDef.texture2D(); + private final HashMap filters = new HashMap<>(); + private GraphSource source; + + @Override + protected void initialize(FrameGraph frameGraph) { + inColor = addInput("Color"); + inDepth = addInput("Depth"); + } + @Override + protected void prepare(FGRenderContext context) { + declare(texDef, outColor); + reference(inColor, inDepth); + } + @Override + protected void execute(FGRenderContext context) { + PassFilter f = filters.get(context.getViewPort()); + if (f == null) { + f = new PassFilter(source.getGraphValue(frameGraph, context.getViewPort())); + f.filter.init(frameGraph.getAssetManager(), context.getRenderManager(), context.getViewPort(), 0, 0); + filters.put(context.getViewPort(), f); + } + f.used = true; + Texture2D colorTex = resources.acquire(inColor); + Texture2D depthTex = resources.acquire(inDepth); + FrameBuffer fb = getFrameBuffer(context, 1); + resources.acquireColorTarget(fb, outColor); + if (f.filter.isEnabled()) { + f.filter.filterPreFrame(context.getTpf()); + List passes = f.filter.getPostRenderPasses(); + if (passes != null) for (Filter.Pass p : passes) { + p.beforeRender(); + Material mat = p.getPassMaterial(); + if (p.requiresSceneAsTexture()) { + applyTexture(mat, colorTex, "Texture", "NumSamples"); + } + if (p.requiresDepthAsTexture()) { + applyTexture(mat, depthTex, "DepthTexture", "NumSamplesDepth"); + } + context.getRenderer().setFrameBuffer(p.getRenderFrameBuffer()); + context.getRenderer().clearBuffers(true, true, true); + context.renderFullscreen(p.getPassMaterial()); + } + Material mat = f.filter.getPassMaterial(); + if (f.filter.isReqSceneTex()) { + applyTexture(mat, colorTex, "Texture", "NumSamples"); + } + if (f.filter.isReqDepthTex()) { + applyTexture(mat, depthTex, "DepthTexture", "NumSamplesDepth"); + } + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + context.renderFullscreen(mat); + f.filter.filterPostRender(context.getRenderer(), fb); + } + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + public void renderingComplete() { + super.renderingComplete(); + for (Iterator it = filters.values().iterator(); it.hasNext();) { + PassFilter f = it.next(); + if (!f.used) { + f.filter.cleanup(frameGraph.getRenderManager().getRenderer()); + it.remove(); + } else { + f.used = false; + } + } + } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + } + + private void applyTexture(Material mat, Texture tex, String texParam, String msParam) { + mat.setTexture(texParam, tex); + if (tex.getImage().getMultiSamples() > 1) { + mat.setInt(msParam, tex.getImage().getMultiSamples()); + } else { + mat.clearParam(msParam); + } + } + + public Filter getFilter(ViewPort vp) { + PassFilter f = filters.get(vp); + if (f != null) { + return f.filter; + } else { + return null; + } + } + + private static class PassFilter { + + public final Filter filter; + public int width = -1; + public int height = -1; + public boolean used = true; + + public PassFilter(Filter filter) { + this.filter = filter; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java similarity index 75% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java index b08a7ea421..cac053dfcf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputBucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java @@ -35,9 +35,12 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; +import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue.Bucket; import java.io.IOException; @@ -46,39 +49,42 @@ * * @author codex */ -public class OutputBucketPass extends RenderPass { +public class OutputRenderPass extends RenderPass { - private Bucket bucket; + private ResourceTicket geometry; private DepthRange depth; + private boolean perspective = true; - public OutputBucketPass() { - this(Bucket.Opaque, DepthRange.IDENTITY); + public OutputRenderPass() { + this(DepthRange.IDENTITY, true); } - public OutputBucketPass(Bucket bucket) { - this(bucket, DepthRange.IDENTITY); + public OutputRenderPass(DepthRange range) { + this(range, true); } - public OutputBucketPass(Bucket bucket, DepthRange depth) { - this.bucket = bucket; + public OutputRenderPass(DepthRange depth, boolean perspective) { this.depth = depth; - if (this.bucket == Bucket.Inherit) { - throw new IllegalArgumentException("Rendered bucket cannot be Inherit."); - } + this.perspective = perspective; } @Override - protected void initialize(FrameGraph frameGraph) {} + protected void initialize(FrameGraph frameGraph) { + geometry = addInput("Geometry"); + } @Override - protected void prepare(FGRenderContext context) {} + protected void prepare(FGRenderContext context) { + reference(geometry); + } @Override protected void execute(FGRenderContext context) { context.popFrameBuffer(); - if (bucket == Bucket.Gui) { + if (!perspective) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); } context.getRenderer().setDepthRange(depth); - context.renderViewPortQueue(bucket, true); - if (bucket == Bucket.Gui) { + //context.renderViewPortQueue(bucket, true); + context.renderGeometryList(resources.acquire(geometry), null, null); + if (!perspective) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); } } @@ -88,25 +94,21 @@ protected void reset(FGRenderContext context) {} protected void cleanup(FrameGraph frameGraph) {} @Override public boolean isUsed() { - return true; - } - @Override - public String getProfilerName() { - return super.getProfilerName()+"["+bucket+"]"; + return geometry.hasSource(); } @Override public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule out = ex.getCapsule(this); - out.write(bucket, "bucket", Bucket.Opaque); out.write(depth, "depth", DepthRange.IDENTITY); + out.write(perspective, "perspective", true); } @Override public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule in = im.getCapsule(this); - bucket = in.readEnum("bucket", Bucket.class, Bucket.Opaque); depth = in.readSavable("depth", DepthRange.class, DepthRange.IDENTITY); + perspective = in.readBoolean("perspective", true); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingRenderPass.java similarity index 98% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingRenderPass.java index 3475a2e847..1a432daa35 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingRenderPass.java @@ -46,7 +46,9 @@ * * @author codex */ -public class PostProcessingPass extends RenderPass { +public class PostProcessingRenderPass extends RenderPass { + + @Override protected void initialize(FrameGraph frameGraph) {} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 17264b6d66..7ddd19cd88 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -788,6 +788,14 @@ public int getIndex() { public boolean isAssigned() { return index >= 0; } + /** + * Gets the number of ticket groups. + * + * @return + */ + public int getNumGroups() { + return groups.size(); + } @Override public int getExecutionIndex() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java index 5836c87614..a974712ca1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java @@ -49,11 +49,13 @@ public class GeometryList implements Iterable{ private static final int DEFAULT_SIZE = 32; - + private Geometry[] geometries; final private ListSort listSort; private int size; private GeometryComparator comparator; + private Camera cam; + private boolean updateFlag = true; /** * Initializes the GeometryList to use the given {@link GeometryComparator} @@ -68,8 +70,18 @@ public GeometryList(GeometryComparator comparator) { listSort = new ListSort(); } + /** + * Marks this list as requiring sorting. + */ + public void setUpdateNeeded() { + updateFlag = true; + } + public void setComparator(GeometryComparator comparator) { - this.comparator = comparator; + if (this.comparator != comparator) { + this.comparator = comparator; + updateFlag = true; + } } /** @@ -89,7 +101,11 @@ public GeometryComparator getComparator() { * @param cam Camera to use for sorting. */ public void setCamera(Camera cam) { - this.comparator.setCamera(cam); + if (this.cam != cam) { + this.cam = cam; + comparator.setCamera(this.cam); + updateFlag = true; + } } /** @@ -97,7 +113,7 @@ public void setCamera(Camera cam) { * * @return Number of elements in the list */ - public int size(){ + public int size() { return size; } @@ -109,6 +125,7 @@ public int size(){ */ public void set(int index, Geometry value) { geometries[index] = value; + updateFlag = true; } /** @@ -135,6 +152,7 @@ public void add(Geometry g) { geometries = temp; // original list replaced by double-size list } geometries[size++] = g; + updateFlag = true; } /** @@ -144,7 +162,7 @@ public void clear() { for (int i = 0; i < size; i++) { geometries[i] = null; } - + updateFlag = true; size = 0; } @@ -153,12 +171,13 @@ public void clear() { */ @SuppressWarnings("unchecked") public void sort() { - if (size > 1) { + if (updateFlag && size > 1) { // sort the spatial list using the comparator if (listSort.getLength() != size) { listSort.allocateStack(size); } - listSort.sort(geometries,comparator); + listSort.sort(geometries, comparator); + updateFlag = false; } } @@ -166,13 +185,10 @@ public void sort() { public Iterator iterator() { return new Iterator() { int index = 0; - @Override public boolean hasNext() { return index < size(); } - - @Override public Geometry next() { if (index >= size()) { @@ -180,11 +196,11 @@ public Geometry next() { } return get(index++); } - @Override public void remove() { throw new UnsupportedOperationException("Geometry list doesn't support iterator removal"); } }; } + } \ No newline at end of file diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java index e8f5029c37..b4de8ce3e5 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java @@ -221,26 +221,4 @@ public void setDebugUnfocus( boolean b ) { public boolean getDebugUnfocus() { return debugUnfocus; } - - @Override - public void write(JmeExporter ex) throws IOException { - super.write(ex); - OutputCapsule oc = ex.getCapsule(this); - oc.write(blurScale, "blurScale", 1f); - oc.write(blurThreshold, "blurThreshold", 0.2f); - oc.write(focusDistance, "focusDistance", 50f); - oc.write(focusRange, "focusRange", 10f); - oc.write(debugUnfocus, "debugUnfocus", false); // strange to write this I guess - } - - @Override - public void read(JmeImporter im) throws IOException { - super.read(im); - InputCapsule ic = im.getCapsule(this); - blurScale = ic.readFloat("blurScale", 1f); - blurThreshold = ic.readFloat("blurThreshold", 0.2f); - focusDistance = ic.readFloat("focusDistance", 50f); - focusRange = ic.readFloat("focusRange", 10f); - debugUnfocus = ic.readBoolean("debugUnfocus", false); - } } diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java new file mode 100644 index 0000000000..40c0ebad56 --- /dev/null +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java @@ -0,0 +1,253 @@ +/* + * 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.post.framegraph; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.renderer.framegraph.passes.RenderPass; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture2D; +import java.io.IOException; + +/** + * Adds cartoon edges to the scene. + * + * @author codex + */ +public class CartoonEdgePass extends RenderPass { + + private ResourceTicket color, depth, normals; + private ResourceTicket result; + private final TextureDef texDef = TextureDef.texture2D(); + private Material material; + private float edgeWidth = 1.0f; + private float edgeIntensity = 1.0f; + private float normalThreshold = 0.5f; + private float depthThreshold = 0.1f; + private float normalSensitivity = 1.0f; + private float depthSensitivity = 10.0f; + private ColorRGBA edgeColor = new ColorRGBA(0, 0, 0, 1); + + @Override + protected void initialize(FrameGraph frameGraph) { + color = addInput("Color"); + depth = addInput("Depth"); + normals = addInput("Normals"); + result = addOutput("Color"); + material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/Post/CartoonEdge.j3md"); + material.setFloat("EdgeWidth", edgeWidth); + material.setFloat("EdgeIntensity", edgeIntensity); + material.setFloat("NormalThreshold", normalThreshold); + material.setFloat("DepthThreshold", depthThreshold); + material.setFloat("NormalSensitivity", normalSensitivity); + material.setFloat("DepthSensitivity", depthSensitivity); + material.setColor("EdgeColor", edgeColor); + } + @Override + protected void prepare(FGRenderContext context) { + declare(texDef, result); + reference(color, depth, normals); + texDef.setSize(context.getWidth(), context.getHeight()); + } + @Override + protected void execute(FGRenderContext context) { + FrameBuffer fb = getFrameBuffer(context, 1); + resources.acquireColorTarget(fb, result); + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + material.setTexture("Texture", resources.acquire(color)); + material.setTexture("DepthTexture", resources.acquire(depth)); + material.setTexture("NormalsTexture", resources.acquire(normals)); + context.renderFullscreen(material); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) { + material = null; + } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + oc.write(edgeWidth, "edgeWidth", 1.0f); + oc.write(edgeIntensity, "edgeIntensity", 1.0f); + oc.write(normalThreshold, "normalThreshold", 0.5f); + oc.write(depthThreshold, "depthThreshold", 0.1f); + oc.write(normalSensitivity, "normalSensitivity", 1.0f); + oc.write(depthSensitivity, "depthSensitivity", 10.0f); + oc.write(edgeColor, "edgeColor", ColorRGBA.Black); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule ic = im.getCapsule(this); + edgeWidth = ic.readFloat("edgeWidth", 1.0f); + edgeIntensity = ic.readFloat("edgeIntensity", 1.0f); + normalThreshold = ic.readFloat("normalThreshold", 0.5f); + depthThreshold = ic.readFloat("depthThreshold", 0.1f); + normalSensitivity = ic.readFloat("normalSensitivity", 1.0f); + depthSensitivity = ic.readFloat("depthSensitivity", 10.0f); + edgeColor = (ColorRGBA)ic.readSavable("edgeColor", ColorRGBA.Black.clone()); + } + + /** + * Return the depth sensitivity
      + * for more details see {@link #setDepthSensitivity(float depthSensitivity)} + * @return the depth sensitivity + */ + public float getDepthSensitivity() { + return depthSensitivity; + } + + /** + * sets the depth sensitivity
      + * defines how much depth will influence edges, default is 10 + * + * @param depthSensitivity the desired sensitivity (default=10) + */ + public void setDepthSensitivity(float depthSensitivity) { + this.depthSensitivity = depthSensitivity; + if (material != null) { + material.setFloat("DepthSensitivity", depthSensitivity); + } + } + + /** + * returns the depth threshold
      + * for more details see {@link #setDepthThreshold(float depthThreshold)} + * @return the threshold + */ + public float getDepthThreshold() { + return depthThreshold; + } + + /** + * sets the depth threshold
      + * Defines at what threshold of difference of depth an edge is outlined default is 0.1f + * + * @param depthThreshold the desired threshold (default=0.1) + */ + public void setDepthThreshold(float depthThreshold) { + this.depthThreshold = depthThreshold; + if (material != null) { + material.setFloat("DepthThreshold", depthThreshold); + } + } + + /** + * returns the edge intensity
      + * for more details see {@link #setEdgeIntensity(float edgeIntensity) } + * @return the intensity + */ + public float getEdgeIntensity() { + return edgeIntensity; + } + + /** + * sets the edge intensity
      + * Defines how visible the outlined edges will be + * + * @param edgeIntensity the desired intensity (default=1) + */ + public void setEdgeIntensity(float edgeIntensity) { + this.edgeIntensity = edgeIntensity; + if (material != null) { + material.setFloat("EdgeIntensity", edgeIntensity); + } + } + + /** + * returns the width of the edges + * @return the width + */ + public float getEdgeWidth() { + return edgeWidth; + } + + /** + * sets the width of the edge in pixels default is 1 + * + * @param edgeWidth the desired width (in pixels, default=1) + */ + public void setEdgeWidth(float edgeWidth) { + this.edgeWidth = edgeWidth; + if (material != null) { + material.setFloat("EdgeWidth", edgeWidth); + } + } + + /** + * returns the normals sensitivity
      + * form more details see {@link #setNormalSensitivity(float normalSensitivity)} + * @return the sensitivity + */ + public float getNormalSensitivity() { + return normalSensitivity; + } + + /** + * Sets the normals sensitivity. Default is 1. + * + * @param normalSensitivity the desired sensitivity (default=1) + */ + public void setNormalSensitivity(float normalSensitivity) { + this.normalSensitivity = normalSensitivity; + if (material != null) { + material.setFloat("NormalSensitivity", normalSensitivity); + } + } + + /** + * returns the normal threshold
      + * for more details see {@link #setNormalThreshold(float normalThreshold)} + * + * @return the threshold + */ + public float getNormalThreshold() { + return normalThreshold; + } + + /** + * sets the normal threshold default is 0.5 + * + * @param normalThreshold the desired threshold (default=0.5) + */ + public void setNormalThreshold(float normalThreshold) { + this.normalThreshold = normalThreshold; + if (material != null) { + material.setFloat("NormalThreshold", normalThreshold); + } + } + + /** + * returns the edge color + * @return the pre-existing instance + */ + public ColorRGBA getEdgeColor() { + return edgeColor; + } + + /** + * Sets the edge color, default is black + * + * @param edgeColor the desired color (alias created, default=(0,0,0,1)) + */ + public void setEdgeColor(ColorRGBA edgeColor) { + this.edgeColor = edgeColor; + if (material != null) { + material.setColor("EdgeColor", edgeColor); + } + } + +} diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java new file mode 100644 index 0000000000..d1be95d4e5 --- /dev/null +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java @@ -0,0 +1,217 @@ +/* + * 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.post.framegraph; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.material.Material; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.renderer.framegraph.passes.RenderPass; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture2D; +import java.io.IOException; + +/** + * + * @author codex + */ +public class DepthOfFieldPass extends RenderPass { + + private ResourceTicket color, depth; + private ResourceTicket result; + private final TextureDef texDef = TextureDef.texture2D(); + private Material material; + private float focusDistance = 50f; + private float focusRange = 10f; + private float blurScale = 1f; + private float blurThreshold = 0.2f; + private boolean debugUnfocus; + + @Override + protected void initialize(FrameGraph frameGraph) { + color = addInput("Color"); + depth = addInput("Depth"); + result = addOutput("Color"); + material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/Post/DepthOfField.j3md"); + material.setFloat("FocusDistance", focusDistance); + material.setFloat("FocusRange", focusRange); + material.setFloat("BlurThreshold", blurThreshold); + material.setBoolean("DebugUnfocus", debugUnfocus); + } + @Override + protected void prepare(FGRenderContext context) { + declare(texDef, result); + reference(color, depth); + texDef.setSize(context.getWidth(), context.getHeight()); + material.setFloat("XScale", blurScale/context.getWidth()); + material.setFloat("YScale", blurScale/context.getHeight()); + } + @Override + protected void execute(FGRenderContext context) { + FrameBuffer fb = getFrameBuffer(context, 1); + resources.acquireColorTarget(fb, result); + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + material.setTexture("Texture", resources.acquire(color)); + material.setTexture("DepthTexture", resources.acquire(depth)); + context.renderFullscreen(material); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + oc.write(blurScale, "blurScale", 1f); + oc.write(blurThreshold, "blurThreshold", 0.2f); + oc.write(focusDistance, "focusDistance", 50f); + oc.write(focusRange, "focusRange", 10f); + oc.write(debugUnfocus, "debugUnfocus", false); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule ic = im.getCapsule(this); + blurScale = ic.readFloat("blurScale", 1f); + blurThreshold = ic.readFloat("blurThreshold", 0.2f); + focusDistance = ic.readFloat("focusDistance", 50f); + focusRange = ic.readFloat("focusRange", 10f); + debugUnfocus = ic.readBoolean("debugUnfocus", false); + } + + /** + * Sets the distance at which objects are purely in focus. + * + * @param f the desired distance (in world units, default=50) + */ + public void setFocusDistance(float f) { + + this.focusDistance = f; + if (material != null) { + material.setFloat("FocusDistance", focusDistance); + } + + } + + /** + * returns the focus distance + * @return the distance + */ + public float getFocusDistance() { + return focusDistance; + } + + /** + * Sets the range to either side of focusDistance where the + * objects go gradually out of focus. Less than focusDistance - focusRange + * and greater than focusDistance + focusRange, objects are maximally "blurred". + * + * @param f the desired half extent (in world units, default=10) + */ + public void setFocusRange(float f) { + this.focusRange = f; + if (material != null) { + material.setFloat("FocusRange", focusRange); + } + + } + + /** + * returns the focus range + * @return the distance + */ + public float getFocusRange() { + return focusRange; + } + + /** + * Sets the blur amount by scaling the convolution filter up or + * down. A value of 1 (the default) performs a sparse 5x5 evenly + * distributed convolution at pixel level accuracy. Higher values skip + * more pixels, and so on until you are no longer blurring the image + * but simply hashing it. + * + * The sparse convolution is as follows: + *%MINIFYHTMLc3d0cd9fab65de6875a381fd3f83e1b338%* + * Where 'x' is the texel being modified. Setting blur scale higher + * than 1 spaces the samples out. + * + * @param f the desired filter scale (default=1) + */ + public void setBlurScale(float f) { + this.blurScale = f; + } + + /** + * returns the blur scale + * @return the scale + */ + public float getBlurScale() { + return blurScale; + } + + /** + * Sets the minimum blur factor before the convolution filter is + * calculated. The default is 0.2 which means if the "unfocus" + * amount is less than 0.2 (where 0 is no blur and 1.0 is full blurScale) + * then no blur will be applied at all. Depending on the GPU implementation, + * this may be an optimization since it uses branching to skip the expensive + * convolution filter. + * + *

      In scenes where the focus distance is close (like 0) and the focus range + * is relatively large, this threshold will remove some subtlety in + * the near-camera blurring and should be set smaller than the default + * or to 0 to disable completely. Sometimes that cut-off is desired if + * mid-to-far field unfocusing is all that is desired.

      + * + * @param f the desired blur factor (default=0.2) + */ + public void setBlurThreshold( float f ) { + this.blurThreshold = f; + if (material != null) { + material.setFloat("BlurThreshold", blurThreshold); + } + } + + /** + * returns the blur threshold. + * @return the threshold + */ + public float getBlurThreshold() { + return blurThreshold; + } + + /** + * Turns on/off debugging of the 'unfocus' value that is used to + * mix the convolution filter. When this is on, the 'unfocus' value + * is rendered as gray scale. This can be used to more easily visualize + * where in your view the focus is centered and how steep the gradient/cutoff + * is, etcetera. + * + * @param b true to enable debugging, false to disable it (default=false) + */ + public void setDebugUnfocus( boolean b ) { + this.debugUnfocus = b; + if( material != null ) { + material.setBoolean("DebugUnfocus", debugUnfocus); + } + } + + /** + * + * @return + */ + public boolean getDebugUnfocus() { + return debugUnfocus; + } + +} From d2c56396076a9b851f013c49773069c6473a2328 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 22 Jun 2024 09:52:00 -0400 Subject: [PATCH 091/111] narrowed PBR issue to metallic=1 --- ...eBasedDeferredSinglePassLightingLogic.java | 1 + .../framegraph/FrameGraphFactory.java | 21 +- .../renderer/framegraph/ResourceTicket.java | 2 +- .../framegraph/light/LightFrustum.java | 43 ++-- .../framegraph/light/LightImagePacker.java | 10 +- .../framegraph/light}/TiledRenderGrid.java | 4 +- .../renderer/framegraph/passes/BlitPass.java | 69 ++++++ .../framegraph/passes/DeferredPass.java | 20 +- .../framegraph/passes/GBufferPass.java | 25 +- .../renderer/framegraph/passes/Junction.java | 4 + .../framegraph/passes/LightImagePass.java | 30 ++- .../framegraph/passes/QueueJoinPass.java | 83 +++++++ .../framegraph/passes/RenderPass.java | 143 +++++++++-- .../framegraph/passes/SceneEnqueuePass.java | 8 +- .../framegraph/passes/TileDeferredPass.java | 2 +- .../com/jme3/renderer/queue/GeometryList.java | 65 +++-- .../java/com/jme3/scene/ParentIterator.java | 62 +++++ .../resources/Common/FrameGraphs/Deferred.j3g | Bin 1440 -> 3430 bytes .../resources/Common/FrameGraphs/Forward.j3g | Bin 707 -> 1039 bytes .../Common/FrameGraphs/TiledDeferred.j3g | Bin 1448 -> 0 bytes .../MatDefs/Light/PBRLightingGBufferPack.frag | 73 +++--- .../resources/Common/MatDefs/Misc/Null.frag | 5 + .../resources/Common/MatDefs/Misc/Null.j3md | 18 ++ .../resources/Common/MatDefs/Misc/Null.vert | 5 + .../ShadingCommon/DeferredShading.frag | 131 ++++++---- .../ShadingCommon/DeferredShading.j3md | 4 + .../com/jme3/post/framegraph/BloomPass.java | 232 ++++++++++++++++++ .../jme3/post/framegraph/CartoonEdgePass.java | 1 + .../post/framegraph/DepthOfFieldPass.java | 5 +- .../TestSimpleDeferredLighting.java | 8 +- .../renderpath/sandbox/FrameGraphSandbox.java | 22 -- .../jme3test/renderpath/sandbox/Main.java | 105 ++++++++ 32 files changed, 992 insertions(+), 209 deletions(-) rename jme3-core/src/main/java/com/jme3/{material/logic => renderer/framegraph/light}/TiledRenderGrid.java (98%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BlitPass.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueJoinPass.java create mode 100644 jme3-core/src/main/java/com/jme3/scene/ParentIterator.java delete mode 100644 jme3-core/src/main/resources/Common/FrameGraphs/TiledDeferred.j3g create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Misc/Null.frag create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Misc/Null.j3md create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Misc/Null.vert create mode 100644 jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java delete mode 100644 jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java 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 b07bc1cd98..14a0fbbadd 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,7 @@ */ package com.jme3.material.logic; +import com.jme3.renderer.framegraph.light.TiledRenderGrid; import com.jme3.asset.AssetManager; import com.jme3.light.*; import com.jme3.material.Material.BindUnits; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 8fa1b717a6..53ee9169dc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -32,7 +32,7 @@ package com.jme3.renderer.framegraph; import com.jme3.asset.AssetManager; -import com.jme3.material.logic.TiledRenderGrid; +import com.jme3.renderer.framegraph.light.TiledRenderGrid; import com.jme3.renderer.framegraph.client.GraphSetting; import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.framegraph.passes.DeferredPass; @@ -63,12 +63,18 @@ public static FrameGraph forward(AssetManager assetManager) { FrameGraph fg = new FrameGraph(assetManager); fg.setName("Forward"); - fg.add(new OutputRenderPass(RenderQueue.Bucket.Opaque)); - fg.add(new OutputRenderPass(RenderQueue.Bucket.Sky, DepthRange.REAR)); - fg.add(new OutputRenderPass(RenderQueue.Bucket.Transparent)); - fg.add(new OutputRenderPass(RenderQueue.Bucket.Gui, DepthRange.FRONT)); - fg.add(new PostProcessingRenderPass()); - fg.add(new OutputRenderPass(RenderQueue.Bucket.Translucent)); + SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass()); + OutputRenderPass opaque = fg.add(new OutputRenderPass()); + OutputRenderPass sky = fg.add(new OutputRenderPass(DepthRange.REAR)); + OutputRenderPass transparent = fg.add(new OutputRenderPass()); + OutputRenderPass gui = fg.add(new OutputRenderPass(DepthRange.FRONT, false)); + OutputRenderPass translucent = fg.add(new OutputRenderPass()); + + opaque.makeInput(enqueue, "Opaque", "Geometry"); + sky.makeInput(enqueue, "Sky", "Geometry"); + transparent.makeInput(enqueue, "Transparent", "Geometry"); + gui.makeInput(enqueue, "Gui", "Geometry"); + translucent.makeInput(enqueue, "Translucent", "Geometry"); return fg; @@ -98,7 +104,6 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { OutputRenderPass sky = fg.add(new OutputRenderPass(DepthRange.REAR)); OutputRenderPass transparent = fg.add(new OutputRenderPass()); OutputRenderPass gui = fg.add(new OutputRenderPass(DepthRange.FRONT, false)); - fg.add(new PostProcessingRenderPass()); OutputRenderPass translucent = fg.add(new OutputRenderPass()); gbuf.makeInput(enqueue, "Opaque", "Geometry"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index 4a62344272..e0ecf2d02f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -238,7 +238,7 @@ public boolean hasSource() { @Override public String toString() { - return "Ticket[name="+name+", index="+localIndex+"]"; + return "Ticket[name="+name+", worldIndex="+getWorldIndex()+"]"; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java index 36693f3508..3cbc2c1ece 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java @@ -9,7 +9,6 @@ import com.jme3.light.Light; import com.jme3.light.PointLight; import com.jme3.light.SpotLight; -import com.jme3.material.logic.TiledRenderGrid; import com.jme3.math.Matrix4f; import com.jme3.math.Vector3f; import com.jme3.math.Vector4f; @@ -41,6 +40,7 @@ public class LightFrustum { private final Vector4f lightLeft = new Vector4f(); private final Vector4f lightUp = new Vector4f(); private final Vector4f lightCenter = new Vector4f(); + private boolean fullscreen = false; public LightFrustum calculateCamera(Camera cam) { viewPortWidth = cam.getWidth() * 0.5f; @@ -76,8 +76,12 @@ public LightFrustum fromDirectional(DirectionalLight dl) { } public LightFrustum fromPoint(PointLight pl) { - float r = pl.getRadius(); - if(r <= 0)return null; + //return fullscreen(); + + float r = Math.abs(pl.getRadius()); + if (r == 0) { + throw new IllegalStateException("PointLight radius cannot be zero in this context."); + } float lr = r * camLeftCoeff; float tr = r * camTopCoeff; tempVec4.set(pl.getPosition().x, pl.getPosition().y, pl.getPosition().z, 1.0f); @@ -143,27 +147,32 @@ public LightFrustum fromAmbient(AmbientLight al) { return fullscreen(); } public LightFrustum fullscreen() { + fullscreen = true; left = bottom = 0; - right = viewPortWidth; - top = viewPortHeight; + right = viewPortWidth*2; + top = viewPortHeight*2; return this; } public void write(ArrayList> tileIndices, TiledRenderGrid tileInfo, int lightIndex) { - int width = tileInfo.getGridWidth(); - int numTiles = tileInfo.getNumTiles(); - int tileLeft = (int)Math.max(Math.floor(left / tileInfo.getTileSize()), 0); - int tileRight = (int)Math.min(Math.ceil(right / tileInfo.getTileSize()), width); - int tileBottom = (int)Math.max(Math.floor(bottom / tileInfo.getTileSize()), 0); - int tileTop = (int)Math.min(Math.ceil(top / tileInfo.getTileSize()), tileInfo.getGridHeight()); - for (int b = tileBottom; b < tileTop; b++) { - int base = b*width; - for (int l = tileLeft; l < tileRight; l++) { - int tileId = l+base; - if (tileId >= 0 && tileId < numTiles) { - tileIndices.get(tileId).add(lightIndex); + if (!fullscreen) { + int width = tileInfo.getGridWidth(); + int numTiles = tileInfo.getNumTiles(); + int tileLeft = (int)Math.max(Math.floor(left / tileInfo.getTileSize()), 0); + int tileRight = (int)Math.min(Math.ceil(right / tileInfo.getTileSize()), width); + int tileBottom = (int)Math.max(Math.floor(bottom / tileInfo.getTileSize()), 0); + int tileTop = (int)Math.min(Math.ceil(top / tileInfo.getTileSize()), tileInfo.getGridHeight()); + for (int b = tileBottom; b < tileTop; b++) { + int base = b*width; + for (int l = tileLeft; l < tileRight; l++) { + int tileId = l+base; + if (tileId >= 0 && tileId < numTiles) { + tileIndices.get(tileId).add(lightIndex); + } } } + } else for (LinkedList l : tileIndices) { + l.add(lightIndex); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java index 2e1c23cc56..d9e4e6e554 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java @@ -10,7 +10,6 @@ import com.jme3.light.LightProbe; import com.jme3.light.PointLight; import com.jme3.light.SpotLight; -import com.jme3.material.logic.TiledRenderGrid; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; @@ -146,14 +145,14 @@ private void packLightIndices() { final int tileWidth = textures[3].getImage().getWidth(); final int tileHeight = textures[3].getImage().getHeight(); final ColorRGBA tileInfoColor = new ColorRGBA(); + tempColor.set(0, 0, 0, 0); for (LinkedList l : tileIndices) { // raster tile info to texture tileInfoColor.r = xIndex; tileInfoColor.g = yIndex; tileInfoColor.b = componentIndex; tileInfoColor.a = l.size(); - // flip Y index, because tiles are computed from bottom to top - rasters[3].setPixel(tileX, tileHeight-tileY, tileInfoColor); + rasters[3].setPixel(tileX, tileY, tileInfoColor); if (++tileX >= tileWidth) { tileX = 0; tileY++; @@ -161,13 +160,13 @@ private void packLightIndices() { // raster light indices to texture for (int index : l) { // pack 4 indices per pixel - switch (componentIndex++) { + switch (componentIndex) { case 0: tempColor.r = index; break; case 1: tempColor.g = index; break; case 2: tempColor.b = index; break; case 3: tempColor.a = index; break; } - if (componentIndex > 3) { + if (++componentIndex > 3) { componentIndex = 0; rasters[4].setPixel(xIndex, yIndex, tempColor); if (++xIndex >= indexWidth) { @@ -178,6 +177,7 @@ private void packLightIndices() { } l.clear(); } + // if the index color is incomplete, raster it to the texture if (componentIndex != 0) { rasters[4].setPixel(xIndex, yIndex, tempColor); } diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java similarity index 98% rename from jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java index 07b7402c4c..876a192f4e 100644 --- a/jme3-core/src/main/java/com/jme3/material/logic/TiledRenderGrid.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.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.material.logic; +package com.jme3.renderer.framegraph.light; import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; @@ -46,7 +46,7 @@ public class TiledRenderGrid implements Savable { private int divisions = 4; - private int forcedTileSize = 64; + private int forcedTileSize = 128; //64 private int tileSize = 0; private int gridWidth = 0; private int gridHeight = 0; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BlitPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BlitPass.java new file mode 100644 index 0000000000..8e0c843e1b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BlitPass.java @@ -0,0 +1,69 @@ +/* + * 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.passes; + +import com.jme3.material.Material; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture2D; + +/** + * + * @author codex + */ +public class BlitPass extends RenderPass { + + private ResourceTicket source; + private ResourceTicket color, depth; + private final TextureDef colorDef = TextureDef.texture2D(); + private final TextureDef depthDef = TextureDef.texture2D(); + private Material nullMat; + + @Override + protected void initialize(FrameGraph frameGraph) { + source = addInput("Source"); + color = addOutput("Color"); + depth = addOutput("Depth"); + colorDef.setFormatFlexible(true); + depthDef.setFormat(Image.Format.Depth); + depthDef.setFormatFlexible(true); + nullMat = new Material(frameGraph.getAssetManager(), "Common/MatDefs/Misc/Null.j3md"); + } + @Override + protected void prepare(FGRenderContext context) { + declare(colorDef, color); + declare(depthDef, depth); + reserve(color, depth); + referenceOptional(source); + } + @Override + protected void execute(FGRenderContext context) { + FrameBuffer sourceBuf = resources.acquireOrElse(source, null); + FrameBuffer targetBuf; + if (sourceBuf != null) { + targetBuf = getFrameBuffer(sourceBuf.getWidth(), sourceBuf.getHeight(), sourceBuf.getSamples()); + colorDef.setSize(sourceBuf.getWidth(), sourceBuf.getHeight()); + depthDef.setSize(sourceBuf.getWidth(), sourceBuf.getHeight()); + } else { + targetBuf = getFrameBuffer(context, 1); + colorDef.setSize(context.getWidth(), context.getHeight()); + depthDef.setSize(context.getWidth(), context.getHeight()); + } + context.getRenderer().copyFrameBuffer(sourceBuf, targetBuf, true, true); + resources.acquireColorTarget(targetBuf, color); + resources.acquireDepthTarget(targetBuf, depth); + context.getRenderer().setFrameBuffer(targetBuf); + context.renderFullscreen(nullMat); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 1d2faf89d7..0be66ee8cc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -47,7 +47,6 @@ import com.jme3.material.logic.SkyLightAndReflectionProbeRender; import com.jme3.material.logic.TechniqueDefLogic; import com.jme3.math.ColorRGBA; -import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Caps; import com.jme3.renderer.RenderManager; @@ -63,7 +62,6 @@ import com.jme3.shader.VarType; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture2D; -import com.jme3.texture.image.ImageRaster; import java.io.IOException; import java.util.EnumSet; import java.util.LinkedList; @@ -78,6 +76,7 @@ public class DeferredPass extends RenderPass implements TechniqueDefLogic { private static Defines defs; private static final List localProbeList = new LinkedList<>(); + public static final int MAX_BUFFER_LIGHTS = 341; private boolean tiled = false; private AssetManager assetManager; @@ -133,6 +132,7 @@ protected void prepare(FGRenderContext context) { reference(getGroupArray("GBufferData")); referenceOptional(lights, numLights, ambient, probes); referenceOptional(getGroupArray("LightTextures")); + referenceOptional(getGroupArray("TileTextures")); } @Override protected void execute(FGRenderContext context) { @@ -156,10 +156,8 @@ protected void execute(FGRenderContext context) { } // get textures used for screenspace light tiling acquireArrayOrElse("TileTextures", tileTextures, null); - if (tileTextures[0] != null) { - material.setTexture("m_Tiles", tileTextures[0]); - material.setTexture("m_LightIndex", tileTextures[1]); - } + material.setTexture("Tiles", tileTextures[0]); + material.setTexture("LightIndex", tileTextures[1]); context.renderFullscreen(material); } material.getActiveTechnique().getDef().setLogic(null); @@ -196,6 +194,7 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager } } //defines.set(defs.numLights, 1); + defines.set(defs.useAmbientLight, true); defines.set(defs.numProbes, Math.min(probeList.size(), 3)); return material.getActiveTechnique().getDef().getShader(assetManager, rendererCaps, defines); } @@ -251,10 +250,13 @@ private void injectShaderGlobals(RenderManager rm, Shader shader, int lastTexUni private void injectLightBuffers(Shader shader, LightList lights) { // ambient lights and probes should already have been extracted at this point Uniform data = shader.getUniform("g_LightData"); - int n = lights.size()*3; + int n = Math.min(lights.size(), MAX_BUFFER_LIGHTS)*3; data.setVector4Length(n); - int i = 0; + int i = 0, lightCount = 0; for (Light l : lights) { + if (lightCount++ > MAX_BUFFER_LIGHTS) { + break; + } Light.Type type = l.getType(); writeColorToUniform(data, l.getColor(), type.getId(), i++); switch (type) { @@ -291,7 +293,7 @@ private void injectLightTextures(Shader shader) { if (tileTextures[0] != null) { w = tileTextures[1].getImage().getWidth(); int h = tileTextures[1].getImage().getHeight(); - shader.getUniform("m_LightIndexSize").setValue(VarType.Vector3, new Vector3f(w, 1f/w, 1f/h)); + shader.getUniform("m_LightIndexSize").setValue(VarType.Vector3, new Vector3f(w-0.5f, 1f/w, 1f/h)); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 3f5ffab461..451b0a760a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -41,7 +41,6 @@ import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.TextureDef; -import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; @@ -50,6 +49,8 @@ import java.util.function.Function; import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.queue.GeometryList; +import com.jme3.scene.ParentIterator; +import com.jme3.scene.Spatial; /** * Renders diffuse, specular, emissive, normal, and depth information to a set of @@ -69,7 +70,6 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private ResourceTicket numRendersTicket; private ValueDef lightDef; private final TextureDef[] texDefs = new TextureDef[5]; - private final LinkedList accumulatedLights = new LinkedList<>(); private int numRenders = 0; @Override @@ -114,10 +114,13 @@ protected void execute(FGRenderContext context) { context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); context.getRenderManager().setForcedTechnique(GBUFFER_PASS); context.getRenderManager().setGeometryRenderHandler(this); - context.renderGeometryList(resources.acquire(geometry), null, this); - // add accumulated lights - while (!accumulatedLights.isEmpty()) { - lightList.add(accumulatedLights.pollFirst()); + GeometryList bucket = resources.acquire(geometry); + context.renderGeometryList(bucket, null, this); + // get lights for all rendered geometries + for (Spatial s : new ParentIterator(bucket)) { + for (Light l : s.getLocalLightList()) { + lightList.add(l); + } } resources.setPrimitive(numRendersTicket, numRenders); } @@ -133,16 +136,6 @@ public boolean renderGeometry(RenderManager rm, Geometry geom) { } rm.renderGeometry(geom); numRenders++; - if (material.getActiveTechnique() != null) { - LightList lts = geom.getFilterWorldLights(); - for (Light l : lts) { - // todo: checking for containment is very slow - if (!accumulatedLights.contains(l)) { - accumulatedLights.add(l); - } - } - return true; - } return false; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 4dd77ac2ca..96a6c82dcf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -155,6 +155,10 @@ public void read(JmeImporter im) throws IOException { defaultIndex = in.readInt("defaultIndex", 0); source = (GraphSource)in.readSavable("source", null); } + @Override + public ResourceTicket addTicketSlot(String group) { + throw new UnsupportedOperationException("Cannot resize group."); + } private void connect(int i) { boolean assignNull = i < 0 || i >= length; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java index 4f658c83fb..e68ae5586f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java @@ -10,7 +10,7 @@ import com.jme3.export.OutputCapsule; import com.jme3.light.LightList; import com.jme3.light.LightProbe; -import com.jme3.material.logic.TiledRenderGrid; +import com.jme3.renderer.framegraph.light.TiledRenderGrid; import com.jme3.math.ColorRGBA; import com.jme3.renderer.Camera; import com.jme3.renderer.framegraph.FGRenderContext; @@ -42,8 +42,8 @@ public class LightImagePass extends RenderPass { private ResourceTicket ambientColor; private ResourceTicket> probes; private final LightTextureDef lightTexDef = new LightTextureDef(512); - private final TextureDef tileDef = TextureDef.texture2D(); - private final TextureDef indexDef = TextureDef.texture2D(); + private final TileTextureDef tileDef = new TileTextureDef(); + private final TileTextureDef indexDef = new TileTextureDef(); private final ColorRGBA ambient = new ColorRGBA(); private final LinkedList probeList = new LinkedList<>(); @@ -60,11 +60,11 @@ protected void initialize(FrameGraph frameGraph) { lightTexDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); lightTexDef.setMagFilter(Texture.MagFilter.Nearest); lightTexDef.setWrap(Texture.WrapMode.EdgeClamp); - tileDef.setFormat(Image.Format.RGBA32I); + tileDef.setFormat(Image.Format.RGBA32F); tileDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); tileDef.setMagFilter(Texture.MagFilter.Nearest); tileDef.setWrap(Texture.WrapMode.EdgeClamp); - indexDef.setFormat(Image.Format.RGBA32I); + indexDef.setFormat(Image.Format.RGBA32F); indexDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); indexDef.setMagFilter(Texture.MagFilter.Nearest); indexDef.setWrap(Texture.WrapMode.EdgeClamp); @@ -151,9 +151,8 @@ public LightTextureDef(int maxLights) { public Texture2D createResource() { Image.Format format = getFormat(); int width = getWidth(); - ByteBuffer data = BufferUtils.createByteBuffer((int)Math.ceil(format.getBitsPerPixel()/8)*width); + ByteBuffer data = BufferUtils.createByteBuffer((int)(format.getBitsPerPixel()/8)*width); Image img = new Image(format, width, 1, data, null, getColorSpace()); - //img.setMipmapsGenerated(false); return createTexture(img); } @Override @@ -162,5 +161,22 @@ public void setHeight(int height) {} public void setDepth(int depth) {} } + private static class TileTextureDef extends TextureDef { + + public TileTextureDef() { + super(Texture2D.class, img -> new Texture2D(img)); + } + + @Override + public Texture2D createResource() { + Image.Format format = getFormat(); + int width = getWidth(); + int height = getHeight(); + ByteBuffer data = BufferUtils.createByteBuffer((int)(format.getBitsPerPixel()/8)*width*height); + Image img = new Image(format, width, height, data, null, getColorSpace()); + return createTexture(img); + } + + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueJoinPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueJoinPass.java new file mode 100644 index 0000000000..bb914346c0 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueJoinPass.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.passes; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.ValueDef; +import com.jme3.renderer.queue.GeometryList; +import com.jme3.renderer.queue.NullComparator; +import java.io.IOException; + +/** + * Joins a number of geometry lists into one. + * + * @author codex + */ +public class QueueJoinPass extends RenderPass { + + private int groupSize = 2; + private ResourceTicket result; + private ValueDef listDef; + + public QueueJoinPass() {} + public QueueJoinPass(int groupSize) { + this.groupSize = groupSize; + } + + @Override + protected void initialize(FrameGraph frameGraph) { + addInputGroup("Input", groupSize); + result = addOutput("Result"); + listDef = new ValueDef<>(GeometryList.class, obj -> new GeometryList(new NullComparator())); + listDef.setReviser(list -> list.clear()); + } + @Override + protected void prepare(FGRenderContext context) { + declare(listDef, result); + reference(getGroupArray("Input")); + } + @Override + protected void execute(FGRenderContext context) { + GeometryList target = resources.acquire(result); + GeometryList[] sources = acquireArray("Input", GeometryList[]::new); + for (GeometryList s : sources) { + target.addList(s); + } + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + if (isAssigned()) { + out.write(getGroupArray("Input").length, "groupSize", 2); + } else { + out.write(groupSize, "groupSize", 2); + } + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + groupSize = in.readInt("groupSize", 2); + } + + public void setGroupSize(int groupSize) { + if (isAssigned()) { + throw new IllegalStateException("Cannot resize group while assigned to a framegraph."); + } + this.groupSize = groupSize; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 7ddd19cd88..0acf38b629 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -50,6 +50,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.function.Function; /** * Performs rendering operations for a framegraph. @@ -301,6 +302,24 @@ protected T[] acquireArray(String name, T[] array) { } return array; } + /** + * Acquires a set of resources from a ticket group and stores them in an + * array created by the function. + * + * @param + * @param name + * @param func + * @return + */ + protected T[] acquireArray(String name, Function func) { + ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); + T[] array = func.apply(tickets.length); + int n = Math.min(array.length, tickets.length); + for (int i = 0; i < n; i++) { + array[i] = resources.acquire(tickets[i]); + } + return array; + } /** * Acquires a set of resources from a ticket group and stores them in * the array. @@ -321,6 +340,27 @@ protected T[] acquireArrayOrElse(String name, T[] array, T val) { } return array; } + /** + * Acquires a set of resources from a ticket group and stores them in an + * array created by the function. + *

      + * Tickets that are invalid will acquire {@code val}. + * + * @param + * @param name + * @param func + * @param val + * @return + */ + protected T[] acquireArrayOrElse(String name, Function func, T val) { + ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); + T[] array = func.apply(tickets.length); + int n = Math.min(array.length, tickets.length); + for (int i = 0; i < n; i++) { + array[i] = resources.acquireOrElse(tickets[i], val); + } + return array; + } /** * Acquires a list of resources from a ticket group and stores them in the given list. * @@ -593,6 +633,23 @@ public void makeInputToList(RenderPass sourcePass, String sourceTicket, String t } target.add().setSource(source); } + /** + * Adds a ticket to the end of a group. + *

      + * The group cannot be a list. + * + * @param + * @param group + * @return added ticket + */ + public ResourceTicket addTicketSlot(String group) { + TicketGroup g = groups.get(group); + if (g == null) { + throw new NullPointerException("Ticket group cannot be null."); + } + g.requireAs(false); + return g.add(); + } /** * Disconnects all input tickets in this pass that have the given ticket as @@ -639,27 +696,38 @@ public void disconnectInputsFrom(RenderPass pass) { * and returned. * * @param cap graph event capturer, for debugging, may be null. + * @param tag * @param width * @param height * @param samples * @return */ - protected FrameBuffer getFrameBuffer(GraphEventCapture cap, int width, int height, int samples) { + protected FrameBuffer getFrameBuffer(GraphEventCapture cap, String tag, int width, int height, int samples) { + if (tag == null) { + tag = PassFrameBuffer.DEF_TAG; + } for (PassFrameBuffer fb : frameBuffers) { - if (fb.qualifies(width, height, samples)) { + if (fb.qualifies(tag, width, height, samples)) { return fb.use(); } } - PassFrameBuffer fb = new PassFrameBuffer(width, height, samples); + PassFrameBuffer fb = new PassFrameBuffer(tag, width, height, samples); frameBuffers.add(fb); if (cap != null) cap.createFrameBuffer(fb.frameBuffer); return fb.use(); } /** - * Gets an existing framebuffer that matches the given properties. - *

      - * In no existing framebuffer matches, a new framebuffer will be created - * and returned. + * + * @param cap + * @param width + * @param height + * @param samples + * @return + */ + protected FrameBuffer getFrameBuffer(GraphEventCapture cap, int width, int height, int samples) { + return getFrameBuffer(cap, null, width, height, samples); + } + /** * * @param width * @param height @@ -667,13 +735,20 @@ protected FrameBuffer getFrameBuffer(GraphEventCapture cap, int width, int heigh * @return */ protected FrameBuffer getFrameBuffer(int width, int height, int samples) { - return getFrameBuffer(null, width, height, samples); + return getFrameBuffer(null, null, width, height, samples); + } + /** + * + * @param tag + * @param width + * @param height + * @param samples + * @return + */ + protected FrameBuffer getFrameBuffer(String tag, int width, int height, int samples) { + return getFrameBuffer(null, tag, width, height, samples); } /** - * Gets an existing framebuffer that matches the context. - *

      - * If no existing framebuffer matches, a new framebuffer will be created - * and returned. Uses event capturing if available. * * @param context * @param samples @@ -682,6 +757,16 @@ protected FrameBuffer getFrameBuffer(int width, int height, int samples) { protected FrameBuffer getFrameBuffer(FGRenderContext context, int samples) { return getFrameBuffer(context.getGraphCapture(), context.getWidth(), context.getHeight(), samples); } + /** + * + * @param context + * @param tag + * @param samples + * @return + */ + protected FrameBuffer getFrameBuffer(FGRenderContext context, String tag, int samples) { + return getFrameBuffer(context.getGraphCapture(), tag, context.getWidth(), context.getHeight(), samples); + } /** * Counts the number of potential references to this pass. @@ -865,10 +950,17 @@ public static String listTicketName(String group) { private static class PassFrameBuffer { + public static final String DEF_TAG = "#DefaultTag"; + + public final String tag; public final FrameBuffer frameBuffer; public boolean used = false; public PassFrameBuffer(int width, int height, int samples) { + this(DEF_TAG, width, height, samples); + } + public PassFrameBuffer(String tag, int width, int height, int samples) { + this.tag = tag; frameBuffer = new FrameBuffer(width, height, samples); } @@ -877,10 +969,11 @@ public FrameBuffer use() { return frameBuffer; } - public boolean qualifies(int width, int height, int samples) { + public boolean qualifies(String tag, int width, int height, int samples) { return frameBuffer.getWidth() == width && frameBuffer.getHeight() == height - && frameBuffer.getSamples() == samples; + && frameBuffer.getSamples() == samples + && this.tag.equals(tag); } public void dispose() { @@ -905,21 +998,23 @@ public TicketGroup(String name, int length) { } public ResourceTicket create(int i) { - return new ResourceTicket<>(groupTicketName(name, i), name); - } - private ResourceTicket create() { - return new ResourceTicket<>(listTicketName(name), name); + String tName; + if (!list) { + tName = groupTicketName(name, i); + } else { + tName = listTicketName(name); + } + return new ResourceTicket<>(tName, name); } public ResourceTicket add() { - requireAsList(); ResourceTicket[] temp = new ResourceTicket[array.length+1]; System.arraycopy(array, 0, temp, 0, array.length); array = temp; - return (array[array.length-1] = create()); + return (array[array.length-1] = create(array.length-1)); } public int remove(ResourceTicket t) { - requireAsList(); + requireAs(true); int i = array.length-1; for (; i >= 0; i--) { if (array[i] == t) break; @@ -937,9 +1032,9 @@ public int remove(ResourceTicket t) { return i; } - private void requireAsList() { - if (!list) { - throw new IllegalStateException("Group must be a list to alter ticket array."); + public void requireAs(boolean asList) { + if (list != asList) { + throw new IllegalStateException("Group must be "+(asList ? "a list" : "an array")+" in this context."); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java index 79e321ca7a..1ea93c8678 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java @@ -64,7 +64,7 @@ protected void prepare(FGRenderContext context) { protected void execute(FGRenderContext context) { ViewPort vp = context.getViewPort(); List scenes = vp.getScenes(); - for (int i = scenes.size(); i >= 0; i--) { + for (int i = scenes.size()-1; i >= 0; i--) { vp.getCamera().setPlaneState(0); queueSubScene(context, scenes.get(i), null); } @@ -73,7 +73,11 @@ protected void execute(FGRenderContext context) { } } @Override - protected void reset(FGRenderContext context) {} + protected void reset(FGRenderContext context) { + for (Bucket b : buckets) { + b.queue.clear(); + } + } @Override protected void cleanup(FrameGraph frameGraph) {} @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java index 16ba7b363f..0e434ddac1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java @@ -35,7 +35,7 @@ import com.jme3.material.Material; import com.jme3.material.TechniqueDef; import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic; -import com.jme3.material.logic.TiledRenderGrid; +import com.jme3.renderer.framegraph.light.TiledRenderGrid; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java index a974712ca1..9a5af3d58f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java @@ -37,6 +37,7 @@ import com.jme3.renderer.Camera; import com.jme3.scene.Geometry; import com.jme3.util.ListSort; +import java.util.ArrayList; /** * This class is a special purpose list of {@link Geometry} objects for render @@ -56,6 +57,7 @@ public class GeometryList implements Iterable{ private GeometryComparator comparator; private Camera cam; private boolean updateFlag = true; + private ArrayList lists = new ArrayList<>(); /** * Initializes the GeometryList to use the given {@link GeometryComparator} @@ -106,6 +108,9 @@ public void setCamera(Camera cam) { comparator.setCamera(this.cam); updateFlag = true; } + for (GeometryList l : lists) { + l.setCamera(cam); + } } /** @@ -154,6 +159,15 @@ public void add(Geometry g) { geometries[size++] = g; updateFlag = true; } + + /** + * + * + * @param l + */ + public void addList(GeometryList l) { + lists.add(l); + } /** * Resets list size to 0. @@ -162,6 +176,7 @@ public void clear() { for (int i = 0; i < size; i++) { geometries[i] = null; } + lists.clear(); updateFlag = true; size = 0; } @@ -179,28 +194,50 @@ public void sort() { listSort.sort(geometries, comparator); updateFlag = false; } + for (GeometryList l : lists) { + l.sort(); + } } @Override public Iterator iterator() { - return new Iterator() { - int index = 0; - @Override - public boolean hasNext() { - return index < size(); + return new ListIterator(); + } + + private class ListIterator implements Iterator { + + private int arrayIndex = 0; + private int listIndex = 0; + private Iterator it = null; + + @Override + public boolean hasNext() { + if (arrayIndex < size) { + return true; } - @Override - public Geometry next() { - if (index >= size()) { - throw new NoSuchElementException("Geometry list has only " + size() + " elements"); + // iterate until a populated list is found + while (it == null || !it.hasNext()) { + if (listIndex >= lists.size()) { + return false; + } + GeometryList l = lists.get(listIndex++); + if (l.size > 0) { + it = l.iterator(); } - return get(index++); } - @Override - public void remove() { - throw new UnsupportedOperationException("Geometry list doesn't support iterator removal"); + return true; + } + @Override + public Geometry next() { + if (it != null) { + return it.next(); } - }; + return get(arrayIndex++); + } + @Override + public void remove() { + throw new UnsupportedOperationException("Geometry list doesn't support iterator removal"); + } } } \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/scene/ParentIterator.java b/jme3-core/src/main/java/com/jme3/scene/ParentIterator.java new file mode 100644 index 0000000000..c36ad20c72 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/scene/ParentIterator.java @@ -0,0 +1,62 @@ +/* + * 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.scene; + +import java.util.Iterator; +import java.util.LinkedList; + +/** + * Iterates through the given spatials and their ancestors. + * + * @author codex + */ +public class ParentIterator implements Iterable, Iterator { + + private static final String VISITED_TAG = ParentIterator.class.getName()+":visited"; + + private final LinkedList spatials = new LinkedList<>(); + private final LinkedList current = new LinkedList<>(); + private final Iterator iterator; + + public ParentIterator(Iterable startingPoints) { + for (Spatial s : startingPoints) { + if (!isVisited(s)) { + visit(s); + } + } + while (!current.isEmpty()) { + Spatial parent = current.removeFirst().getParent(); + if (parent != null && !isVisited(parent)) { + visit(parent); + } + } + iterator = spatials.iterator(); + } + + private boolean isVisited(Spatial s) { + return s.getUserData(VISITED_TAG) != null; + } + private void visit(Spatial s) { + s.setUserData(VISITED_TAG, true); + current.addFirst(s); + spatials.add(s); + } + + @Override + public Iterator iterator() { + return this; + } + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + @Override + public Spatial next() { + Spatial s = iterator.next(); + s.setUserData(VISITED_TAG, null); + return s; + } + +} diff --git a/jme3-core/src/main/resources/Common/FrameGraphs/Deferred.j3g b/jme3-core/src/main/resources/Common/FrameGraphs/Deferred.j3g index 162413476962fb1d1a8a28fb80815585a026b8fd..ab430aae62b219955cef6f2f0bfab93df5c3fdca 100644 GIT binary patch literal 3430 zcma)<&rcgy5XX0R{S%wt1PFvcfB*?#esgM-(vToWO+kQiXq3ZZKa9cNb#~uIA?l%j zK~Ghyo~lZ{R=u@7_0T_{hpLr&t9ovGuc{vUowvKj3$}%&=g;oGnRzqwX5QLQo<3UB zG|j;1>?C~iXRKgXbEj3YmJ_dQwj*-~<}354B6g2XML|MJDj)U!+>+9ZXb&Rgxz$zD}1M+p8Uv-_(n$ zaTnrYfwd2#P$>&b=2VXy_+0_hL8o!SrW@VQUB~@hRf9o7NE?8?>{g|AVs4k+g6R}H z8ZBO{Bz%kes=))hF`X+eUKBNXa*-qBEj-NBgyYt@bzjvplL@mi+ctu2Hn(qDB`$Ma zxgK{>$&xq<0}cS27@;{1<6boxT!w?v6lV<90WfEhrrLlVeotK zCdhW6Yp{=_;39Yn+y}=%54;V229AS2f)n81;2ng@>rR3@;1no9_z?RNybJyW&VYY{ zh&j$FoCDtm?}5kQeeh#&9{d(u0DlAFOZ*=&hZMqhZ3$cjm%(S?3iuMlv&1JL-X@7} zz;*Cva0C1U+zjps*Xo_|g+{5cXNfvVCxc>?pcJJkLs>lOq8{p{ew`+0fNszr4bd>& zq!AjWTQo+uX&f_mXp*LAn(opJ&C(p*qx&>Z3$#c%TB2oIp;cNlVB4UM!*WF&+NDxO zP>Qef*0D|9>Nwgn3ujM-Jh6)qT&E4%${Lz*M2$4G|*XbDzH5@o}U;T}has4h}Hf_laNP|xLqK&NhW4&)wuFkwkB@A1EW8Qai$~3hA61l-RAAcv}a(^sq`Q_9~(B>SEHr2y~Hg)(y8TqC2Vb9@8lknpV~`hvK#L9O2@Qtuzr^ zffE;EE3L#Z$)jQD;n}~9VQBgn4IaO9jcvsLd{3}r9?a~8wp}8=djtIB2%sGq*`)O=$ znKKy?UQ;=5F3cH?2(K$)R22HAMMX`k$+%8EYO@+D#h}zPv*L-MXj%z!?17*kbt^%R zI}r3Eo>EIE(4LnzurBA9YYVw63!{J#CqlU>y}BhoZRl=aBCNamyq_twravDPU442( zB@!*4B1-BMe`r^12M4Gk*TuM+LXP9=*Fn>LfO`7Uv0xmWowGXHqvO(4=Fl-Mw`SrW ti)s&O^N1L=wQ=VeM2En40K@_nC+O$zC9ucjC1goh%N!&WNHMT3UW5b3G zf5A7fIvmr zllDDYsMh6t-iv4`A)psBW||3=5i1(F$Dl1>BFBktvkQ0$G=L9)3Gl79fUkfJdkaqXpgpuYr%j>)>$E{_+N2I`asI4H&Dwk6L^_xwYSphi*T!{~<9#Gd)c*gR5%T2X zvq2VDZfY;Sl&c?TNMzpX=BW}K2bT2mVAyIJ|n;^G-p^31N+!EltN*i{fgc5Z&3e6Sq#Q9smg;aYINT8HsX4>VY;PNT{gk2~LZ>q;8wFS+865R&nNk z@KZSRKl&s3#&&`dqDWYJJL`QrZ$32p;p5T15JCZ=lvwBAo3xlE=QFdPIAb&8j7z>b zJu_3M%d@1^Rb{GVk{WA{?DyK#<`a(KENO@}u(&F=`9IHyI?o-@%8F7_SOOG@4-#t8Tgio3#cRdW`XK03*DgD{scB;3WSZQ2U za;aB~{s!}kpKq-AkmXLaof_y!@qj~AUOP{`RY(A47nsX&DX*9U#y|k@oe=l|^njm0 zANU1Cz;9p+_ycfb?tmDQydS_mgWZ9B4~tlo!g9Q3MqUW&4-0p#9cHFSk`x87ecF-~ z(l*63pdH%fd^opnBU8+bcQ=Z9$EC(oViwWm3acg;H%vX{#Fic7Q>SfJYP?k6 Yd1EG)wAHB2J8z`7M77?RHQutn2a;yp?f?J) literal 707 zcma))K}*9h6vy+Lw%goAMa7#J!GlnQiC01927)+rCj}vPajSD_Nz#KiZ+;lhei1*B z|JQ9Gt_%zR!4+v~i)F(~dZ9r@1jY^;vFQ7+_%eovkI$3CSRLeqi%dJC~X909Y&!sE0N* z@D>~VpN)dwX5=au!up~QirYe7pKSFy(_=mZL(ArwK6Pz-%Q4d@eULSGOwz9HsRSGOf7rhp_x z=$q6c*bA}C+0DO|bLIevx)jN~>6@gGHx!BUcP>MSLjiUTh}uJ|j4Kr0ieF%5?L^rx fGf9mKTNTfh?hC@h+g`o%g=bWYntQ&MDLj7wS+ANl diff --git a/jme3-core/src/main/resources/Common/FrameGraphs/TiledDeferred.j3g b/jme3-core/src/main/resources/Common/FrameGraphs/TiledDeferred.j3g deleted file mode 100644 index ed45c02beb1b6e271aedbb0e5b01df8787ac5835..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1448 zcma)6%Wl&^6!o>^N9(jrQ=VeM2En3|izs3Xv}vOvC=tmDR#SVDm^!vKwkxq?%Z3eq z!8fqvL%QY{*l@1xL`fT>S~_#C=gyq_n6clyJKEPY%>W!CjQs5S$;A6Sk^7#KaUhjc z-cX5&94V2Gy<;}JY<5I0uw2(ZVYE__WilhST|bFq>E~e*XS$Aw>9e;|xl-`D2gPtG zRS$aDr_(XUMvS1^I=_d3JumsN*jv<1&rs`kZ&IEy6f9L_4` zEOpM+4db-P2cds1bAu7=iNM99f-7BT-)m?9g9ww`9cNOw0%!js&zP@4z62vD`U~c~%CGRT zMh@v@P=ideVXu=*peAk5CT&rRwy8}!oIh)lJNM0SF?TRW)VkUfu8(W0#)ldLQ0wX) zLfHQK7lSOW-qc=xtyVwMkj%2x?m&q+O9lQFIg3NqT)NQc7NJ3FrEGZu+_HNbSw!vY zA1F&9roB|EiWwC?V)CKf=X&w0ush*!SY*|pqaVgKbnO2L0n+F zGd0L;)Pvr!_hd;u&XlIhx5^qu}(^b 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 f65cd8399f..0ed0aa3cd3 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag @@ -11,7 +11,7 @@ varying vec2 texCoord; #ifdef SEPARATE_TEXCOORD - varying vec2 texCoord2; + varying vec2 texCoord2; #endif varying vec4 Color; @@ -25,23 +25,23 @@ varying vec3 wPosition; #if NB_PROBES >= 1 - uniform samplerCube g_PrefEnvMap; - uniform vec3 g_ShCoeffs[9]; - uniform mat4 g_LightProbeData; + 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; + 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; + uniform samplerCube g_PrefEnvMap3; + uniform vec3 g_ShCoeffs3[9]; + uniform mat4 g_LightProbeData3; #endif #ifdef BASECOLORMAP - uniform sampler2D m_BaseColorMap; + uniform sampler2D m_BaseColorMap; #endif #ifdef USE_PACKED_MR @@ -59,7 +59,7 @@ varying vec3 wPosition; uniform vec4 m_Emissive; #endif #ifdef EMISSIVEMAP - uniform sampler2D m_EmissiveMap; + uniform sampler2D m_EmissiveMap; #endif #if defined(EMISSIVE) || defined(EMISSIVEMAP) uniform float m_EmissivePower; @@ -67,39 +67,39 @@ varying vec3 wPosition; #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 + + 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; + uniform sampler2D m_ParallaxMap; #endif #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) uniform float m_ParallaxHeight; #endif #ifdef LIGHTMAP - uniform sampler2D m_LightMap; + uniform sampler2D m_LightMap; #endif #if defined(NORMALMAP) || defined(PARALLAXMAP) - uniform sampler2D m_NormalMap; - varying vec4 wTangent; + uniform sampler2D m_NormalMap; + varying vec4 wTangent; #endif varying vec3 wNormal; #ifdef DISCARD_ALPHA - uniform float m_AlphaDiscardThreshold; + uniform float m_AlphaDiscardThreshold; #endif -void main() { - +void main(){ vec2 newTexCoord; vec3 viewDir = normalize(g_CameraPosition - wPosition); @@ -160,7 +160,7 @@ void main() { float alpha = albedo.a; #ifdef DISCARD_ALPHA - if (alpha < m_AlphaDiscardThreshold) { + if(alpha < m_AlphaDiscardThreshold){ discard; } #endif @@ -169,11 +169,16 @@ void main() { // Read from textures // *********************** #if defined(NORMALMAP) - vec4 normalHeight = texture2D(m_NormalMap, newTexCoord); - 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); + 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; + vec3 normal = norm; #endif #ifdef SPECGLOSSPIPELINE @@ -230,7 +235,7 @@ void main() { //float ndotv = max( dot( normal, viewDir ),0.0); - #if defined(EMISSIVE) || defined(EMISSIVEMAP) + #if defined(EMISSIVE) || defined (EMISSIVEMAP) #ifdef EMISSIVEMAP vec4 emissive = texture2D(m_EmissiveMap, newTexCoord); #else @@ -249,5 +254,5 @@ void main() { outGBuffer0.a = alpha; // shading model id - outGBuffer2.a = PBR_LIGHTING + 0.01; + outGBuffer2.a = PBR_LIGHTING + 0.01f; } diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Null.frag b/jme3-core/src/main/resources/Common/MatDefs/Misc/Null.frag new file mode 100644 index 0000000000..face67a151 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Null.frag @@ -0,0 +1,5 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" + +void main() { + discard; +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Null.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Null.j3md new file mode 100644 index 0000000000..362a967547 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Null.j3md @@ -0,0 +1,18 @@ +MaterialDef Null { + + MaterialParameters { + } + + Technique { + + VertexShader GLSL310 GLSL300 GLSL150 GLSL100 : Common/MatDefs/Misc/Null.vert + FragmentShader GLSL310 GLSL300 GLSL150 GLSL100 : Common/MatDefs/Misc/Null.frag + + WorldParameters { + } + + Defines { + } + + } +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Null.vert b/jme3-core/src/main/resources/Common/MatDefs/Misc/Null.vert new file mode 100644 index 0000000000..6cfed024dc --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Null.vert @@ -0,0 +1,5 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" + +void main() { + gl_Position = vec4(0.0); +} 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 7c154244ba..79a008174d 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -11,11 +11,11 @@ // skyLight and reflectionProbe uniform vec4 g_AmbientLightColor; #import "Common/ShaderLib/SkyLightReflectionProbe.glsllib" -#ifdef USE_LIGHT_TEXTURES - uniform vec2 g_ResolutionInverse; -#else +//#ifdef USE_LIGHT_TEXTURES +// uniform vec2 g_ResolutionInverse; +//#else varying vec2 texCoord; -#endif +//#endif varying mat4 viewProjectionMatrixInverse; uniform mat4 g_ViewMatrix; @@ -39,11 +39,11 @@ uniform int m_NBLights; void main(){ - #ifdef USE_LIGHT_TEXTURES - vec2 innerTexCoord = gl_FragCoord.xy * g_ResolutionInverse; - #else + //#ifdef USE_LIGHT_TEXTURES + // vec2 innerTexCoord = gl_FragCoord.xy * g_ResolutionInverse; + //#else vec2 innerTexCoord = texCoord; - #endif + //#endif // unpack m_GBuffer vec4 shadingInfo = texture2D(m_GBuffer2, innerTexCoord); int shadingModelId = int(floor(shadingInfo.a)); @@ -52,6 +52,7 @@ void main(){ // Due to GPU architecture, each shading mode is performed for each pixel, which is very inefficient. // TODO: Remove these if statements if possible. if (shadingModelId == PHONG_LIGHTING) { + // phong shading vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); vec4 buff1 = texture2D(m_GBuffer1, innerTexCoord); @@ -64,7 +65,6 @@ void main(){ vec3 viewDir = normalize(g_CameraPosition - vPos); gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; gl_FragColor.a = alpha; - //int lightNum = 0; #ifdef TILES // fetch index info from tile this fragment is contained by vec4 tileInfo = texture2D(m_Tiles, innerTexCoord); @@ -82,10 +82,6 @@ void main(){ if (componentIndex == 0 || lightIndex.x < 0) { // get indices from next pixel lightIndex = texture2D(m_LightIndex, vec2(x, y) * m_LightIndexSize.yz); - if (componentIndex == 0 && ++x >= m_LightIndexSize.x) { - x = 0; - y++; - } } // apply index from each component in order vec2 pixel = vec2(m_LightTexInv, 0); @@ -95,8 +91,15 @@ void main(){ case 2: pixel.x *= lightIndex.z; break; case 3: pixel.x *= lightIndex.w; break; } - if (++componentIndex > 3) { + // increment indices + componentIndex++; + if (componentIndex > 3) { componentIndex = 0; + x++; + if (x >= m_LightIndexSize.x) { + x = 0; + y++; + } } #else vec2 pixel = vec2(m_LightTexInv * i, 0); @@ -145,12 +148,11 @@ void main(){ i += 3; #endif } - //if (NB_LIGHTS == 1) { - // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); - //} + } else if (shadingModelId == PBR_LIGHTING) { + // PBR shading - vec3 vPos = getPosition(innerTexCoord, depth, viewProjectionMatrixInverse); + vec3 vPos = getPosition(innerTexCoord, viewProjectionMatrixInverse); vec4 buff0 = texture2D(m_GBuffer0, innerTexCoord); vec4 buff1 = texture2D(m_GBuffer1, innerTexCoord); vec3 emissive = shadingInfo.rgb; @@ -164,60 +166,104 @@ void main(){ vec4 n1n2 = texture2D(m_GBuffer3, innerTexCoord); vec3 normal = octDecode(n1n2.xy); vec3 norm = octDecode(n1n2.zw); - vec3 viewDir = normalize(g_CameraPosition - vPos); + vec3 viewDir = normalize(g_CameraPosition - vPos); + float ndotv = max( dot( normal, viewDir ),0.0); - int lightNum = 0; gl_FragColor.rgb = vec3(0.0); + #ifdef TILES + // fetch index info from tile this fragment is contained by + vec4 tileInfo = texture2D(m_Tiles, innerTexCoord); + int x = int(tileInfo.x); + int y = int(tileInfo.y); + int componentIndex = int(tileInfo.z); + int lightCount = int(tileInfo.w); + vec4 lightIndex = vec4(-1.0); + for (int i = 0; i < lightCount;) { + #else for (int i = 0; i < NB_LIGHTS;) { + #endif #ifdef USE_LIGHT_TEXTURES - vec2 pixel = vec2(m_LightTexInv * i, 0); + #ifdef TILED_LIGHTS + if (componentIndex == 0 || lightIndex.x < 0) { + // get indices from next pixel + lightIndex = texture2D(m_LightIndex, vec2(x, y) * m_LightIndexSize.yz); + } + // apply index from each component in order + vec2 pixel = vec2(m_LightTexInv, 0); + switch (componentIndex) { + case 0: pixel.x *= lightIndex.x; break; + case 1: pixel.x *= lightIndex.y; break; + case 2: pixel.x *= lightIndex.z; break; + case 3: pixel.x *= lightIndex.w; break; + } + // increment indices + componentIndex++; + if (componentIndex > 3) { + componentIndex = 0; + x++; + if (x >= m_LightIndexSize.x) { + x = 0; + y++; + } + } + #else + vec2 pixel = vec2(m_LightTexInv * i, 0); + #endif vec4 lightColor = texture2D(m_LightTex1, pixel); vec4 lightData1 = texture2D(m_LightTex2, pixel); #else vec4 lightColor = g_LightData[i]; vec4 lightData1 = g_LightData[i+1]; #endif + vec4 lightDir; vec3 lightVec; - lightComputeDir(vPos, lightColor.w, lightData1, lightDir,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){ + // allow use of control flow + if (lightColor.w > 1.0) { #endif - #ifdef USE_LIGHT_TEXTURES - spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); - #else - spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); - #endif + #if USE_LIGHT_TEXTURES + spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); + #else + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + #endif #if __VERSION__ >= 110 - } + } #endif spotFallOff *= lightDir.w; + + float radius = 1.0 / lightData1.w; + if (distance(vPos, lightData1.xyz) < radius) { + //gl_FragColor.rgb += lightColor.rgb * spotFallOff; + } #ifdef NORMALMAP - //Normal map -> lighting is computed in tangent space - lightDir.xyz = normalize(lightDir.xyz * tbnMat); + //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); + //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); + lightColor.rgb, fZero, Roughness, ndotv, + directDiffuse, directSpecular); vec3 directLighting = diffuseColor.rgb * directDiffuse + directSpecular; - gl_FragColor.rgb += directLighting * spotFallOff; - #ifdef USE_LIGHT_TEXTURES - i++; + + //gl_FragColor.rgb += directSpecular; + + #if USE_LIGHT_TEXTURES + i++; #else - i += 3; + i += 3; #endif } // skyLight and reflectionProbe @@ -227,14 +273,15 @@ void main(){ gl_FragColor.rgb += skyLight; gl_FragColor.rgb += emissive; gl_FragColor.a = alpha; - gl_FragColor.rgb = vec3(1-lightNum); - gl_FragColor.a = 1.0; + } /*else if (shadingModelId == SUBSURFACE_SCATTERING) { // TODO: implement subsurface scattering }*/ else if (shadingModelId == UNLIT) { + // unlit shading gl_FragColor.rgb = shadingInfo.rgb; gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f); + } else { discard; } 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 d7a46be786..e5c26785bb 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md @@ -16,6 +16,10 @@ MaterialDef DeferredShading { Int LightTexSize Vector2 LightTexInv + // Tiles + Texture2D Tiles + Texture2D LightIndex + } Technique DeferredPass { diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java new file mode 100644 index 0000000000..0a2d46e16c --- /dev/null +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java @@ -0,0 +1,232 @@ +/* + * 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.post.framegraph; + +import com.jme3.asset.AssetManager; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.renderer.framegraph.passes.RenderPass; +import com.jme3.renderer.queue.GeometryList; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture2D; +import java.io.IOException; + +/** + * + * @author codex + */ +public class BloomPass extends RenderPass { + + private ResourceTicket inColor; + private ResourceTicket objects; + private ResourceTicket midTex; + private ResourceTicket result; + private final TextureDef texDef = TextureDef.texture2D(); + private Material extractMat, hBlurMat, vBlurMat, outMat; + private float blurScale = 1.5f; + private float exposurePower = 5.0f; + private float exposureCutOff = 0.0f; + private float bloomIntensity = 2.0f; + private float downSamplingFactor = 1; + + @Override + protected void initialize(FrameGraph frameGraph) { + inColor = addInput("Color"); + objects = addInput("Objects"); + result = addOutput("Color"); + AssetManager assets = frameGraph.getAssetManager(); + extractMat = new Material(assets, "Common/MatDefs/Post/BloomExtract.j3md"); + hBlurMat = new Material(assets, "Common/MatDefs/Blur/HGaussianBlur.j3md"); + vBlurMat = new Material(assets, "Common/MatDefs/Blur/VGaussianBlur.j3md"); + outMat = new Material(assets, "Common/MatDefs/Post/BloomFinal.j3md"); + } + @Override + protected void prepare(FGRenderContext context) { + declare(texDef, result); + reserve(result); + referenceOptional(inColor, objects); + } + @Override + protected void execute(FGRenderContext context) { + // configure definitions + int w = (int)Math.max(1f, context.getWidth()/downSamplingFactor); + int h = (int)Math.max(1f, context.getHeight()/downSamplingFactor); + texDef.setSize(w, h); + // get resources + FrameBuffer outFb = getFrameBuffer(w, h, 1); + Texture2D outTarget = resources.acquireColorTarget(outFb, result); + FrameBuffer midFb = getFrameBuffer("mid", w, h, 1); + declare(texDef, midTex); + Texture2D midTarget = resources.acquireColorTarget(midFb, midTex); + GeometryList geometry = resources.acquireOrElse(objects, null); + Texture2D scene = resources.acquireOrElse(inColor, null); + context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); + // geometry render + if (geometry != null) { + context.getRenderer().setFrameBuffer(outFb); + context.getRenderer().clearBuffers(true, true, true); + context.getRenderManager().setForcedTechnique("Glow"); + context.renderGeometryList(geometry, null, null); + context.getRenderManager().setForcedTechnique(null); + extractMat.setTexture("GlowMap", outTarget); + } else { + extractMat.clearParam("GlowMap"); + } + // extraction + extractMat.setFloat("ExposurePow", exposurePower); + extractMat.setFloat("ExposureCutoff", exposureCutOff); + extractMat.setBoolean("Extract", scene != null); + if (scene != null) { + extractMat.setTexture("Texture", scene); + } else { + extractMat.clearParam("Texture"); + } + render(context, midFb, extractMat); + // horizontal blur + hBlurMat.setTexture("Texture", midTarget); + hBlurMat.setFloat("Size", context.getWidth()); + hBlurMat.setFloat("Scale", blurScale); + render(context, outFb, hBlurMat); + // vertical blur + vBlurMat.setTexture("Texture", outTarget); + vBlurMat.setFloat("Size", context.getHeight()); + vBlurMat.setFloat("Scale", blurScale); + render(context, midFb, vBlurMat); + // final output + outMat.setTexture("Texture", scene); + outMat.setTexture("BloomTex", midTarget); + render(context, outFb, outMat); + resources.release(midTex); + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule oc = ex.getCapsule(this); + oc.write(blurScale, "blurScale", 1.5f); + oc.write(exposurePower, "exposurePower", 5.0f); + oc.write(exposureCutOff, "exposureCutOff", 0.0f); + oc.write(bloomIntensity, "bloomIntensity", 2.0f); + oc.write(downSamplingFactor, "downSamplingFactor", 1); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule ic = im.getCapsule(this); + blurScale = ic.readFloat("blurScale", 1.5f); + exposurePower = ic.readFloat("exposurePower", 5.0f); + exposureCutOff = ic.readFloat("exposureCutOff", 0.0f); + bloomIntensity = ic.readFloat("bloomIntensity", 2.0f); + downSamplingFactor = ic.readFloat("downSamplingFactor", 1); + } + + private void render(FGRenderContext context, FrameBuffer fb, Material mat) { + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + context.renderFullscreen(mat); + } + + /** + * returns the bloom intensity + * @return the intensity value + */ + public float getBloomIntensity() { + return bloomIntensity; + } + + /** + * intensity of the bloom effect default is 2.0 + * + * @param bloomIntensity the desired intensity (default=2) + */ + public void setBloomIntensity(float bloomIntensity) { + this.bloomIntensity = bloomIntensity; + } + + /** + * returns the blur scale + * @return the blur scale + */ + public float getBlurScale() { + return blurScale; + } + + /** + * sets The spread of the bloom default is 1.5f + * + * @param blurScale the desired scale (default=1.5) + */ + public void setBlurScale(float blurScale) { + this.blurScale = blurScale; + } + + /** + * returns the exposure cutoff
      + * for more details see {@link #setExposureCutOff(float exposureCutOff)} + * @return the exposure cutoff + */ + public float getExposureCutOff() { + return exposureCutOff; + } + + /** + * Define the color threshold on which the bloom will be applied (0.0 to 1.0) + * + * @param exposureCutOff the desired threshold (≥0, ≤1, default=0) + */ + public void setExposureCutOff(float exposureCutOff) { + this.exposureCutOff = exposureCutOff; + } + + /** + * returns the exposure power
      + * for more details see {@link #setExposurePower(float exposurePower)} + * @return the exposure power + */ + public float getExposurePower() { + return exposurePower; + } + + /** + * defines how many times the bloom extracted color will be multiplied by itself. default is 5.0
      + * a high value will reduce rough edges in the bloom and somehow the range of the bloom area + * + * @param exposurePower the desired exponent (default=5) + */ + public void setExposurePower(float exposurePower) { + this.exposurePower = exposurePower; + } + + /** + * returns the downSampling factor
      + * for more details see {@link #setDownSamplingFactor(float downSamplingFactor)} + * @return the downsampling factor + */ + public float getDownSamplingFactor() { + return downSamplingFactor; + } + + /** + * Sets the downSampling factor : the size of the computed texture will be divided by this factor. default is 1 for no downsampling + * A 2 value is a good way of widening the blur + * + * @param downSamplingFactor the desired factor (default=1) + */ + public void setDownSamplingFactor(float downSamplingFactor) { + this.downSamplingFactor = downSamplingFactor; + } + +} diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java index 40c0ebad56..e25a942965 100644 --- a/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java @@ -56,6 +56,7 @@ protected void initialize(FrameGraph frameGraph) { @Override protected void prepare(FGRenderContext context) { declare(texDef, result); + reserve(result); reference(color, depth, normals); texDef.setSize(context.getWidth(), context.getHeight()); } diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java index d1be95d4e5..67a710c394 100644 --- a/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java @@ -48,6 +48,7 @@ protected void initialize(FrameGraph frameGraph) { @Override protected void prepare(FGRenderContext context) { declare(texDef, result); + reserve(result); reference(color, depth); texDef.setSize(context.getWidth(), context.getHeight()); material.setFloat("XScale", blurScale/context.getWidth()); @@ -66,7 +67,9 @@ protected void execute(FGRenderContext context) { @Override protected void reset(FGRenderContext context) {} @Override - protected void cleanup(FrameGraph frameGraph) {} + protected void cleanup(FrameGraph frameGraph) { + material = null; + } @Override public void write(JmeExporter ex) throws IOException { super.write(ex); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 9faa09c8be..39197bebba 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -662,11 +662,11 @@ public void simpleInitApp() { //guiViewPort.setEnabled(false); //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - FrameGraph forward = new FrameGraph(assetManager, "Common/FrameGraphs/Forward.j3g"); - forward.setName("forward"); + //FrameGraph forward = new FrameGraph(assetManager, "Common/FrameGraphs/Forward.j3g"); + //forward.setName("forward"); //FrameGraph deferred = new FrameGraph(assetManager, "Common/FrameGraphs/Deferred.j3g"); - FrameGraph deferred = FrameGraphFactory.deferred(assetManager, false); - deferred.setName("deferred1"); + FrameGraph deferred = FrameGraphFactory.deferred(assetManager, true); + deferred.setName("deferred"); //FrameGraph deferred2 = FrameGraphFactory.deferred(assetManager, false); //deferred2.setName("deferred2"); //FrameGraph graph = FrameGraphFactory.forward(assetManager, renderManager); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java deleted file mode 100644 index 22756fa1b2..0000000000 --- a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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() { - - - - } - -} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java new file mode 100644 index 0000000000..048f6446a3 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java @@ -0,0 +1,105 @@ +/* + * 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; +import com.jme3.environment.EnvironmentProbeControl; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +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.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.FrameGraphFactory; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.RectangleMesh; +import com.jme3.system.AppSettings; + +/** + * + * @author codex + */ +public class Main extends SimpleApplication { + + private final boolean pbr = true; + + public static void main(String[] args) { + Main app = new Main(); + AppSettings settings = new AppSettings(true); + settings.setWidth(768); + settings.setHeight(768); + app.setSettings(settings); + app.start(); + } + + @Override + public void simpleInitApp() { + + //stateManager.attach(new DetailedProfilerState()); + + FrameGraph deferred = FrameGraphFactory.deferred(assetManager, false); + deferred.setJunctionSetting("LightPackMethod", true); + //viewPort.setFrameGraph(deferred); + + // set camera move speed + flyCam.setMoveSpeed(30); + flyCam.setDragToRotate(true); + viewPort.setBackgroundColor(ColorRGBA.White.mult(0.05f)); + + // add a large floor to the scene + RectangleMesh floorMesh = new RectangleMesh( + new Vector3f(-100, 0, -100), new Vector3f(100, 0, -100), new Vector3f(-100, 0, 100)); + floorMesh.flip(); + Geometry floor = new Geometry("Floor", floorMesh); + floor.setLocalTranslation(0, -5, 0); + Material mat = createMaterial(ColorRGBA.White); + floor.setMaterial(mat); + rootNode.attachChild(floor); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(1, -1, 1)); + //rootNode.addLight(dl); + + // add a lot of boxes to the scene + for (int i = 0; i < 500; i++) { + Geometry box = new Geometry("Box", new Box(1, 1, 1)); + box.setLocalTranslation(FastMath.rand.nextFloat(-100, 100), 0, FastMath.rand.nextFloat(-100, 100)); + box.setMaterial(createMaterial(ColorRGBA.White)); + rootNode.attachChild(box); + EnvironmentProbeControl.tagGlobal(box); + } + + // add some lights to the scene + for (int i = 0; i < 100; i++) { + PointLight pl = new PointLight(); + pl.setPosition(new Vector3f(FastMath.rand.nextFloat(-100, 100), 5, FastMath.rand.nextFloat(-100, 100))); + pl.setRadius(100); + pl.setColor(ColorRGBA.randomColor()); + rootNode.addLight(pl); + } + + //rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); + //rootNode.addLight(new AmbientLight(ColorRGBA.White.mult(0f))); + + } + + private Material createMaterial(ColorRGBA color) { + if (pbr) { + Material mat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md"); + mat.setColor("BaseColor", color); + mat.setFloat("Metallic", 1.0f); + return mat; + } else { + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Diffuse", color); + return mat; + } + } + +} From eb67e8e3d5cb4ebfed8c140a9bcdd113c73f4ebd Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sun, 23 Jun 2024 07:49:27 -0400 Subject: [PATCH 092/111] fixed functional array issues --- .../renderer/framegraph/FrameGraphData.java | 4 +- .../renderer/framegraph/ResourceList.java | 22 ++-- .../framegraph/light/TiledRenderGrid.java | 6 +- .../framegraph/passes/BucketPass.java | 66 +++++----- .../ShadingCommon/DeferredShading.frag | 4 +- .../jme3test/renderpath/sandbox/Main.java | 121 +++++++++--------- 6 files changed, 116 insertions(+), 107 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java index bf2ce78120..2e144c9fae 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java @@ -69,7 +69,7 @@ public FrameGraphData() { } public FrameGraphData(FrameGraph fg, Collection passes, Map settings) { this.name = fg.getName(); - this.passes = passes.toArray(RenderPass[]::new); + this.passes = passes.toArray(new RenderPass[0]); this.settings = new HashMap<>(); for (String key : settings.keySet()) { this.settings.put(key, new SavableObject(settings.get(key))); @@ -103,7 +103,7 @@ public void write(JmeExporter ex) throws IOException { OutputCapsule out = ex.getCapsule(this); out.write(name, "name", DEF_NAME); out.write(passes, "passes", DEF_PASSES); - out.write(list.toArray(SavablePassConnection[]::new), "connections", DEF_CONNECTIONS); + out.write(list.toArray(new SavablePassConnection[0]), "connections", DEF_CONNECTIONS); out.writeStringSavableMap(settings, "settings", DEF_SETTINGS); // reset export ids for (RenderPass p : passes) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 0bd1598b6c..b00f27ebbf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -455,15 +455,21 @@ public T acquireColorTarget(FrameBuffer fbo, ResourceTicket< return replaceColorTarget(fbo, ticket, 0); } private T replaceColorTarget(FrameBuffer fbo, ResourceTicket ticket, int i) { - Texture existing = fbo.getColorTarget(i).getTexture(); - T acquired = acquire(ticket); - if (acquired != existing) { - fbo.setColorTarget(i, FrameBuffer.target(acquired)); - fbo.setUpdateNeeded(); - if (cap != null) cap.bindTexture(ticket.getWorldIndex(), ticket.getName()); - textureBinds++; + if (i < fbo.getNumColorTargets()) { + Texture existing = fbo.getColorTarget(i).getTexture(); + T acquired = acquire(ticket); + if (acquired != existing) { + fbo.setColorTarget(i, FrameBuffer.target(acquired)); + fbo.setUpdateNeeded(); + if (cap != null) cap.bindTexture(ticket.getWorldIndex(), ticket.getName()); + textureBinds++; + } + return acquired; + } else { + T acquired = acquire(ticket); + fbo.addColorTarget(FrameBuffer.target(acquired)); + return acquired; } - return acquired; } /** * Acquires and assigns a texture as the depth target to the framebuffer. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java index 876a192f4e..29a2e48fbd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java @@ -46,7 +46,7 @@ public class TiledRenderGrid implements Savable { private int divisions = 4; - private int forcedTileSize = 128; //64 + private int forcedTileSize = 64; //64 private int tileSize = 0; private int gridWidth = 0; private int gridHeight = 0; @@ -55,6 +55,10 @@ public TiledRenderGrid() {} public TiledRenderGrid(int divisions) { this.divisions = divisions; } + public TiledRenderGrid(int divisions, int forcedTileSize) { + this.divisions = divisions; + this.forcedTileSize = forcedTileSize; + } public void update(Camera cam) { tileSize = (forcedTileSize > 0 ? forcedTileSize : cam.getWidth()/divisions); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 945ba16a83..14a99358a3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -35,13 +35,13 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.material.RenderState; import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; @@ -55,32 +55,28 @@ */ public class BucketPass extends RenderPass { - private Bucket bucket; private final DepthRange depth = new DepthRange(); - private int samples = 1; - private boolean flush = true; private ResourceTicket inColor, inDepth, outColor, outDepth; + private ResourceTicket geometry; private TextureDef colorDef, depthDef; - private Texture2D depthTex; + private boolean perspective; public BucketPass() { - this(Bucket.Opaque, DepthRange.IDENTITY); + this(DepthRange.IDENTITY, true); } - public BucketPass(Bucket bucket) { - this(bucket, DepthRange.IDENTITY); + public BucketPass(DepthRange depth) { + this(depth, true); } - public BucketPass(Bucket bucket, DepthRange depth) { - this.bucket = bucket; + public BucketPass(DepthRange depth, boolean perspective) { this.depth.set(depth); - if (this.bucket == Bucket.Inherit) { - throw new IllegalArgumentException("Rendered bucket cannot be Inherit."); - } + this.perspective = perspective; } @Override protected void initialize(FrameGraph frameGraph) { inColor = addInput("Color"); inDepth = addInput("Depth"); + geometry = addInput("Geometry"); outColor = addOutput("Color"); outDepth = addOutput("Depth"); colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); @@ -97,24 +93,24 @@ protected void prepare(FGRenderContext context) { declare(colorDef, outColor); declare(depthDef, outDepth); reserve(outColor, outDepth); + reference(geometry); referenceOptional(inColor, inDepth); } @Override protected void execute(FGRenderContext context) { FrameBuffer fb = getFrameBuffer(context, 1); - resources.acquireColorTargets(fb, outColor); - depthTex = resources.acquireDepthTarget(fb, outDepth); - System.out.println(fb.getDepthTarget()); + resources.acquireColorTarget(fb, outColor); + resources.acquireDepthTarget(fb, outDepth); context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); context.renderTextures(resources.acquireOrElse(inColor, null), resources.acquireOrElse(inDepth, null)); context.getRenderer().setDepthRange(depth); - if (bucket == Bucket.Gui) { + if (!perspective) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); } - context.renderViewPortQueue(bucket, flush); - if (bucket == Bucket.Gui) { + context.renderGeometryList(resources.acquire(geometry), null, null); + if (!perspective) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); } } @@ -123,29 +119,18 @@ protected void reset(FGRenderContext context) {} @Override protected void cleanup(FrameGraph frameGraph) {} @Override - public String getProfilerName() { - return super.getProfilerName()+"["+bucket+"]"; - } - @Override public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule out = ex.getCapsule(this); - out.write(bucket, "bucket", Bucket.Opaque); out.write(depth, "depth", DepthRange.IDENTITY); - out.write(samples, "samples", 1); - out.write(flush, "flush", true); + out.write(perspective, "perspective", true); } @Override public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule in = im.getCapsule(this); - bucket = in.readEnum("bucket", Bucket.class, Bucket.Opaque); depth.set(in.readSavable("depth", DepthRange.class, DepthRange.IDENTITY)); - samples = in.readInt("samples", 1); - flush = in.readBoolean("flush", true); - if (samples <= 0) { - throw new IllegalArgumentException("Samples must be greater than zero."); - } + perspective = in.readBoolean("perspective", true); } /** @@ -166,9 +151,20 @@ public DepthRange getDepthRange() { return depth; } - @Override - public String toString() { - return "BucketPass["+bucket+"]"; + /** + * + * @param perspective + */ + public void setPerspective(boolean perspective) { + this.perspective = perspective; + } + + /** + * + * @return + */ + public boolean isPerspective() { + return perspective; } } 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 79a008174d..61ac2828dc 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -274,9 +274,9 @@ void main(){ gl_FragColor.rgb += emissive; gl_FragColor.a = alpha; - } /*else if (shadingModelId == SUBSURFACE_SCATTERING) { + } else if (shadingModelId == SUBSURFACE_SCATTERING) { // TODO: implement subsurface scattering - }*/ else if (shadingModelId == UNLIT) { + } else if (shadingModelId == UNLIT) { // unlit shading gl_FragColor.rgb = shadingInfo.rgb; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java index 048f6446a3..aee0824850 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java @@ -4,20 +4,20 @@ */ package jme3test.renderpath.sandbox; +import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; -import com.jme3.environment.EnvironmentProbeControl; -import com.jme3.light.AmbientLight; -import com.jme3.light.DirectionalLight; 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.framegraph.CartoonEdgePass; +import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.FrameGraphFactory; +import com.jme3.renderer.framegraph.passes.BucketPass; +import com.jme3.renderer.framegraph.passes.OutputPass; +import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; -import com.jme3.scene.shape.RectangleMesh; import com.jme3.system.AppSettings; /** @@ -25,9 +25,7 @@ * @author codex */ public class Main extends SimpleApplication { - - private final boolean pbr = true; - + public static void main(String[] args) { Main app = new Main(); AppSettings settings = new AppSettings(true); @@ -40,66 +38,71 @@ public static void main(String[] args) { @Override public void simpleInitApp() { - //stateManager.attach(new DetailedProfilerState()); + FrameGraph frameGraph = new FrameGraph(assetManager); + + SceneEnqueuePass enqueue = frameGraph.add(new SceneEnqueuePass()); + BucketPass opaque = frameGraph.add(new BucketPass()); + BucketPass sky = frameGraph.add(new BucketPass(DepthRange.REAR)); + BucketPass transparent = frameGraph.add(new BucketPass()); + BucketPass gui = frameGraph.add(new BucketPass(DepthRange.FRONT, false)); + BucketPass translucent = frameGraph.add(new BucketPass()); + OutputPass output = frameGraph.add(new OutputPass()); + + opaque.makeInput(enqueue, "Opaque", "Geometry"); + + sky.makeInput(opaque, "Color", "Color"); + sky.makeInput(opaque, "Depth", "Depth"); + sky.makeInput(enqueue, "Sky", "Geometry"); - FrameGraph deferred = FrameGraphFactory.deferred(assetManager, false); - deferred.setJunctionSetting("LightPackMethod", true); - //viewPort.setFrameGraph(deferred); + transparent.makeInput(sky, "Color", "Color"); + transparent.makeInput(sky, "Depth", "Depth"); + transparent.makeInput(enqueue, "Transparent", "Geometry"); - // set camera move speed - flyCam.setMoveSpeed(30); + gui.makeInput(transparent, "Color", "Color"); + gui.makeInput(transparent, "Depth", "Depth"); + gui.makeInput(enqueue, "Gui", "Geometry"); + + translucent.makeInput(gui, "Color", "Color"); + translucent.makeInput(gui, "Depth", "Depth"); + translucent.makeInput(enqueue, "Translucent", "Geometry"); + + output.makeInput(translucent, "Color", "Color"); + output.makeInput(translucent, "Depth", "Depth"); + + viewPort.setFrameGraph(frameGraph); + + // setup camera flyCam.setDragToRotate(true); - viewPort.setBackgroundColor(ColorRGBA.White.mult(0.05f)); - - // add a large floor to the scene - RectangleMesh floorMesh = new RectangleMesh( - new Vector3f(-100, 0, -100), new Vector3f(100, 0, -100), new Vector3f(-100, 0, 100)); - floorMesh.flip(); - Geometry floor = new Geometry("Floor", floorMesh); - floor.setLocalTranslation(0, -5, 0); - Material mat = createMaterial(ColorRGBA.White); - floor.setMaterial(mat); - rootNode.attachChild(floor); + flyCam.setMoveSpeed(20); - DirectionalLight dl = new DirectionalLight(); - dl.setDirection(new Vector3f(1, -1, 1)); - //rootNode.addLight(dl); + // setup background + viewPort.setBackgroundColor(ColorRGBA.White.mult(0.02f)); - // add a lot of boxes to the scene - for (int i = 0; i < 500; i++) { - Geometry box = new Geometry("Box", new Box(1, 1, 1)); - box.setLocalTranslation(FastMath.rand.nextFloat(-100, 100), 0, FastMath.rand.nextFloat(-100, 100)); - box.setMaterial(createMaterial(ColorRGBA.White)); - rootNode.attachChild(box); - EnvironmentProbeControl.tagGlobal(box); - } + // add a cube to the scene + Geometry cube = new Geometry("cube", new Box(1, 1, 1)); + Material mat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md"); + mat.setColor("BaseColor", ColorRGBA.White); + mat.setFloat("Metallic", 0.5f); + cube.setMaterial(mat); + rootNode.attachChild(cube); - // add some lights to the scene - for (int i = 0; i < 100; i++) { - PointLight pl = new PointLight(); - pl.setPosition(new Vector3f(FastMath.rand.nextFloat(-100, 100), 5, FastMath.rand.nextFloat(-100, 100))); - pl.setRadius(100); - pl.setColor(ColorRGBA.randomColor()); - rootNode.addLight(pl); - } + // add a light to the scene + PointLight pl = new PointLight(); + pl.setColor(ColorRGBA.White); + pl.setPosition(new Vector3f(2, 3, 3)); + pl.setRadius(20); + rootNode.addLight(pl); - //rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); - //rootNode.addLight(new AmbientLight(ColorRGBA.White.mult(0f))); + // profiler + DetailedProfilerState profiler = new DetailedProfilerState(); + profiler.setEnabled(false); + stateManager.attach(profiler); } - private Material createMaterial(ColorRGBA color) { - if (pbr) { - Material mat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md"); - mat.setColor("BaseColor", color); - mat.setFloat("Metallic", 1.0f); - return mat; - } else { - Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); - mat.setBoolean("UseMaterialColors", true); - mat.setColor("Diffuse", color); - return mat; - } + @Override + public void simpleUpdate(float tpf) { + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); } } From 09d4ebacb84a5095184b0978a8100224299e5c3f Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sun, 23 Jun 2024 08:08:29 -0400 Subject: [PATCH 093/111] fixed build errors --- .../com/jme3/anim/tween/action/Action.java | 26 +- .../jme3/anim/tween/action/BaseAction.java | 1 - .../environment/EnvironmentProbeControl.java | 2 +- .../SkyLightAndReflectionProbeRender.java | 3 +- ...eBasedDeferredSinglePassLightingLogic.java | 1017 ----------------- .../framegraph/passes/TileDeferredPass.java | 115 -- .../src/main/java/com/jme3/scene/Spatial.java | 2 +- .../shader/bufferobject/BufferObject.java | 2 +- 8 files changed, 19 insertions(+), 1149 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java diff --git a/jme3-core/src/main/java/com/jme3/anim/tween/action/Action.java b/jme3-core/src/main/java/com/jme3/anim/tween/action/Action.java index 344a69b216..55c2db1e08 100644 --- a/jme3-core/src/main/java/com/jme3/anim/tween/action/Action.java +++ b/jme3-core/src/main/java/com/jme3/anim/tween/action/Action.java @@ -38,13 +38,13 @@ /** * Wraps an array of Tween actions into an action object. - * *

      * Notes : - *

    • The sequence of tweens is determined by {@link com.jme3.anim.tween.Tweens} utility class and the {@link BaseAction} interpolates that sequence.
    • - *
    • This implementation mimics the {@link com.jme3.anim.tween.AbstractTween}, but it delegates the interpolation method {@link Tween#interpolate(double)} + *
        + *
      • The sequence of tweens is determined by {@link com.jme3.anim.tween.Tweens} utility class and the {@link BaseAction} interpolates that sequence.
      • + *
      • This implementation mimics the {@link com.jme3.anim.tween.AbstractTween}, but it delegates the interpolation method {@link Tween#interpolate(double)} * to the {@link BlendableAction} class.
      • - *

        + *
      * * Created by Nehon. * @@ -66,10 +66,11 @@ public abstract class Action implements JmeCloneable, Tween { * Instantiates an action object that wraps a tween actions array by extracting their actions to the collection {@link Action#actions}. *

      * Notes : - *

    • If intentions are to wrap some tween actions, then subclasses have to call this constructor, examples : {@link BlendableAction} and {@link BlendAction}.
    • - *
    • If intentions are to make an implementation of {@link Action} that shouldn't wrap tweens of actions, then subclasses shouldn't call this + *
        + *
      • If intentions are to wrap some tween actions, then subclasses have to call this constructor, examples : {@link BlendableAction} and {@link BlendAction}.
      • + *
      • If intentions are to make an implementation of {@link Action} that shouldn't wrap tweens of actions, then subclasses shouldn't call this * constructor, examples : {@link ClipAction} and {@link BaseAction}.
      • - *

        + *
      * * @param tweens the tween actions to be wrapped (not null). */ @@ -119,11 +120,12 @@ public double getSpeed() { * Alters the speedup factor applied by the layer running this action. *

      * Notes: - *

    • This factor controls the animation direction, if the speed is a positive value then the animation will run forward and vice versa.
    • - *
    • The speed factor gets applied, inside the {@link com.jme3.anim.AnimLayer}, on each interpolation step by this formula : time += tpf * action.getSpeed() * composer.globalSpeed.
    • - *
    • Default speed is 1.0, it plays the animation clips at their normal speed.
    • - *
    • Setting the speed factor to Zero will stop the animation, while setting it to a negative number will play the animation in a backward fashion.
    • - *

      + *
        + *
      • This factor controls the animation direction, if the speed is a positive value then the animation will run forward and vice versa.
      • + *
      • The speed factor gets applied, inside the {@link com.jme3.anim.AnimLayer}, on each interpolation step by this formula : time += tpf * action.getSpeed() * composer.globalSpeed.
      • + *
      • Default speed is 1.0, it plays the animation clips at their normal speed.
      • + *
      • Setting the speed factor to Zero will stop the animation, while setting it to a negative number will play the animation in a backward fashion.
      • + *
      * * @param speed the speed of frames. */ diff --git a/jme3-core/src/main/java/com/jme3/anim/tween/action/BaseAction.java b/jme3-core/src/main/java/com/jme3/anim/tween/action/BaseAction.java index edc819f7ff..928c168bc0 100644 --- a/jme3-core/src/main/java/com/jme3/anim/tween/action/BaseAction.java +++ b/jme3-core/src/main/java/com/jme3/anim/tween/action/BaseAction.java @@ -55,7 +55,6 @@ * //run the action within this layer * animComposer.setCurrentAction("basicAction", ActionState.class.getSimpleName()); * - *

      * Created by Nehon. */ public class BaseAction extends Action { diff --git a/jme3-core/src/main/java/com/jme3/environment/EnvironmentProbeControl.java b/jme3-core/src/main/java/com/jme3/environment/EnvironmentProbeControl.java index d07a039995..9f685d5987 100644 --- a/jme3-core/src/main/java/com/jme3/environment/EnvironmentProbeControl.java +++ b/jme3-core/src/main/java/com/jme3/environment/EnvironmentProbeControl.java @@ -65,7 +65,7 @@ * ec1.setPosition(new Vector3f(0,0,0)); * // ec2.setPosition(new Vector3f(0,0,10)); * 3. Tag the spatials that are part of the environment - * scene.deepFirstTraversal(s->{ + * scene.deepFirstTraversal(s -> { * if(s.getUserData("isEnvNode")!=null){ * EnvironmentProbeControl.tagGlobal(s); * // or ec1.tag(s); 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 c51f30918d..4972452df3 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 @@ -46,7 +46,8 @@ import java.util.List; /** - * Rendering logic for handling SkyLight and ReflectionProbe.
      + * 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 */ 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 deleted file mode 100644 index 14a0fbbadd..0000000000 --- a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java +++ /dev/null @@ -1,1017 +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.material.logic; - -import com.jme3.renderer.framegraph.light.TiledRenderGrid; -import com.jme3.asset.AssetManager; -import com.jme3.light.*; -import com.jme3.material.Material.BindUnits; -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; - -/** - * 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{ - - private final static String LIGHT_CULL_DRAW_STAGE = "Light_Cull_Draw_Stage"; - private final static String TILE_SIZE = "g_TileSize"; - private final static String TILE_WIDTH = "g_WidthTile"; - private final static String 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"; - // 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 packAsTextures = true; - // Use textures to store large amounts of light data at once, avoiding multiple draw calls - private Texture2D lightData1; - private Texture2D lightData2; - private Texture2D lightData3; - private ImageRaster lightDataUpdateIO1; - 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); - - 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; - private final int useAmbientLightDefineId; - - - - // temp var - private Matrix4f vp; - private float camLeftCoeff = -1; - private float camTopCoeff = -1; - private float viewPortWidth = -1; - private float viewPortHeight = -1; - private final float[] matArray1 = new float[16]; - private final Vector3f tempVec3 = new Vector3f(); - private final Vector3f tempVec3_2 = new Vector3f(); - private final Vector4f tempVec4 = new Vector4f(); - private final Vector4f tempvec4_2 = new Vector4f(); - private final Vector4f tempVec4_3 = new Vector4f(); - private final Vector4f camUp = new Vector4f(); - private final Vector4f camLeft = new Vector4f(); - private final Vector4f lightLeft = new Vector4f(); - private final Vector4f lightUp = new Vector4f(); - private final Vector4f lightCenter = new Vector4f(); - private final LightFrustum _lightFrustum = new LightFrustum(0, 0, 0, 0); - - // tile info - private final TiledRenderGrid tileInfo; - private final TiledRenderGrid prevTileInfo = new TiledRenderGrid(); - private int maxLights = 1024; - private boolean updateLightDataFlag = true; - - // 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; - - /** - * 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; - 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; - } - } - - public TileBasedDeferredSinglePassLightingLogic(TechniqueDef techniqueDef, TiledRenderGrid tileInfo) { - super(techniqueDef); - this.tileInfo = tileInfo; - lightIndexWidth = (int)(Math.floor(Math.sqrt(1024))); - singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean); - if(packAsTextures){ - packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int); - packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean); - prepareLightData(1024); - } - else{ - 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); - } - - /** - * Clear the lightsIndex cache texture for rebuilding. - */ - private void cleanupLightsIndexTexture(){ - if(lightsIndexData != null){ - lightsIndexData.getImage().dispose(); - lightsIndexData = null; - } - } - - /** - * 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); - 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()); - } - - /** - * Clear the lightsDecode cache texture for rebuilding. - */ - private void cleanupLightsDecodeTexture(){ - if(lightsDecodeData != null){ - lightsDecodeData.getImage().dispose(); - lightsDecodeData = null; - } - } - - /** - * Clear the lightsIndex and lightsDecode cache texture for rebuilding. - */ - private void cleanupTileTexture(){ - cleanupLightsIndexTexture(); - cleanupLightsDecodeTexture(); - } - - /** - * 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() { - if (tileInfo.gridDemensionsDiffer(prevTileInfo)) { - cleanupTileTexture(); - createLightsIndexTexture(lightIndexWidth); - lightsDecodeData = new Texture2D(tileInfo.getGridHeight(), tileInfo.getGridHeight(), 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) * tileInfo.getNumTiles()); - Image convertedImageU = new Image(Image.Format.RGBA32F, tileInfo.getGridWidth(), tileInfo.getGridHeight(), dataU, null, ColorSpace.Linear); - lightsDecodeData.setImage(convertedImageU); - lightsDecodeData.getImage().setMipmapsGenerated(false); - lightsDecodeDataUpdateIO = ImageRaster.create(lightsDecodeData.getImage()); - } - if (tileInfo.numTilesDiffer(prevTileInfo)) { - tiles = new ArrayList<>(); - for (int i = 0, n = tileInfo.getNumTiles(); i < n; i++) { - tiles.add(new ArrayList<>()); - } - } else for (ArrayList l : tiles) { - l.clear(); - } - if (lightsDecode == null) { - lightsDecode = new ArrayList<>(); - } else { - lightsDecode.clear(); - } - if (lightsIndex == null) { - lightsIndex = new ArrayList<>(); - } else { - 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; - 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); - } - } - } - } - - /** - * 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 - //⬆ - //| - //| - //----------➡ - // 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); - } - } - } - } - - /** - * 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; - 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; - } - - /** - * 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){ - 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; - } - - /** - * 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(); - - 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)); - if(lightIndexWidth > this.lightIndexWidth){ - // recreate - cleanupLightsIndexTexture(); - // 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. - // 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); - 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); - } - } - // 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); - 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); - } - - 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(); - } - } - - /** - * 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); - 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()); - -// 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 - public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, - EnumSet rendererCaps, LightList lights, DefineList defines) { - if(packAsTextures){ - 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) { - useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, false); - defines.set(nbSkyLightAndReflectionProbesDefineId, skyLightAndReflectionProbes.size()); - defines.set(useAmbientLightDefineId, useAmbientLight); - } - 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; - } - - 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, 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; - int skips = 0; - 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; - } - // check that the number of visible lights does not exceed the maximum - if (curIndex >= lightNum) { - throw new IllegalStateException("Number of lights exceeded specified maximum of "+lightNum+"."); - } - 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()); - } - } - 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(); - 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, 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, BindUnits lastBindUnit) { - int renderedLights = 0; - Renderer renderer = renderManager.getRenderer(); - boolean isLightCullStageDraw = false; - if(geometry.getUserData(LIGHT_CULL_DRAW_STAGE) != null){ - isLightCullStageDraw = geometry.getUserData(LIGHT_CULL_DRAW_STAGE); - } - if(packAsTextures){ - if(updateLightDataFlag){ - cleanupLightData(); - prepareLightData(maxLights); - updateLightDataFlag = false; - } - 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"); -// 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) { - - // get render grid info - tileInfo.verifyUpdated(); - shader.getUniform(TILE_SIZE).setValue(VarType.Int, tileInfo.getTileSize()); - shader.getUniform(TILE_WIDTH).setValue(VarType.Int, tileInfo.getGridWidth()); - shader.getUniform(TILE_HEIGHT).setValue(VarType.Int, tileInfo.getGridHeight()); - reset(); - prevTileInfo.copyFrom(tileInfo); - - 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 - LightFrustum lightFrustum; - 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(tileInfo.getTileSize(), tileInfo.getGridWidth(), tileInfo.getGridHeight(), tileInfo.getNumTiles(), tiles, lightFrustum, i); - } else { - // full tilesLight - tilesFullUpdate(tileInfo.getGridWidth(), tileInfo.getGridHeight(), tileInfo.getNumTiles(), tiles, i); - } - } - - // Encode light source information - //lightCount.setValue(VarType.Int, count); - //geometry.getMaterial().setInt("NBLight", count); - tileLightDecode(tileInfo.getNumTiles(), tiles, tileInfo.getGridWidth(), tileInfo.getGridHeight(), shader, geometry, lights); - while (renderedLights < count) { - renderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, renderedLights, isLightCullStageDraw, lastBindUnit.textureUnit); - renderer.setShader(shader); - renderMeshFromGeometry(renderer, geometry); - } - } else { - //geometry.getMaterial().setInt("NBLight", 0); - renderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, renderedLights, isLightCullStageDraw, lastBindUnit.textureUnit); - 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 (renderedLights < lights.size()) { - renderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, renderedLights, isLightCullStageDraw); - renderer.setShader(shader); - renderMeshFromGeometry(renderer, geometry); - } - } - } - } - - public void setMaxLights(int maxLights) { - if (this.maxLights != maxLights) { - this.maxLights = maxLights; - updateLightDataFlag = true; - } - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java deleted file mode 100644 index 0e434ddac1..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/TileDeferredPass.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2024 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.passes; - -import com.jme3.light.LightList; -import com.jme3.material.Material; -import com.jme3.material.TechniqueDef; -import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic; -import com.jme3.renderer.framegraph.light.TiledRenderGrid; -import com.jme3.renderer.framegraph.FGRenderContext; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.ResourceTicket; -import com.jme3.renderer.framegraph.definitions.TextureDef; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture2D; - -/** - * Renders GBuffer information using tiled deferred lighting to a color texture. - * - * @author codex - */ -public class TileDeferredPass extends RenderPass { - - private ResourceTicket diffuse, specular, emissive, normal, depth, outColor; - private ResourceTicket lights; - private ResourceTicket tiles; - private TextureDef colorDef; - private Material material; - private final TiledRenderGrid tileInfo = new TiledRenderGrid(); - - @Override - protected void initialize(FrameGraph frameGraph) { - diffuse = addInput("Diffuse"); - specular = addInput("Specular"); - emissive = addInput("Emissive"); - normal = addInput("Normal"); - depth = addInput("Depth"); - outColor = addOutput("Color"); - lights = addInput("Lights"); - tiles = addInput("TileInfo"); - colorDef = new TextureDef<>(Texture2D.class, img -> new Texture2D(img)); - colorDef.setFormatFlexible(true); - material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md"); - material = material.clone(); - for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("TileBasedDeferredPass")) { - t.setLogic(new TileBasedDeferredSinglePassLightingLogic(t, tileInfo)); - } - } - @Override - protected void prepare(FGRenderContext context) { - colorDef.setSize(context.getWidth(), context.getHeight()); - declare(colorDef, outColor); - reserve(outColor); - reference(diffuse, specular, emissive, normal, depth); - referenceOptional(lights, tiles); - } - @Override - protected void execute(FGRenderContext context) { - FrameBuffer fb = getFrameBuffer(context, 1); - resources.acquireColorTargets(fb, outColor); - context.getRenderer().setFrameBuffer(fb); - context.getRenderer().clearBuffers(true, true, true); - TiledRenderGrid trg = resources.acquireOrElse(tiles, null); - if (trg != null) { - tileInfo.copyFrom(trg); - } - tileInfo.update(context.getViewPort().getCamera()); - material.setTexture("Context_InGBuff0", resources.acquire(diffuse)); - material.setTexture("Context_InGBuff1", resources.acquire(specular)); - material.setTexture("Context_InGBuff2", resources.acquire(emissive)); - material.setTexture("Context_InGBuff3", resources.acquire(normal)); - material.setTexture("Context_InGBuff4", resources.acquire(depth)); - material.selectTechnique("TileBasedDeferredPass", context.getRenderManager()); - LightList lightList = resources.acquireOrElse(lights, null); - if (lightList != null) { - context.getScreen().render(context.getRenderManager(), material, lightList); - } else { - context.renderFullscreen(material); - } - } - @Override - protected void reset(FGRenderContext context) {} - @Override - protected void cleanup(FrameGraph frameGraph) {} - -} 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 dea54b355c..1037325887 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Spatial.java +++ b/jme3-core/src/main/java/com/jme3/scene/Spatial.java @@ -436,7 +436,7 @@ public LightList getWorldLightList() { } /** - * set Current filterLight.
      + * Set Current filterLight. * @param filterLight */ public void setFilterLight(LightList filterLight){ diff --git a/jme3-core/src/main/java/com/jme3/shader/bufferobject/BufferObject.java b/jme3-core/src/main/java/com/jme3/shader/bufferobject/BufferObject.java index cb7a87b89d..d85081c1dc 100644 --- a/jme3-core/src/main/java/com/jme3/shader/bufferobject/BufferObject.java +++ b/jme3-core/src/main/java/com/jme3/shader/bufferobject/BufferObject.java @@ -306,7 +306,7 @@ public AccessHint getAccessHint() { /** * Set AccessHint to hint the renderer on how to access this data. * - * @param natureHint + * @param accessHint */ public void setAccessHint(AccessHint accessHint) { this.accessHint = accessHint; From 42f5ab68df404bbdf516d38e8ff25657ddc91a82 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sun, 23 Jun 2024 08:28:56 -0400 Subject: [PATCH 094/111] fixed depth of field filter import-export --- .../src/main/java/com/jme3/math/FastMath.java | 3 +-- .../framegraph/passes/RenderPass.java | 1 - .../bufferobject/layout/BufferLayout.java | 2 +- .../util/struct/StructStd140BufferObject.java | 8 +++---- .../jme3/post/filters/DepthOfFieldFilter.java | 22 +++++++++++++++++++ 5 files changed, 28 insertions(+), 8 deletions(-) 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 90c025d672..c0eacfdd5d 100644 --- a/jme3-core/src/main/java/com/jme3/math/FastMath.java +++ b/jme3-core/src/main/java/com/jme3/math/FastMath.java @@ -848,8 +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 float between min (inclusive) to - * max (inclusive). + * @return A random float between min (inclusive) to max (inclusive). */ public static float nextRandomFloat(float min, float max) { float f = (nextRandomFloat() * (max - min + 1.0f)) + min; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 0acf38b629..08bcfacac3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -941,7 +941,6 @@ public static String groupTicketName(String group, int i) { /** * * @param group - * @param i * @return */ public static String listTicketName(String group) { diff --git a/jme3-core/src/main/java/com/jme3/shader/bufferobject/layout/BufferLayout.java b/jme3-core/src/main/java/com/jme3/shader/bufferobject/layout/BufferLayout.java index 78198ad025..db8310ad66 100644 --- a/jme3-core/src/main/java/com/jme3/shader/bufferobject/layout/BufferLayout.java +++ b/jme3-core/src/main/java/com/jme3/shader/bufferobject/layout/BufferLayout.java @@ -85,7 +85,7 @@ protected ObjectSerializer getSerializer(Object obj) { /** * Register a serializer * - * @param type + * @param serializer */ protected void registerSerializer(ObjectSerializer serializer) { serializers.add(serializer); diff --git a/jme3-core/src/main/java/com/jme3/util/struct/StructStd140BufferObject.java b/jme3-core/src/main/java/com/jme3/util/struct/StructStd140BufferObject.java index 4529239865..269009a960 100644 --- a/jme3-core/src/main/java/com/jme3/util/struct/StructStd140BufferObject.java +++ b/jme3-core/src/main/java/com/jme3/util/struct/StructStd140BufferObject.java @@ -56,15 +56,15 @@ public class StructStd140BufferObject extends BufferObject { private final Std140Layout std140 = new Std140Layout(); /** - * Create an empty Struct buffer - * - * @param str + * Create an empty Struct buffer. */ public StructStd140BufferObject() { } /** - * Internal only + * Internal only. + * + * @param id */ public StructStd140BufferObject(int id) { super(id); diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java index b4de8ce3e5..31b708a84d 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java @@ -95,7 +95,29 @@ protected void initFilter(AssetManager assets, RenderManager renderManager, material.setFloat("XScale", blurScale * xScale); material.setFloat("YScale", blurScale * yScale); } + + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + out.write(focusDistance, "focusDistance", 50f); + out.write(focusRange, "focusRange", 10f); + out.write(blurScale, "blurScale", 1f); + out.write(blurThreshold, "blurThreshold", 0.2f); + out.write(debugUnfocus, "debugUnfocus", false); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + focusDistance = in.readFloat("focusDistance", 50f); + focusRange = in.readFloat("focusRange", 10f); + blurScale = in.readFloat("blurScale", 1f); + blurThreshold = in.readFloat("blurThreshold", 0.2f); + debugUnfocus = in.readBoolean("debugUnfocus", false); + } + /** * Sets the distance at which objects are purely in focus. * From 1531f0fc0aeb3b1fed740816f5e0a772700631e6 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 24 Jun 2024 08:30:51 -0400 Subject: [PATCH 095/111] fixed deferred light probes --- .../framegraph/light/LightImagePacker.java | 2 +- .../framegraph/passes/DeferredPass.java | 25 +- .../framegraph/passes/LightImagePass.java | 2 +- .../MatDefs/Misc/UnshadedGBufferPack.frag | 4 +- .../ShadingCommon/DeferredShading.frag | 361 +++++++++--------- .../TerrainTestAdvancedRenderPath.java | 10 + .../renderpath/TestDeferredPBRShading.java | 28 +- .../TestSimpleDeferredLighting.java | 4 +- .../TerrainLightingGBufferPack.frag | 10 +- .../MatDefs/Terrain/TerrainLighting.j3md | 4 +- 10 files changed, 234 insertions(+), 216 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java index d9e4e6e554..b784744e3b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java @@ -53,7 +53,7 @@ public Texture2D getTexture(int i) { public int packLights(LightList lights, ColorRGBA ambient, List probes, Camera cam, TiledRenderGrid tileInfo) { - ambient.set(0, 0, 0, 1); + ambient.set(0, 0, 0, 0); probes.clear(); if (lights.size() == 0) { return 0; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 0be66ee8cc..9f3b995ab5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -77,6 +77,7 @@ public class DeferredPass extends RenderPass implements TechniqueDefLogic { private static Defines defs; private static final List localProbeList = new LinkedList<>(); public static final int MAX_BUFFER_LIGHTS = 341; + public static final int MAX_PROBES = 3; private boolean tiled = false; private AssetManager assetManager; @@ -189,13 +190,16 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager probeList = resources.acquire(probes); defines.set(defs.useTextures, true); defines.set(defs.numLights, resources.acquire(numLights)); + if (!ambientColor.equals(ColorRGBA.BlackNoAlpha)) { + defines.set(defs.useAmbientLight, true); + } if (tileTextures[0] != null) { defines.set(defs.useTiles, true); } } //defines.set(defs.numLights, 1); defines.set(defs.useAmbientLight, true); - defines.set(defs.numProbes, Math.min(probeList.size(), 3)); + defines.set(defs.numProbes, getNumReadyProbes(probeList)); return material.getActiveTechnique().getDef().getShader(assetManager, rendererCaps, defines); } @Override @@ -227,20 +231,35 @@ public void read(JmeImporter im) throws IOException { tiled = in.readBoolean("tiled", false); } + private int getNumReadyProbes(List probes) { + int n = 0; + if (probes == null) { + return n; + } + for (LightProbe p : probes) { + if (p.isEnabled() && p.isReady() && ++n == MAX_PROBES) { + break; + } + } + return n; + } + private void injectShaderGlobals(RenderManager rm, Shader shader, int lastTexUnit) { shader.getUniform("g_AmbientLightColor").setValue(VarType.Vector4, ambientColor); if (probeList != null && !probeList.isEmpty()) { int i = 0; // inject light probes for (LightProbe p : probeList) { + if (!p.isEnabled() || !p.isReady()) { + continue; + } String num = (++i > 1 ? String.valueOf(i) : ""); Uniform sky = shader.getUniform("g_SkyLightData"+num); Uniform coeffs = shader.getUniform("g_ShCoeffs"+num); Uniform env = shader.getUniform("g_ReflectionEnvMap"+num); lastTexUnit = SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData( rm, lastTexUnit, sky, coeffs, env, p); - // shaders only support up to 3 probes at once - if (i == 3) break; + if (i == MAX_PROBES) break; } } else { // disable light probes diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java index e68ae5586f..e5bc5acb06 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java @@ -44,7 +44,7 @@ public class LightImagePass extends RenderPass { private final LightTextureDef lightTexDef = new LightTextureDef(512); private final TileTextureDef tileDef = new TileTextureDef(); private final TileTextureDef indexDef = new TileTextureDef(); - private final ColorRGBA ambient = new ColorRGBA(); + private final ColorRGBA ambient = new ColorRGBA(0, 0, 0, 0); private final LinkedList probeList = new LinkedList<>(); @Override diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/UnshadedGBufferPack.frag b/jme3-core/src/main/resources/Common/MatDefs/Misc/UnshadedGBufferPack.frag index 0cbfdeb00c..3bda12aec3 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Misc/UnshadedGBufferPack.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/UnshadedGBufferPack.frag @@ -58,8 +58,8 @@ void main(){ color.rgb = vec3(mix(color.rgb, gray, m_DesaturationValue)); #endif - Context_OutGBuff2.rgb = color.rgb; + outGBuffer2.rgb = color.rgb; // shading model id - Context_OutGBuff2.a = UNLIT + color.a * 0.1f; + outGBuffer2.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 61ac2828dc..513f0cc9bf 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -22,19 +22,21 @@ uniform mat4 g_ViewMatrix; uniform vec3 g_CameraPosition; uniform int m_NBLights; -#ifdef USE_LIGHT_TEXTURES - uniform sampler2D m_LightTex1; - uniform sampler2D m_LightTex2; - uniform sampler2D m_LightTex3; - uniform float m_LightTexInv; - #ifdef TILED_LIGHTS - uniform sampler2D m_Tiles; - uniform sampler2D m_LightIndex; - uniform vec3 m_LightIndexSize; // x=width, yz=size inverse - #define TILES true +#if NB_LIGHTS > 0 + #ifdef USE_LIGHT_TEXTURES + uniform sampler2D m_LightTex1; + uniform sampler2D m_LightTex2; + uniform sampler2D m_LightTex3; + uniform float m_LightTexInv; + #ifdef TILED_LIGHTS + uniform sampler2D m_Tiles; + uniform sampler2D m_LightIndex; + uniform vec3 m_LightIndexSize; // x=width, yz=size inverse + #define TILES true + #endif + #else + uniform vec4 g_LightData[NB_LIGHTS]; #endif -#else - uniform vec4 g_LightData[NB_LIGHTS]; #endif @@ -64,90 +66,93 @@ void main(){ vec3 normal = texture2D(m_GBuffer3, innerTexCoord).xyz; vec3 viewDir = normalize(g_CameraPosition - vPos); gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; - gl_FragColor.a = alpha; - #ifdef TILES - // fetch index info from tile this fragment is contained by - vec4 tileInfo = texture2D(m_Tiles, innerTexCoord); - int x = int(tileInfo.x); - int y = int(tileInfo.y); - int componentIndex = int(tileInfo.z); - int lightCount = int(tileInfo.w); - vec4 lightIndex = vec4(-1.0); - for (int i = 0; i < lightCount;) { - #else - for (int i = 0; i < NB_LIGHTS;) { - #endif - #ifdef USE_LIGHT_TEXTURES - #ifdef TILED_LIGHTS - if (componentIndex == 0 || lightIndex.x < 0) { - // get indices from next pixel - lightIndex = texture2D(m_LightIndex, vec2(x, y) * m_LightIndexSize.yz); - } - // apply index from each component in order - vec2 pixel = vec2(m_LightTexInv, 0); - switch (componentIndex) { - case 0: pixel.x *= lightIndex.x; break; - case 1: pixel.x *= lightIndex.y; break; - case 2: pixel.x *= lightIndex.z; break; - case 3: pixel.x *= lightIndex.w; break; - } - // increment indices - componentIndex++; - if (componentIndex > 3) { - componentIndex = 0; - x++; - if (x >= m_LightIndexSize.x) { - x = 0; - y++; + //gl_FragColor.a = alpha; + gl_FragColor.a = 1.0; + #if NB_LIGHTS > 0 + #ifdef TILES + // fetch index info from tile this fragment is contained by + vec4 tileInfo = texture2D(m_Tiles, innerTexCoord); + int x = int(tileInfo.x); + int y = int(tileInfo.y); + int componentIndex = int(tileInfo.z); + int lightCount = int(tileInfo.w); + vec4 lightIndex = vec4(-1.0); + for (int i = 0; i < lightCount;) { + #else + for (int i = 0; i < NB_LIGHTS;) { + #endif + #ifdef USE_LIGHT_TEXTURES + #ifdef TILED_LIGHTS + if (componentIndex == 0 || lightIndex.x < 0) { + // get indices from next pixel + lightIndex = texture2D(m_LightIndex, vec2(x, y) * m_LightIndexSize.yz); + } + // apply index from each component in order + vec2 pixel = vec2(m_LightTexInv, 0); + switch (componentIndex) { + case 0: pixel.x *= lightIndex.x; break; + case 1: pixel.x *= lightIndex.y; break; + case 2: pixel.x *= lightIndex.z; break; + case 3: pixel.x *= lightIndex.w; break; } - } + // increment indices + componentIndex++; + if (componentIndex > 3) { + componentIndex = 0; + x++; + if (x >= m_LightIndexSize.x) { + x = 0; + y++; + } + } + #else + vec2 pixel = vec2(m_LightTexInv * i, 0); + #endif + vec4 lightColor = texture2D(m_LightTex1, pixel); + vec4 lightData1 = texture2D(m_LightTex2, pixel); #else - vec2 pixel = vec2(m_LightTexInv * i, 0); + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; #endif - vec4 lightColor = texture2D(m_LightTex1, pixel); - vec4 lightData1 = texture2D(m_LightTex2, pixel); - #else - vec4 lightColor = g_LightData[i]; - vec4 lightData1 = g_LightData[i+1]; - #endif - vec4 lightDir; - vec3 lightVec; - lightComputeDir(vPos, lightColor.w, lightData1, lightDir, lightVec); + 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 + float spotFallOff = 1.0; + #if __VERSION__ >= 110 + // allow use of control flow + if (lightColor.w > 1.0) { + #endif + #ifdef USE_LIGHT_TEXTURES + spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), 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); + + gl_FragColor.rgb += lightColor.rgb * diffuseColor.rgb * vec3(light.x) + + lightColor.rgb * specularColor.rgb * vec3(light.y); + #ifdef USE_LIGHT_TEXTURES - spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); + i++; #else - spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + i += 3; #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); - - gl_FragColor.rgb += lightColor.rgb * diffuseColor.rgb * vec3(light.x) + - lightColor.rgb * specularColor.rgb * vec3(light.y); - - #ifdef USE_LIGHT_TEXTURES - i++; - #else - i += 3; - #endif - } + #endif } else if (shadingModelId == PBR_LIGHTING) { @@ -170,110 +175,112 @@ void main(){ float ndotv = max( dot( normal, viewDir ),0.0); gl_FragColor.rgb = vec3(0.0); - #ifdef TILES - // fetch index info from tile this fragment is contained by - vec4 tileInfo = texture2D(m_Tiles, innerTexCoord); - int x = int(tileInfo.x); - int y = int(tileInfo.y); - int componentIndex = int(tileInfo.z); - int lightCount = int(tileInfo.w); - vec4 lightIndex = vec4(-1.0); - for (int i = 0; i < lightCount;) { - #else - for (int i = 0; i < NB_LIGHTS;) { - #endif - #ifdef USE_LIGHT_TEXTURES - #ifdef TILED_LIGHTS - if (componentIndex == 0 || lightIndex.x < 0) { - // get indices from next pixel - lightIndex = texture2D(m_LightIndex, vec2(x, y) * m_LightIndexSize.yz); - } - // apply index from each component in order - vec2 pixel = vec2(m_LightTexInv, 0); - switch (componentIndex) { - case 0: pixel.x *= lightIndex.x; break; - case 1: pixel.x *= lightIndex.y; break; - case 2: pixel.x *= lightIndex.z; break; - case 3: pixel.x *= lightIndex.w; break; - } - // increment indices - componentIndex++; - if (componentIndex > 3) { - componentIndex = 0; - x++; - if (x >= m_LightIndexSize.x) { - x = 0; - y++; + #if NB_LIGHTS > 0 + #ifdef TILES + // fetch index info from tile this fragment is contained by + vec4 tileInfo = texture2D(m_Tiles, innerTexCoord); + int x = int(tileInfo.x); + int y = int(tileInfo.y); + int componentIndex = int(tileInfo.z); + int lightCount = int(tileInfo.w); + vec4 lightIndex = vec4(-1.0); + for (int i = 0; i < lightCount;) { + #else + for (int i = 0; i < NB_LIGHTS;) { + #endif + #ifdef USE_LIGHT_TEXTURES + #ifdef TILED_LIGHTS + if (componentIndex == 0 || lightIndex.x < 0) { + // get indices from next pixel + lightIndex = texture2D(m_LightIndex, vec2(x, y) * m_LightIndexSize.yz); + } + // apply index from each component in order + vec2 pixel = vec2(m_LightTexInv, 0); + switch (componentIndex) { + case 0: pixel.x *= lightIndex.x; break; + case 1: pixel.x *= lightIndex.y; break; + case 2: pixel.x *= lightIndex.z; break; + case 3: pixel.x *= lightIndex.w; break; + } + // increment indices + componentIndex++; + if (componentIndex > 3) { + componentIndex = 0; + x++; + if (x >= m_LightIndexSize.x) { + x = 0; + y++; + } } - } + #else + vec2 pixel = vec2(m_LightTexInv * i, 0); + #endif + vec4 lightColor = texture2D(m_LightTex1, pixel); + vec4 lightData1 = texture2D(m_LightTex2, pixel); #else - vec2 pixel = vec2(m_LightTexInv * i, 0); + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; #endif - vec4 lightColor = texture2D(m_LightTex1, pixel); - vec4 lightData1 = texture2D(m_LightTex2, pixel); - #else - vec4 lightColor = g_LightData[i]; - vec4 lightData1 = g_LightData[i+1]; - #endif - - vec4 lightDir; - vec3 lightVec; - lightComputeDir(vPos, lightColor.w, lightData1, lightDir, lightVec); + + 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 USE_LIGHT_TEXTURES - spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); - #else - spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + float spotFallOff = 1.0; + #if __VERSION__ >= 110 + // allow use of control flow + if (lightColor.w > 1.0) { #endif - #if __VERSION__ >= 110 - } - #endif - spotFallOff *= lightDir.w; - - float radius = 1.0 / lightData1.w; - if (distance(vPos, lightData1.xyz) < radius) { - //gl_FragColor.rgb += lightColor.rgb * spotFallOff; - } + #if USE_LIGHT_TEXTURES + spotFallOff = computeSpotFalloff(texture2D(m_LightTex3, pixel), lightVec); + #else + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + #endif + #if __VERSION__ >= 110 + } + #endif + spotFallOff *= lightDir.w; + + float radius = 1.0 / lightData1.w; + if (distance(vPos, lightData1.xyz) < radius) { + //gl_FragColor.rgb += lightColor.rgb * spotFallOff; + } - #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 + #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; + vec3 directDiffuse; + vec3 directSpecular; - float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir, - lightColor.rgb, fZero, Roughness, ndotv, - directDiffuse, directSpecular); + float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir, + lightColor.rgb, fZero, Roughness, ndotv, + directDiffuse, directSpecular); - vec3 directLighting = diffuseColor.rgb * directDiffuse + directSpecular; - gl_FragColor.rgb += directLighting * spotFallOff; - - //gl_FragColor.rgb += directSpecular; - - #if USE_LIGHT_TEXTURES - i++; - #else - i += 3; - #endif - } + vec3 directLighting = diffuseColor.rgb * directDiffuse + directSpecular; + gl_FragColor.rgb += directLighting * spotFallOff; + + //gl_FragColor.rgb += directSpecular; + + #if USE_LIGHT_TEXTURES + i++; + #else + i += 3; + #endif + } + #endif // skyLight and reflectionProbe vec3 skyLight = renderSkyLightAndReflectionProbes( indoorSunLightExposure, viewDir, vPos, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao); gl_FragColor.rgb += skyLight; gl_FragColor.rgb += emissive; - gl_FragColor.a = alpha; - + //gl_FragColor.a = alpha; + gl_FragColor.a = 1.0; } else if (shadingModelId == SUBSURFACE_SCATTERING) { // TODO: implement subsurface scattering } else if (shadingModelId == UNLIT) { diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java index 56831d8eb9..6f391c1dd8 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java @@ -34,15 +34,18 @@ import com.jme3.app.SimpleApplication; import com.jme3.asset.TextureKey; import com.jme3.bounding.BoundingBox; +import com.jme3.environment.EnvironmentProbeControl; 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.material.Material; import com.jme3.material.TechniqueDef; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; +import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; @@ -93,6 +96,8 @@ public void initialize() { public void simpleInitApp() { setupKeys(); + viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, false)); + // First, we load up our textures and the heightmap texture for the terrain // TERRAIN TEXTURE material @@ -307,7 +312,12 @@ private void createSky() { Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg"); Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down); + EnvironmentProbeControl.tagGlobal(sky); rootNode.attachChild(sky); + + rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); + rootNode.addLight(new AmbientLight(ColorRGBA.White)); + } protected Node createAxisMarker(float arrowSize) { diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java index 645bf880a0..2b1fb42a96 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java @@ -1,17 +1,14 @@ 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.EnvironmentProbeControl; 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.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.FastMath; @@ -55,6 +52,8 @@ public void simpleInitApp() { rootNode.addLight(dl); dl.setColor(ColorRGBA.White); rootNode.attachChild(modelNode); + + rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray)); FilterPostProcessor fpp = new FilterPostProcessor(assetManager); int numSamples = context.getSettings().getSamples(); @@ -72,13 +71,12 @@ public void simpleInitApp() { //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); + EnvironmentProbeControl.tagGlobal(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); + rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); LightsDebugState debugState = new LightsDebugState(); stateManager.attach(debugState); @@ -152,20 +150,6 @@ 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) { diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 39197bebba..3616c0deee 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -665,13 +665,13 @@ public void simpleInitApp() { //FrameGraph forward = new FrameGraph(assetManager, "Common/FrameGraphs/Forward.j3g"); //forward.setName("forward"); //FrameGraph deferred = new FrameGraph(assetManager, "Common/FrameGraphs/Deferred.j3g"); - FrameGraph deferred = FrameGraphFactory.deferred(assetManager, true); + FrameGraph deferred = FrameGraphFactory.deferred(assetManager, false); deferred.setName("deferred"); //FrameGraph deferred2 = FrameGraphFactory.deferred(assetManager, false); //deferred2.setName("deferred2"); //FrameGraph graph = FrameGraphFactory.forward(assetManager, renderManager); viewPort.setFrameGraph(deferred); - guiViewPort.setFrameGraph(deferred); + //guiViewPort.setFrameGraph(deferred); //renderManager.setFrameGraph(deferred); //renderManager.setFrameGraph(forward); 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 index 92f1e6f231..b7d01aaa14 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag @@ -618,10 +618,10 @@ void main(){ //------------------------------- // 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; + outGBuffer3.xyz = normal; + outGBuffer0 = diffuseColor * DiffuseSum; + outGBuffer1.rgb = SpecularSum.rgb * 100.0f + AmbientSum.rgb * 0.01f; + outGBuffer1.a = m_Shininess; // shading model id - Context_OutGBuff2.a = LEGACY_LIGHTING; + outGBuffer2.a = PHONG_LIGHTING; } 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 ea31874abb..773eacb03a 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md @@ -243,9 +243,7 @@ MaterialDef Terrain Lighting { } } - Technique GBufferPass{ - - Pipeline Deferred + Technique GBufferPass { VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.vert FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag From b2424bc7b60c8bd3d14772f77cbfef2df061c824 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 24 Jun 2024 09:57:06 -0400 Subject: [PATCH 096/111] fixed ambient and fixed buffered lights --- .../framegraph/passes/DeferredPass.java | 24 +++++++++++-------- .../ShadingCommon/DeferredShading.frag | 2 ++ .../TerrainTestAdvancedRenderPath.java | 2 +- .../TestSimpleDeferredLighting.java | 4 +++- .../TerrainLightingGBufferPack.frag | 2 ++ .../TerrainLightingGBufferPack.vert | 5 ++-- 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 9f3b995ab5..2d9af2294b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -74,10 +74,16 @@ */ public class DeferredPass extends RenderPass implements TechniqueDefLogic { + /** + * Indicates the maximum number of lights that can be handled using buffers. + *

      + * Development Note: if more uniforms are added to the shader, this value may need to + * be decreased. + */ + public static final int MAX_BUFFER_LIGHTS = 338; + public static final int MAX_PROBES = 3; private static Defines defs; private static final List localProbeList = new LinkedList<>(); - public static final int MAX_BUFFER_LIGHTS = 341; - public static final int MAX_PROBES = 3; private boolean tiled = false; private AssetManager assetManager; @@ -183,20 +189,21 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager ambientColor.set(amb); probeList = resources.acquire(probes); } - defines.set(defs.numLights, lights.size()*3); + defines.set(defs.numLights, Math.min(lights.size(), MAX_BUFFER_LIGHTS)*3); } else { // get resources for lighting with textures ambientColor.set(resources.acquire(ambient)); probeList = resources.acquire(probes); defines.set(defs.useTextures, true); defines.set(defs.numLights, resources.acquire(numLights)); - if (!ambientColor.equals(ColorRGBA.BlackNoAlpha)) { - defines.set(defs.useAmbientLight, true); - } + if (tileTextures[0] != null) { defines.set(defs.useTiles, true); } } + //if (!ambientColor.equals(ColorRGBA.BlackNoAlpha)) { + // defines.set(defs.useAmbientLight, true); + //} //defines.set(defs.numLights, 1); defines.set(defs.useAmbientLight, true); defines.set(defs.numProbes, getNumReadyProbes(probeList)); @@ -273,7 +280,7 @@ private void injectLightBuffers(Shader shader, LightList lights) { data.setVector4Length(n); int i = 0, lightCount = 0; for (Light l : lights) { - if (lightCount++ > MAX_BUFFER_LIGHTS) { + if (lightCount++ >= MAX_BUFFER_LIGHTS) { break; } Light.Type type = l.getType(); @@ -294,9 +301,6 @@ private void injectLightBuffers(Shader shader, LightList lights) { writeVectorToUniform(data, sl.getPosition(), sl.getInvSpotRange(), i++); writeVectorToUniform(data, sl.getDirection(), sl.getPackedAngleCos(), i++); break; - case Ambient: - case Probe: - throw new IllegalStateException("Internal: ambient and probe lights should not be present."); default: throw new UnsupportedOperationException("Light "+type+" not supported."); } 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 513f0cc9bf..d0e8d92911 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag @@ -154,6 +154,8 @@ void main(){ } #endif + //gl_FragColor.rgb = AmbientSum; + } else if (shadingModelId == PBR_LIGHTING) { // PBR shading diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java index 6f391c1dd8..a71f5c8855 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java @@ -316,7 +316,7 @@ private void createSky() { rootNode.attachChild(sky); rootNode.addControl(new EnvironmentProbeControl(assetManager, 256)); - rootNode.addLight(new AmbientLight(ColorRGBA.White)); + rootNode.addLight(new AmbientLight(ColorRGBA.White.mult(0.05f))); } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 3616c0deee..30add22d54 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -675,8 +675,10 @@ public void simpleInitApp() { //renderManager.setFrameGraph(deferred); //renderManager.setFrameGraph(forward); + rootNode.addLight(new AmbientLight(ColorRGBA.White)); + Junction lightingMethod = deferred.get(Junction.class, "LightPackMethod"); - lightingMethod.setIndexSource((fg, vp) -> 0); + //lightingMethod.setIndexSource((fg, vp) -> 0); File capTarget = new File(System.getProperty("user.home")+"/earlyFrameCapture.txt"); GraphEventCapture cap = new GraphEventCapture(capTarget); 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 index b7d01aaa14..33e13bc950 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag @@ -6,6 +6,7 @@ #import "Common/ShaderLib/ShadingModel.glsllib" uniform float m_Shininess; +uniform vec4 g_AmbientLightColor; varying vec4 AmbientSum; varying vec4 DiffuseSum; @@ -621,6 +622,7 @@ void main(){ outGBuffer3.xyz = normal; outGBuffer0 = diffuseColor * DiffuseSum; outGBuffer1.rgb = SpecularSum.rgb * 100.0f + AmbientSum.rgb * 0.01f; + //outGBuffer1.rgb = SpecularSum.rgb * 100.0f + g_AmbientLightColor.rgb * 0.01f; outGBuffer1.a = m_Shininess; // shading model id outGBuffer2.a = PHONG_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 index b1284d28f3..1b54f6551e 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.vert +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.vert @@ -44,7 +44,8 @@ void main(){ wBinormal = cross(wNormal, wTangent)* inTangent.w; #endif - AmbientSum = g_AmbientLightColor; + //AmbientSum = g_AmbientLightColor; + AmbientSum = vec4(1.0); DiffuseSum = vec4(1.0); SpecularSum = vec4(0.0); @@ -54,4 +55,4 @@ void main(){ wNormal = inNormal; #endif -} \ No newline at end of file +} From efa277163d182f62a5e3f2a345a789beef89bd0d Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 24 Jun 2024 10:17:31 -0400 Subject: [PATCH 097/111] fixed gbuffer packing for advanced terrain --- .../framegraph/passes/DeferredPass.java | 21 ++++++++++++------- .../TestFrameGraphLoadingSpeeds.java | 20 +++++++++--------- .../TestPBRTerrainAdvancedRenderPath.java | 18 ++++++++++------ .../AdvancedPBRTerrainGBufferPack.frag | 16 +++++++------- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 2d9af2294b..418b9dd91a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -75,13 +75,22 @@ public class DeferredPass extends RenderPass implements TechniqueDefLogic { /** - * Indicates the maximum number of lights that can be handled using buffers. + * Indicates the maximum number of directional, point, and spot lights + * that can be handled using buffers. *

      - * Development Note: if more uniforms are added to the shader, this value may need to - * be decreased. + * Excess lights will be discarded. + *

      + * Development Note: if more uniforms are added to the + * shader, this value may need to be decreased. */ public static final int MAX_BUFFER_LIGHTS = 338; + /** + * Indicates the maximum number of light probes that can be handled. + *

      + * Excess light probes will be discarded. + */ public static final int MAX_PROBES = 3; + private static Defines defs; private static final List localProbeList = new LinkedList<>(); @@ -196,15 +205,11 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager probeList = resources.acquire(probes); defines.set(defs.useTextures, true); defines.set(defs.numLights, resources.acquire(numLights)); - if (tileTextures[0] != null) { defines.set(defs.useTiles, true); } } - //if (!ambientColor.equals(ColorRGBA.BlackNoAlpha)) { - // defines.set(defs.useAmbientLight, true); - //} - //defines.set(defs.numLights, 1); + // this may need to be changed to only be enabled when there is an ambient light present defines.set(defs.useAmbientLight, true); defines.set(defs.numProbes, getNumReadyProbes(probeList)); return material.getActiveTechnique().getDef().getShader(assetManager, rendererCaps, defines); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java b/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java index f541e279ae..0ed325cae3 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java @@ -37,7 +37,7 @@ /** * Tests framegraph loading speeds. *

      - * The test loads a total of 9 framegraphs (3 forward, 3 deferred, and 3 tiled deferred) + * The test loads a total of 6 framegraphs (3 forward and 3 deferred) * after a delay of 100 frames, with 10 frames seperating each load. After all loading * is complete, the application quits. Results are printed to the console as milliseconds * each load took to complete. @@ -63,26 +63,26 @@ public void simpleInitApp() {} public void simpleUpdate(float tpf) { if (--frameDelay <= 0) { switch (loadIndex++) { - case 6: + case 0: + case 2: + case 4: load(loadIndex, "forward", "Common/FrameGraphs/Forward.j3g"); + break; + case 1: case 3: - case 0: load(loadIndex, "forward", "Common/FrameGraphs/Forward.j3g"); break; - case 7: - case 4: - case 1: load(loadIndex, "deferred", "Common/FrameGraphs/Deferred.j3g"); break; - case 8: - case 5: - case 2: load(loadIndex, "tiled deferred", "Common/FrameGraphs/TiledDeferred.j3g"); break; + case 5: load(loadIndex, "deferred", "Common/FrameGraphs/Deferred.j3g"); + break; default: stop(); } frameDelay = 10; } } - private void load(int index, String name, String path) { + private FrameGraph load(int index, String name, String path) { long timeBefore = System.currentTimeMillis(); FrameGraph fg = new FrameGraph(assetManager, path); long timeAfter = System.currentTimeMillis(); System.out.println(index+": "+name+": "+(timeAfter-timeBefore)+"ms"); + return fg; } } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java index 4fe56f42f9..f1e928c9f2 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java @@ -43,8 +43,8 @@ import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; -import com.jme3.renderer.framegraph.FrameGraphFactory; import com.jme3.shader.VarType; +import com.jme3.system.AppSettings; import com.jme3.terrain.geomipmap.TerrainLodControl; import com.jme3.terrain.geomipmap.TerrainQuad; import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; @@ -153,7 +153,10 @@ public class TestPBRTerrainAdvancedRenderPath extends SimpleApplication { public static void main(String[] args) { TestPBRTerrainAdvancedRenderPath app = new TestPBRTerrainAdvancedRenderPath(); - app.setShowSettings(true); + AppSettings settings = new AppSettings(true); + settings.setWidth(768); + settings.setHeight(768); + app.setSettings(settings); app.start(); } @@ -195,14 +198,17 @@ public void onAction(String name, boolean pressed, float tpf) { @Override public void simpleInitApp() { - viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, true)); - //renderManager.setFrameGraph(RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred)); - //renderManager.setRenderPath(RenderManager.RenderPath.TiledDeferred); + + //viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, false)); + flyCam.setDragToRotate(true); + flyCam.setMoveSpeed(50); + setupKeys(); setUpTerrain(); - setUpTerrainMaterial(); // <- This method contains the important info about using 'AdvancedPBRTerrain.j3md' + setUpTerrainMaterial(); setUpLights(); setUpCamera(); + } private void setUpTerrainMaterial() { 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 index 90feef10b5..56a60a66d5 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/AdvancedPBRTerrainGBufferPack.frag +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/AdvancedPBRTerrainGBufferPack.frag @@ -469,12 +469,12 @@ void main(){ // 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; + outGBuffer3.xy = n1; + outGBuffer3.zw = n2; + outGBuffer0.rgb = floor(diffuseColor.rgb * 100.0f) + ao * 0.1f; + outGBuffer1.rgb = floor(specularColor.rgb * 100.0f) + fZero * 0.1f; + outGBuffer1.a = Roughness; + outGBuffer0.a = alpha; @@ -491,14 +491,14 @@ void main(){ 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; + outGBuffer2.a = PBR_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; + outGBuffer2.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 From 00f268c5ba7280f79f044765c2af4adf91cbbd23 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Mon, 24 Jun 2024 10:44:01 -0400 Subject: [PATCH 098/111] fixed pbr terrain --- .../renderer/framegraph/ResourceList.java | 39 ++++++- .../renderer/framegraph/ResourceTicket.java | 13 +++ .../framegraph/passes/DeferredPass.java | 2 +- .../renderpath/TestPBRTerrainRenderPath.java | 12 ++- .../java/jme3test/renderpath/TestRTT.java | 102 ------------------ .../jme3test/renderpath/TestShadingModel.java | 6 -- .../GBufferPack/PBRTerrainGBufferPack.frag | 16 +-- 7 files changed, 70 insertions(+), 120 deletions(-) delete mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestRTT.java diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index b00f27ebbf..01e93309ba 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -73,6 +73,7 @@ protected RenderResource create(ResourceProducer producer, ResourceDef res.getTicket().setLocalIndex(add(res)); return res; } + /** * Locates the resource associated with the ticket. * @@ -101,15 +102,19 @@ protected RenderResource locate(ResourceTicket ticket) { } throw new IndexOutOfBoundsException(ticket+" is out of bounds for size "+resources.size()); } + /** * Returns true if the ticket can be used to locate a resource. + *

      + * Use {@link ResourceTicket#validate(com.jme3.renderer.framegraph.ResourceTicket)} instead. * * @param ticket * @return */ public boolean validate(ResourceTicket ticket) { - return ticket != null && ticket.getWorldIndex() >= 0; + return ResourceTicket.validate(ticket); } + /** * Adds the resource to the first available slot. * @@ -137,6 +142,7 @@ protected int add(RenderResource res) { return i; } } + /** * Removes the resource at the index. * @@ -183,6 +189,7 @@ public void reserve(int passIndex, ResourceTicket ticket) { ticket.copyObjectTo(locate(ticket).getTicket()); } } + /** * Makes reservations for each given ticket. * @@ -210,6 +217,7 @@ public void reference(int passIndex, ResourceTicket ticket) { resource.reference(passIndex); if (cap != null) cap.referenceResource(resource.getIndex(), ticket.getName()); } + /** * References the resource associated with the ticket if the ticket * is not null and does not have a negative world index. @@ -225,6 +233,7 @@ public boolean referenceOptional(int passIndex, ResourceTicket ticket) { } return false; } + /** * References resources associated with the tickets. * @@ -236,6 +245,7 @@ public void reference(int passIndex, ResourceTicket... tickets) { reference(passIndex, t); } } + /** * Optionally references resources associated with the tickets. * @@ -294,6 +304,7 @@ public void setConstant(ResourceTicket ticket) { if (cap != null) cap.setObjectConstant(obj.getId()); } } + /** * Marks the resource associated with the ticket if the ticket is not * null and does not have a negative world index. @@ -333,6 +344,19 @@ public boolean isVirtual(ResourceTicket ticket, boolean optional) { return true; } + /** + * Acquires the object held by the given resource. + *

      + * If the object does have an object associated with it (virtual), one will either + * be created or reallocated by the {@link RenderObjectMap}. + *

      + * The object's id is written to the ticket. + * + * @param + * @param resource + * @param ticket + * @return + */ protected T acquire(RenderResource resource, ResourceTicket ticket) { if (!resource.isUsed()) { throw new IllegalStateException(resource+" was unexpectedly acquired."); @@ -344,6 +368,7 @@ protected T acquire(RenderResource resource, ResourceTicket ticket) { resource.getTicket().copyObjectTo(ticket); return resource.getResource(); } + /** * Acquires and returns the value associated with the resource at the ticket. *

      @@ -361,6 +386,7 @@ public T acquire(ResourceTicket ticket) { } return acquire(resource, ticket); } + /** * If the ticket is not null and has a positive or zero world index, an object * will be acquired for the resource and returned. @@ -381,6 +407,7 @@ public T acquireOrElse(ResourceTicket ticket, T value) { } return value; } + /** * Acquires and assigns textures as color targets to the framebuffer. *

      @@ -395,6 +422,7 @@ public T acquireOrElse(ResourceTicket ticket, T value) { public void acquireColorTargets(FrameBuffer fbo, ResourceTicket... tickets) { acquireColorTargets(fbo, null, tickets); } + /** * Acquires and assigns textures as color targets to the framebuffer. * @@ -432,6 +460,7 @@ public Texture[] acquireColorTargets(FrameBuffer fbo, Texture[] texArray, Resour } return texArray; } + /** * Acquires the texture associated with the ticket and assigns it to the framebuffer. * @@ -454,6 +483,7 @@ public T acquireColorTarget(FrameBuffer fbo, ResourceTicket< } return replaceColorTarget(fbo, ticket, 0); } + private T replaceColorTarget(FrameBuffer fbo, ResourceTicket ticket, int i) { if (i < fbo.getNumColorTargets()) { Texture existing = fbo.getColorTarget(i).getTexture(); @@ -468,9 +498,11 @@ private T replaceColorTarget(FrameBuffer fbo, ResourceTicket } else { T acquired = acquire(ticket); fbo.addColorTarget(FrameBuffer.target(acquired)); + fbo.setUpdateNeeded(); return acquired; } } + /** * Acquires and assigns a texture as the depth target to the framebuffer. *

      @@ -518,6 +550,7 @@ protected T extract(RenderResource resource, ResourceTicket ticket) { resource.getTicket().copyObjectTo(ticket); return map.extract(resource); } + /** * Permanently extracts the object from the object manager. *

      @@ -536,6 +569,7 @@ public T extract(ResourceTicket ticket) { } return object; } + /** * If the ticket is not null and has a positive or zero world index, an object * will be extracted by the resource and returned. @@ -582,6 +616,7 @@ public void release(ResourceTicket ticket) { } } } + /** * Releases the ticket if the ticket is not null and contains a non-negative * world index. @@ -596,6 +631,7 @@ public boolean releaseOptional(ResourceTicket ticket) { } return false; } + /** * Releases the resources obtained by the tickets from use. * @@ -606,6 +642,7 @@ public void release(ResourceTicket... tickets) { release(t); } } + /** * Optionally releases the resources obtained by the tickets from use. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index e0ecf2d02f..6dda9badd6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -241,4 +241,17 @@ public String toString() { return "Ticket[name="+name+", worldIndex="+getWorldIndex()+"]"; } + /** + * Returns true if the ticket is valid for locating a resource. + *

      + * A ticket is only valid if it is not null and its world index + * is greater than or equal to zero. + * + * @param ticket + * @return true if ticket is valid + */ + public static boolean validate(ResourceTicket ticket) { + return ticket != null && ticket.getWorldIndex() >= 0; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 418b9dd91a..70023b6e77 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -83,7 +83,7 @@ public class DeferredPass extends RenderPass implements TechniqueDefLogic { * Development Note: if more uniforms are added to the * shader, this value may need to be decreased. */ - public static final int MAX_BUFFER_LIGHTS = 338; + public static final int MAX_BUFFER_LIGHTS = 320; /** * Indicates the maximum number of light probes that can be handled. *

      diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java index 01d847c568..16b1d415fa 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java @@ -33,7 +33,9 @@ */ import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; +import com.jme3.asset.ModelKey; import com.jme3.asset.TextureKey; +import com.jme3.asset.cache.AssetCache; import com.jme3.font.BitmapText; import com.jme3.input.KeyInput; import com.jme3.input.controls.ActionListener; @@ -48,7 +50,10 @@ import com.jme3.math.Vector3f; import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.ToneMapFilter; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; +import com.jme3.renderer.framegraph.light.TiledRenderGrid; +import com.jme3.renderer.framegraph.passes.LightImagePass; import com.jme3.system.AppSettings; import com.jme3.terrain.geomipmap.TerrainLodControl; import com.jme3.terrain.geomipmap.TerrainQuad; @@ -114,7 +119,7 @@ public class TestPBRTerrainRenderPath extends SimpleApplication { private AmbientLight ambientLight; private DirectionalLight directionalLight; private PointLight[] pointLights; - private int currentPointLightNum = 1000; + private int currentPointLightNum = 700; private boolean isNight = true; private final float dayLightIntensity = 1.0f; @@ -196,7 +201,10 @@ else if(name.equals("addPointLight") && !pressed){ @Override public void simpleInitApp() { - viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, true)); + FrameGraph fg = FrameGraphFactory.deferred(assetManager, true); + fg.get(LightImagePass.class).setMaxLights(1024); + fg.setSetting("TileInfo", new TiledRenderGrid(7, -1)); + //viewPort.setFrameGraph(fg); flyCam.setDragToRotate(true); // For this scene, use a tileSize=64 configuration (at 1600*900 resolution) diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRTT.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRTT.java deleted file mode 100644 index 0e1f79bddc..0000000000 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestRTT.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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; - -import com.jme3.app.SimpleApplication; -import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; -import com.jme3.scene.Geometry; -import com.jme3.scene.shape.Box; -import com.jme3.scene.shape.Quad; -import com.jme3.system.AppSettings; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Image; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture2D; -import java.util.LinkedList; - -/** - * Temporary test to narrow down a bug involving render to texture. - * - * @author codex - */ -public class TestRTT extends SimpleApplication { - - private FrameBuffer fbo; - private Material targetMat1, targetMat2, targetMat3; - private Texture targetTex; - private final LinkedList stack = new LinkedList<>(); - private final int frameDelay = 50; - private int frame = frameDelay; - - private static final int w = 768, h = 768; - - public static void main(String[] args) { - TestRTT app = new TestRTT(); - AppSettings settings = new AppSettings(true); - settings.setWidth(w); - settings.setHeight(h); - app.setSettings(settings); - app.start(); - } - - @Override - public void simpleInitApp() { - - flyCam.setDragToRotate(true); - guiViewPort.setClearFlags(true, true, true); - guiViewPort.setBackgroundColor(ColorRGBA.Green.mult(.05f)); - - fbo = new FrameBuffer(w, h, 1); - viewPort.setOutputFrameBuffer(fbo); - - Geometry g = new Geometry("box", new Box(1, 1, 1)); - Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - m.setColor("Color", ColorRGBA.Blue); - g.setMaterial(m); - rootNode.attachChild(g); - - Geometry quad1 = new Geometry("quad1", new Quad(300, 300)); - quad1.setLocalTranslation(70, 410, 0); - targetMat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - quad1.setMaterial(targetMat1); - guiNode.attachChild(quad1); - - Geometry quad2 = new Geometry("quad2", new Quad(300, 300)); - quad2.setLocalTranslation(380, 410, 0); - targetMat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - quad2.setMaterial(targetMat2); - guiNode.attachChild(quad2); - - Geometry quad3 = new Geometry("quad3", new Quad(300, 300)); - quad3.setLocalTranslation(310, 50, 0); - targetMat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); - quad3.setMaterial(targetMat3); - guiNode.attachChild(quad3); - - stack.add(new Texture2D(w, h, Image.Format.RGBA8)); - stack.add(new Texture2D(w, h, Image.Format.RGBA8)); - - } - @Override - public void simpleUpdate(float tpf) { - if (frame++ >= frameDelay) { - frame = 0; - if (targetTex == stack.getFirst()) { - targetTex = stack.getLast(); - } else { - targetTex = stack.getFirst(); - } - targetMat1.setTexture("ColorMap", stack.getFirst()); - targetMat2.setTexture("ColorMap", stack.getLast()); - targetMat3.setTexture("ColorMap", targetTex); - fbo.clearColorTargets(); - fbo.addColorTarget(FrameBuffer.target(targetTex)); - // this fixes the entire issue - fbo.setUpdateNeeded(); - } - } - -} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java index 28b6c79324..dd8b2911a0 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java @@ -83,12 +83,6 @@ public static void main(String[] args) { app.setSettings(settings); app.start(); } - - @Override - public void simpleUpdate(float tpf) { - //cam.lookAt(new Vector3f(), Vector3f.UNIT_Y); - RenderObjectMap objects = renderManager.getRenderObjectMap(); - } @Override public void simpleInitApp() { 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 index ba92341a60..21a1fa04d7 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/PBRTerrainGBufferPack.frag +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/PBRTerrainGBufferPack.frag @@ -404,12 +404,12 @@ vec3 fZero = vec3(specular); // 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; + outGBuffer3.xy = n1; + outGBuffer3.zw = n2; + outGBuffer0.rgb = floor(diffuseColor.rgb * 100.0f) + ao * 0.1f; + outGBuffer1.rgb = floor(specularColor.rgb * 100.0f) + fZero * 0.1f; + outGBuffer1.a = Roughness; + outGBuffer0.a = alpha; @@ -426,10 +426,10 @@ vec3 fZero = vec3(specular); 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; + outGBuffer2.a = PBR_LIGHTING + indoorSunLightExposure * 0.01f; if(emissive.a > 0){ emissive = emissive * pow(emissive.a * 5, emissiveIntensity) * emissiveIntensity * 20 * emissive.a; } - Context_OutGBuff2.rgb = emissive.rgb; + outGBuffer2.rgb = emissive.rgb; } From dbde835b79709fd754fda24fe3c5f1e000dca5ca Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Tue, 25 Jun 2024 10:12:07 -0400 Subject: [PATCH 099/111] made render object map threadsafe --- .../jme3/renderer/framegraph/FrameGraph.java | 170 ++++------- .../jme3/renderer/framegraph/PassIndex.java | 92 ++++++ .../framegraph/PassQueueExecutor.java | 244 ++++++++++++++++ .../renderer/framegraph/RenderObject.java | 56 +++- .../renderer/framegraph/RenderObjectMap.java | 267 ++++++++++++------ .../renderer/framegraph/RenderResource.java | 10 +- .../renderer/framegraph/ResourceList.java | 59 +--- .../renderer/framegraph/ResourceProducer.java | 2 +- .../framegraph/SavablePassConnection.java | 2 +- .../jme3/renderer/framegraph/TimeFrame.java | 60 ++-- .../framegraph/debug/GraphEventCapture.java | 2 +- .../framegraph/passes/RenderPass.java | 15 +- 12 files changed, 696 insertions(+), 283 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java 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 00a70f993a..6928ed2970 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 @@ -44,6 +44,7 @@ import com.jme3.renderer.framegraph.client.GraphSetting; import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.passes.Attribute; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -88,10 +89,15 @@ */ public class FrameGraph { + /** + * Index for the main render thread pass queue. + */ + public static final int RENDER_THREAD = 0; + private final AssetManager assetManager; private final ResourceList resources; private final FGRenderContext context; - private final LinkedList passes = new LinkedList<>(); + private final ArrayList queues = new ArrayList<>(1); private final HashMap settings = new HashMap<>(); private String name = "FrameGraph"; private boolean rendered = false; @@ -105,6 +111,7 @@ public FrameGraph(AssetManager assetManager) { this.assetManager = assetManager; this.resources = new ResourceList(); this.context = new FGRenderContext(this); + this.queues.add(new PassQueueExecutor(this, RENDER_THREAD)); } /** * Creates a new framegraph from the given data. @@ -147,22 +154,6 @@ public void configure(RenderManager rm, ViewPort vp, AppProfiler prof, float tpf resources.setRenderManager(rm); context.target(rm, vp, prof, tpf); } - /** - * Pre-frame operations. - */ - public void preFrame() { - for (RenderPass p : passes) { - p.preFrame(context); - } - } - /** - * Post-queue operations. - */ - public void postQueue() { - for (RenderPass p : passes) { - p.postQueue(context); - } - } /** * Executes this framegraph. *

      @@ -188,51 +179,50 @@ public boolean execute() { if (!rendered) { resources.beginRenderingSession(); } - for (RenderPass p : passes) { - if (prof != null) prof.fgStep(FgStep.Prepare, p.getProfilerName()); - if (cap != null) cap.prepareRenderPass(p.getIndex(), p.getProfilerName()); - p.prepareRender(context); + for (PassQueueExecutor queue : queues) { + for (RenderPass p : queue) { + if (prof != null) prof.fgStep(FgStep.Prepare, p.getProfilerName()); + if (cap != null) cap.prepareRenderPass(p.getIndex(), p.getProfilerName()); + p.prepareRender(context); + } } // cull passes and resources if (prof != null) prof.vpStep(VpStep.FrameGraphCull, vp, null); - for (RenderPass p : passes) { - p.countReferences(); + for (PassQueueExecutor queue : queues) { + for (RenderPass p : queue) { + p.countReferences(); + } } resources.cullUnreferenced(); // execute if (prof != null) prof.vpStep(VpStep.FrameGraphExecute, vp, null); context.pushRenderSettings(); - for (RenderPass p : passes) { - if (p.isUsed()) { - if (prof != null) prof.fgStep(FgStep.Execute, p.getProfilerName()); - if (cap != null) cap.executeRenderPass(p.getIndex(), p.getProfilerName()); - p.executeRender(context); - context.popRenderSettings(); - } + for (PassQueueExecutor p : queues) { + p.execute(context); } context.popFrameBuffer(); // reset if (prof != null) prof.vpStep(VpStep.FrameGraphReset, vp, null); - for (RenderPass p : passes) { - if (prof != null) prof.fgStep(FgStep.Reset, p.getProfilerName()); - p.resetRender(context); + for (PassQueueExecutor queue : queues) { + for (RenderPass p : queue) { + if (prof != null) prof.fgStep(FgStep.Reset, p.getProfilerName()); + p.resetRender(context); + } } // cleanup resources resources.clear(); - if (rendered) { - return false; - } else { - rendered = true; - return true; - } + if (rendered) return false; + else return (rendered = true); } /** * Should be called only when all rendering for the frame is complete. */ public void renderingComplete() { // notify passes - for (RenderPass p : passes) { - p.renderingComplete(); + for (PassQueueExecutor queue : queues) { + for (RenderPass p : queue) { + p.renderingComplete(); + } } // reset flags rendered = false; @@ -246,9 +236,7 @@ public void renderingComplete() { * @return given pass */ public T add(T pass) { - passes.addLast(pass); - pass.initializePass(this, passes.size()-1); - return pass; + return queues.get(RENDER_THREAD).add(pass); } /** * Adds the pass at the index in the pass queue. @@ -263,18 +251,7 @@ public T add(T pass) { * @return */ public T add(T pass, int index) { - if (index < 0) { - throw new IndexOutOfBoundsException("Index cannot be negative."); - } - if (index >= passes.size()) { - return add(pass); - } - passes.add(index, pass); - pass.initializePass(this, index); - for (RenderPass p : passes) { - p.shiftExecutionIndex(index, true); - } - return pass; + return queues.get(RENDER_THREAD).add(pass, index); } /** * Creates and adds an Attribute pass and links it to the given ticket. @@ -286,9 +263,7 @@ public T add(T pass, int index) { * @return created Attribute */ public Attribute addAttribute(ResourceTicket ticket) { - Attribute attr = add(new Attribute<>()); - attr.getInput(Attribute.INPUT).setSource(ticket); - return attr; + return queues.get(RENDER_THREAD).addAttribute(ticket); } /** @@ -299,9 +274,10 @@ public Attribute addAttribute(ResourceTicket ticket) { * @return first qualifying pass, or null */ public T get(Class type) { - for (RenderPass p : passes) { - if (type.isAssignableFrom(p.getClass())) { - return (T)p; + for (PassQueueExecutor q : queues) { + T p = q.get(type); + if (p != null) { + return p; } } return null; @@ -315,9 +291,10 @@ public T get(Class type) { * @return first qualifying pass, or null */ public T get(Class type, String name) { - for (RenderPass p : passes) { - if (name.equals(p.getName()) && type.isAssignableFrom(p.getClass())) { - return (T)p; + for (PassQueueExecutor q : queues) { + T p = q.get(type, name); + if (p != null) { + return p; } } return null; @@ -331,9 +308,10 @@ public T get(Class type, String name) { * @return pass of the id, or null */ public T get(Class type, int id) { - for (RenderPass p : passes) { - if (id == p.getId() && type.isAssignableFrom(p.getClass())) { - return (T)p; + for (PassQueueExecutor q : queues) { + T p = q.get(type, id); + if (p != null) { + return p; } } return null; @@ -349,25 +327,7 @@ public T get(Class type, int id) { * @throws IndexOutOfBoundsException if the index is less than zero or >= the queue size */ public RenderPass remove(int i) { - if (i < 0 || i >= passes.size()) { - throw new IndexOutOfBoundsException("Index "+i+" is out of bounds for size "+passes.size()); - } - int j = 0; - RenderPass removed = null; - for (Iterator it = passes.iterator(); it.hasNext();) { - RenderPass p = it.next(); - if (removed != null) { - p.disconnectInputsFrom(removed); - p.shiftExecutionIndex(i, false); - } else if (j++ == i) { - removed = p; - it.remove(); - } - } - if (removed != null) { - removed.cleanupPass(this); - } - return removed; + return queues.get(RENDER_THREAD).remove(i); } /** * Removes the given pass from the queue. @@ -378,25 +338,10 @@ public RenderPass remove(int i) { * @return true if the pass was removed from the queue */ public boolean remove(RenderPass pass) { - int i = 0; - boolean found = false; - for (Iterator it = passes.iterator(); it.hasNext();) { - RenderPass p = it.next(); - if (found) { - // shift execution indices down - p.disconnectInputsFrom(pass); - p.shiftExecutionIndex(i, false); - continue; - } - if (p == pass) { - it.remove(); - found = true; + for (PassQueueExecutor queue : queues) { + if (queue.remove(pass)) { + return true; } - i++; - } - if (found) { - pass.cleanupPass(this); - return true; } return false; } @@ -404,10 +349,9 @@ public boolean remove(RenderPass pass) { * Clears all passes from the pass queue. */ public void clear() { - for (RenderPass p : passes) { - p.cleanupPass(this); + for (PassQueueExecutor queue : queues) { + queue.clear(); } - passes.clear(); } /** @@ -568,6 +512,14 @@ public Context getCLContext() { public String getName() { return name; } + /** + * Returns true if this framegraph is running asynchronous passes. + * + * @return + */ + public boolean isAsync() { + return queues.size() > 1; + } /** * Applies the framegraph data to this framegraph. @@ -622,7 +574,7 @@ public FrameGraph loadData(String assetPath) { * @return */ public FrameGraphData createData() { - return new FrameGraphData(this, passes, settings); + return new FrameGraphData(this, queues, settings); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java new file mode 100644 index 0000000000..5b9bff668c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java @@ -0,0 +1,92 @@ +/* + * 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 PassIndex { + + private int threadIndex, queueIndex; + + public PassIndex(int queueIndex) { + this(FrameGraph.RENDER_THREAD, queueIndex); + } + public PassIndex(int threadIndex, int queueIndex) { + this.threadIndex = threadIndex; + this.queueIndex = queueIndex; + } + + public PassIndex set(PassIndex index) { + threadIndex = index.threadIndex; + queueIndex = index.queueIndex; + return this; + } + + /** + * Shifts the thread index down one if the thread index is greater + * than the given index. + * + * @param i + * @return new thread index + */ + public int shiftThread(int i) { + if (threadIndex > i) { + threadIndex--; + } + return threadIndex; + } + /** + * Shifts the queue index down one if the thread index is greater than + * the given index. + * + * @param i + * @return new queue index + */ + public int shiftQueue(int i) { + if (queueIndex > i) { + queueIndex--; + } + return queueIndex; + } + + public int getThreadIndex() { + return threadIndex; + } + public int getQueueIndex() { + return queueIndex; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 19 * hash + this.threadIndex; + hash = 19 * hash + this.queueIndex; + return hash; + } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PassIndex other = (PassIndex) obj; + if (this.threadIndex != other.threadIndex) { + return false; + } + return this.queueIndex == other.queueIndex; + } + @Override + public String toString() { + return PassIndex.class.getSimpleName()+"[thread="+threadIndex+", queue="+queueIndex+']'; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java new file mode 100644 index 0000000000..fc327c5253 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java @@ -0,0 +1,244 @@ +/* + * 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.profile.FgStep; +import static com.jme3.renderer.framegraph.FrameGraph.RENDER_THREAD; +import com.jme3.renderer.framegraph.passes.Attribute; +import com.jme3.renderer.framegraph.passes.RenderPass; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * + * @author codex + */ +public class PassQueueExecutor implements Runnable, Iterable { + + private final FrameGraph frameGraph; + private final LinkedList queue = new LinkedList<>(); + private int index; + private Thread thread; + private FGRenderContext context; + + public PassQueueExecutor(FrameGraph frameGraph, int index) { + this.frameGraph = frameGraph; + this.index = index; + } + + @Override + public void run() { + boolean async = isAsync(); + for (RenderPass p : queue) { + if (p.isUsed()) { + /*if (!async) { + if (context.isProfilerAvailable()) context.getProfiler().fgStep(FgStep.Execute, p.getProfilerName()); + if (cap != null) cap.executeRenderPass(p.getIndex(), p.getProfilerName()); + }*/ + p.executeRender(context); + if (!async) { + context.popRenderSettings(); + } + } + } + } + @Override + public Iterator iterator() { + return queue.iterator(); + } + + public void execute(FGRenderContext context) { + if (!isAsync()) { + run(); + } else { + thread = new Thread(this); + thread.start(); + } + } + + /** + * Adds the pass to end of the pass queue. + * + * @param + * @param pass + * @return given pass + */ + public T add(T pass) { + queue.addLast(pass); + pass.initializePass(frameGraph, new PassIndex(index, queue.size()-1)); + return pass; + } + /** + * Adds the pass at the index in the pass queue. + *

      + * If the index is >= the current queue size, the pass will + * be added to the end of the queue. Passes above the added pass + * will have their indexes shifted. + * + * @param + * @param pass + * @param index + * @return + */ + public T add(T pass, int index) { + if (index < 0) { + throw new IndexOutOfBoundsException("Index cannot be negative."); + } + if (index >= queue.size()) { + return add(pass); + } + queue.add(index, pass); + pass.initializePass(frameGraph, new PassIndex(this.index, index)); + for (RenderPass p : queue) { + p.shiftExecutionIndex(index, true); + } + return pass; + } + /** + * Creates and adds an Attribute pass and links it to the given ticket. + *

      + * This is handy for quickly debugging various resources in the graph. + * + * @param + * @param ticket ticket to reference from + * @return created Attribute + */ + public Attribute addAttribute(ResourceTicket ticket) { + Attribute attr = add(new Attribute<>()); + attr.getInput(Attribute.INPUT).setSource(ticket); + return attr; + } + + /** + * Gets the first pass that is of or a subclass of the given class. + * + * @param + * @param type + * @return first qualifying pass, or null + */ + public T get(Class type) { + for (RenderPass p : queue) { + if (type.isAssignableFrom(p.getClass())) { + return (T)p; + } + } + return null; + } + /** + * Gets the first pass of the given class that is named as given. + * + * @param + * @param type + * @param name + * @return first qualifying pass, or null + */ + public T get(Class type, String name) { + for (RenderPass p : queue) { + if (name.equals(p.getName()) && type.isAssignableFrom(p.getClass())) { + return (T)p; + } + } + return null; + } + /** + * Gets the pass that holds the given id number. + * + * @param + * @param type + * @param id + * @return pass of the id, or null + */ + public T get(Class type, int id) { + for (RenderPass p : queue) { + if (id == p.getId() && type.isAssignableFrom(p.getClass())) { + return (T)p; + } + } + return null; + } + + /** + * Removes the pass at the index in the queue. + *

      + * Passes above the removed pass will have their indexes shifted. + * + * @param i + * @return removed pass + * @throws IndexOutOfBoundsException if the index is less than zero or >= the queue size + */ + public RenderPass remove(int i) { + if (i < 0 || i >= queue.size()) { + throw new IndexOutOfBoundsException("Index "+i+" is out of bounds for size "+queue.size()); + } + int j = 0; + RenderPass removed = null; + for (Iterator it = queue.iterator(); it.hasNext();) { + RenderPass p = it.next(); + if (removed != null) { + p.disconnectInputsFrom(removed); + p.shiftExecutionIndex(i, false); + } else if (j++ == i) { + removed = p; + it.remove(); + } + } + if (removed != null) { + removed.cleanupPass(frameGraph); + } + return removed; + } + /** + * Removes the given pass from the queue. + *

      + * Passes above the removed pass will have their indexes shifted. + * + * @param pass + * @return true if the pass was removed from the queue + */ + public boolean remove(RenderPass pass) { + int i = 0; + boolean found = false; + for (Iterator it = queue.iterator(); it.hasNext();) { + RenderPass p = it.next(); + if (found) { + // shift execution indices down + p.disconnectInputsFrom(pass); + p.shiftExecutionIndex(i, false); + continue; + } + if (p == pass) { + it.remove(); + found = true; + } + i++; + } + if (found) { + pass.cleanupPass(frameGraph); + return true; + } + return false; + } + /** + * Clears all passes from the pass queue. + */ + public void clear() { + for (RenderPass p : queue) { + p.cleanupPass(frameGraph); + } + queue.clear(); + } + + public int shiftIndex(int i) { + if (index > i) { + index--; + } + return index; + } + + public boolean isAsync() { + return index != FrameGraph.RENDER_THREAD; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java index f6978038e3..c317152abf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java @@ -33,7 +33,8 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.util.NativeObject; -import java.util.BitSet; +import java.util.Iterator; +import java.util.LinkedList; import java.util.function.Consumer; /** @@ -51,11 +52,13 @@ public class RenderObject { private final long id; private final T object; - private final BitSet reservations = new BitSet(); + private final LinkedList reservations = new LinkedList<>(); private int timeoutDuration; private int timeout = 0; private boolean acquired = false; private boolean constant = false; + private boolean inspect = false; + private boolean prioritized = false; private Consumer disposer; /** @@ -83,6 +86,23 @@ else if (object instanceof NativeObject) { } } + public void startInspect() { + inspect = true; + } + public void endInspect() { + inspect = false; + } + public boolean isInspect() { + return inspect; + } + + public void setPrioritized(boolean prioritized) { + this.prioritized = prioritized; + } + public boolean isPrioritized() { + return prioritized; + } + /** * Acquires this render object for use. */ @@ -107,22 +127,40 @@ public void release() { * * @param index */ - public void reserve(int index) { - reservations.set(index); + public void reserve(PassIndex index) { + reservations.add(index); } /** * Disposes the internal object. */ public void dispose() { + // ensure this cannot be acquired + acquired = true; disposer.accept(object); } + /** + * Returns true if + * + * @param index + * @return + */ + public boolean claimReservation(PassIndex index) { + for (Iterator it = reservations.iterator(); it.hasNext();) { + if (it.next().equals(index)) { + it.remove(); + return true; + } + } + return false; + } /** * Clears all reservations. */ public void clearReservations() { reservations.clear(); } + /** * Ticks down the timer tracking frames since last use. * @@ -172,8 +210,8 @@ public boolean isAcquired() { * @param index * @return */ - public boolean isReservedAt(int index) { - return reservations.get(index); + public boolean isReservedAt(PassIndex index) { + return reservations.contains(index); } /** * Returns true if this render object is reserved within the time frame. @@ -182,11 +220,11 @@ public boolean isReservedAt(int index) { * @return */ public boolean isReservedWithin(TimeFrame frame) { - if (frame.getStartIndex() >= reservations.size()) { + if (frame.getStartQueueIndex() >= reservations.size()) { return false; } - int n = Math.min(reservations.size()-1, frame.getEndIndex()); - for (int i = frame.getStartIndex(); i <= n; i++) { + int n = Math.min(reservations.size()-1, frame.getEndQueueIndex()); + for (int i = frame.getStartQueueIndex(); i <= n; i++) { if (reservations.get(i)) { return true; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 107c36796c..ad8eb2c6be 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -36,6 +36,9 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * Manages creation, reallocation, and disposal of {@link RenderObject}s. @@ -45,7 +48,8 @@ public class RenderObjectMap { private final RenderManager renderManager; - private final HashMap objectMap = new HashMap<>(); + private final Map objectMap; + private final boolean async; private int staticTimeout = 1; // statistics @@ -58,8 +62,14 @@ public class RenderObjectMap { private int totalObjects = 0; private int flushedObjects = 0; - public RenderObjectMap(RenderManager renderManager) { + public RenderObjectMap(RenderManager renderManager, boolean async) { this.renderManager = renderManager; + this.async = async; + if (this.async) { + objectMap = new ConcurrentHashMap<>(); + } else { + objectMap = new HashMap<>(); + } } /** @@ -99,14 +109,24 @@ protected boolean isAvailable(RenderObject object) { * Allocates a render object to the resource. *

      * First, if this resource holds an object id, the corresponding render object, - * if it still exists, will be tried for reallocation. Then, each render object - * will be tried for reallocation. Finally, if all else fails, a new render object + * if it still exists, will be tried for reallocation. If that fails, each render object + * will be tried for reallocation. Finally, if that fails, a new render object * will be created and allocated to the resource. + *

      + * If this RenderObjectMap is asynchronous, this method is threadsafe. * * @param * @param resource */ public void allocate(RenderResource resource) { + if (async) { + allocateAsync(resource); + } else { + allocateSync(resource); + } + } + + private void allocateSync(RenderResource resource) { if (resource.isUndefined()) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); } @@ -114,7 +134,8 @@ public void allocate(RenderResource resource) { totalAllocations++; ResourceDef def = resource.getDefinition(); if (def.isUseExisting()) { - if (allocateSpecific(resource)) { + // first try allocating a specific object, which is much faster + if (allocateSpecificSync(resource)) { return; } // find object to allocate @@ -122,15 +143,18 @@ public void allocate(RenderResource resource) { RenderObject indirectObj = null; for (RenderObject obj : objectMap.values()) { if (isAvailable(obj) && !obj.isReservedWithin(resource.getLifeTime())) { + // try applying a direct resource T r = def.applyDirectResource(obj.getObject()); if (r != null) { resource.setObject(obj, r); if (cap != null) cap.reallocateObject(obj.getId(), resource.getIndex(), resource.getResource().getClass().getSimpleName()); objectsReallocated++; + obj.endInspect(); return; } - if (indirectObj == null) { + // then try applying an indirect resource, which is not as desirable + if (!obj.isPrioritized() && indirectObj == null) { indirectRes = def.applyIndirectResource(obj.getObject()); if (indirectRes != null) { indirectObj = obj; @@ -138,12 +162,14 @@ public void allocate(RenderResource resource) { } } } + // allocate indirect object if (indirectObj != null) { - // allocate indirect object + indirectObj.startInspect(); resource.setObject(indirectObj, indirectRes); if (cap != null) cap.reallocateObject(indirectObj.getId(), resource.getIndex(), resource.getResource().getClass().getSimpleName()); objectsReallocated++; + indirectObj.endInspect(); return; } } @@ -153,62 +179,164 @@ public void allocate(RenderResource resource) { resource.getIndex(), resource.getResource().getClass().getSimpleName()); objectsCreated++; } - /** - * Allocates the specific render object directly referenced by the resource, - * if one is referenced. - * - * @param - * @param resource - * @return true if the specific render object was allocated - */ - public boolean allocateSpecific(RenderResource resource) { + private boolean allocateSpecificSync(RenderResource resource) { GraphEventCapture cap = renderManager.getGraphCapture(); ResourceDef def = resource.getDefinition(); long id = resource.getTicket().getObjectId(); if (id < 0) return false; // allocate reserved object - RenderObject obj = objectMap.get(id); - if (cap != null) cap.attemptReallocation(id, resource.getIndex()); - if (obj != null && isAvailable(obj) - && (obj.isReservedAt(resource.getLifeTime().getStartIndex()) - || !obj.isReservedWithin(resource.getLifeTime()))) { - // reserved object is only applied if it is accepted by the definition - T r = def.applyDirectResource(obj.getObject()); - if (r == null) { - r = def.applyIndirectResource(obj.getObject()); - } - if (r != null) { - resource.setObject(obj, r); - if (cap != null) cap.reallocateObject(id, resource.getIndex(), - resource.getResource().getClass().getSimpleName()); - completedReservations++; - objectsReallocated++; - return true; + RenderObject obj = objectMap.get(id); + if (obj != null) { + if (cap != null) cap.attemptReallocation(id, resource.getIndex()); + if (isAvailable(obj) && (obj.isReservedAt(resource.getLifeTime().getStartQueueIndex()) + || !obj.isReservedWithin(resource.getLifeTime()))) { + // reserved object is only applied if it is accepted by the definition + T r = def.applyDirectResource(obj.getObject()); + if (r == null) { + r = def.applyIndirectResource(obj.getObject()); + } + if (r != null) { + resource.setObject(obj, r); + if (cap != null) cap.reallocateObject(id, resource.getIndex(), + resource.getResource().getClass().getSimpleName()); + completedReservations++; + objectsReallocated++; + return true; + } } + if (cap != null) cap.allocateSpecificFailed(obj, resource); } failedReservations++; - if (cap != null) cap.allocateSpecificFailed(obj, resource); return false; } - /** - * Directly creates a new render object containing the value for the render - * resource. - *

      - * The object is still subject to the resource's definition, although the definition - * may not have created the internal value. - * - * @param - * @param resource - * @param value - */ - public void allocateDirect(RenderResource resource, T value) { - RenderObject object = create(resource.getDefinition(), value); - resource.setObject(object, value); - if (renderManager.getGraphCapture() != null) { - renderManager.getGraphCapture().setObjectDirect( - object.getId(), resource.getIndex(), value.getClass().getSimpleName()); + private void allocateAsync(RenderResource resource) { + if (resource.isUndefined()) { + throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); + } + GraphEventCapture cap = renderManager.getGraphCapture(); + totalAllocations++; + ResourceDef def = resource.getDefinition(); + if (def.isUseExisting()) { + // first try allocating a specific object, which is much faster + if (allocateSpecificAsync(resource)) { + return; + } + // find object to allocate + T indirectRes = null; + RenderObject indirectObj = null; + LinkedList skipped = new LinkedList<>(); + Iterator it = objectMap.values().iterator(); + boolean next; + while ((next = it.hasNext()) || !skipped.isEmpty()) { + RenderObject obj; + if (next) obj = it.next(); + else obj = skipped.removeFirst(); + if (isAvailable(obj)) { + if ((next || !skipped.isEmpty()) && obj.isInspect()) { + // Inspect this object later, because something else is inspecting it. + // This makes this thread try other objects first, instead of waiting + // for a synchronized block to be available. + skipped.addLast(obj); + continue; + } + // If multiple threads do happen to be here at the same time, ensure only one + // will inspect at a time. + synchronized (obj) { + // The thread we were waiting on may have claimed to object, so check again + // if it is available. + if (!isAvailable(obj)) { + continue; + } + obj.startInspect(); + if (!obj.isReservedWithin(resource.getLifeTime())) { + // try applying a direct resource + T r = def.applyDirectResource(obj.getObject()); + if (r != null) { + resource.setObject(obj, r); + if (cap != null) cap.reallocateObject(obj.getId(), resource.getIndex(), + resource.getResource().getClass().getSimpleName()); + objectsReallocated++; + obj.endInspect(); + return; + } + // then try applying an indirect resource, which is not as desirable + if (!obj.isPrioritized() && indirectObj == null) { + indirectRes = def.applyIndirectResource(obj.getObject()); + if (indirectRes != null) { + indirectObj = obj; + // make sure no other thread attempts to apply this indirectly at the same time + obj.setPrioritized(true); + obj.endInspect(); + continue; + } + } + } + obj.endInspect(); + } + } + } + // allocate indirect object + if (indirectObj != null) synchronized (indirectObj) { + // disable priority flag + indirectObj.setPrioritized(false); + // check again if object is available + if (isAvailable(indirectObj)) { + indirectObj.startInspect(); + resource.setObject(indirectObj, indirectRes); + if (cap != null) cap.reallocateObject(indirectObj.getId(), resource.getIndex(), + resource.getResource().getClass().getSimpleName()); + objectsReallocated++; + indirectObj.endInspect(); + } else { + // In the unlikely event that another thread "steals" this object + // from this thread, try allocating again. + allocateAsync(resource); + } + return; + } } + // create new object + resource.setObject(create(def)); + if (cap != null) cap.createObject(resource.getObject().getId(), + resource.getIndex(), resource.getResource().getClass().getSimpleName()); + objectsCreated++; + } + private boolean allocateSpecificAsync(RenderResource resource) { + GraphEventCapture cap = renderManager.getGraphCapture(); + ResourceDef def = resource.getDefinition(); + long id = resource.getTicket().getObjectId(); + if (id < 0) return false; + // allocate reserved object + RenderObject obj = objectMap.get(id); + if (obj != null) { + if (cap != null) cap.attemptReallocation(id, resource.getIndex()); + if (isAvailable(obj)) synchronized (obj) { + obj.startInspect(); + if ((obj.isReservedAt(resource.getLifeTime().getStartQueueIndex()) + || !obj.isReservedWithin(resource.getLifeTime()))) { + // reserved object is only applied if it is accepted by the definition + T r = def.applyDirectResource(obj.getObject()); + if (r == null) { + r = def.applyIndirectResource(obj.getObject()); + } + if (r != null) { + resource.setObject(obj, r); + if (cap != null) cap.reallocateObject(id, resource.getIndex(), + resource.getResource().getClass().getSimpleName()); + completedReservations++; + objectsReallocated++; + obj.endInspect(); + return true; + } + } + obj.endInspect(); + } + if (cap != null) cap.allocateSpecificFailed(obj, resource); + } + failedReservations++; + return false; } + /** * Makes a reservation of render object holding the specified id at the render * pass index so that no other resource may (without a reservation) use that @@ -218,7 +346,7 @@ public void allocateDirect(RenderResource resource, T value) { * @param index * @return */ - public boolean reserve(long objectId, int index) { + public boolean reserve(long objectId, PassIndex index) { RenderObject obj = objectMap.get(objectId); if (obj != null) { obj.reserve(index); @@ -230,39 +358,6 @@ public boolean reserve(long objectId, int index) { } return false; } - /** - * Untracks the render object held by the resource. - *

      - * If the resource is virtual, a new resource will be allocated then - * immediately untracked. - * - * @param - * @param resource - * @return - */ - public T extract(RenderResource resource) { - if (resource.isUndefined()) { - return null; - } - if (resource.isVirtual()) { - allocate(resource); - } - RenderObject obj = objectMap.remove(resource.getTicket().getObjectId()); - return (obj != null ? obj.getObject() : null); - } - /** - * Removes the render object holding the given value from the map. - * - * @param value - */ - public void remove(Object value) { - for (Iterator it = objectMap.values().iterator(); it.hasNext();) { - RenderObject object = it.next(); - if (object.getObject() == value) { - it.remove(); - } - } - } /** * Disposes the render object pointed to by the resource. * @@ -273,10 +368,10 @@ public void dispose(RenderResource resource) { if (id >= 0) { RenderObject obj = objectMap.remove(id); if (obj != null) { + obj.dispose(); if (renderManager.getGraphCapture() != null) { renderManager.getGraphCapture().disposeObject(id); } - obj.dispose(); } } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 5c64e6e811..e7dbacdbb1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -42,10 +42,10 @@ */ public class RenderResource { - private final ResourceProducer producer; - private final ResourceDef def; - private final ResourceTicket ticket; - private final TimeFrame lifetime; + private ResourceProducer producer; + private ResourceDef def; + private ResourceTicket ticket; + private TimeFrame lifetime; private RenderObject object; private T resource; private int refs = 0; @@ -70,7 +70,7 @@ public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTic * * @param index */ - public void reference(int index) { + public void reference(PassIndex index) { lifetime.extendTo(index); refs++; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 01e93309ba..26f6e1fe29 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -52,6 +52,7 @@ public class ResourceList { private RenderObjectMap map; private GraphEventCapture cap; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); + private LinkedList references = new LinkedList<>(); private int nextSlot = 0; private int textureBinds = 0; @@ -183,7 +184,7 @@ public ResourceTicket declare(ResourceProducer producer, ResourceDef d * @param passIndex * @param ticket */ - public void reserve(int passIndex, ResourceTicket ticket) { + public void reserve(PassIndex passIndex, ResourceTicket ticket) { if (ticket.getObjectId() >= 0) { map.reserve(ticket.getObjectId(), passIndex); ticket.copyObjectTo(locate(ticket).getTicket()); @@ -196,7 +197,7 @@ public void reserve(int passIndex, ResourceTicket ticket) { * @param passIndex * @param tickets */ - public void reserve(int passIndex, ResourceTicket... tickets) { + public void reserve(PassIndex passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { reserve(passIndex, t); } @@ -212,7 +213,7 @@ public void reserve(int passIndex, ResourceTicket... tickets) { * @param passIndex render pass index * @param ticket */ - public void reference(int passIndex, ResourceTicket ticket) { + public void reference(PassIndex passIndex, ResourceTicket ticket) { RenderResource resource = locate(ticket); resource.reference(passIndex); if (cap != null) cap.referenceResource(resource.getIndex(), ticket.getName()); @@ -226,7 +227,7 @@ public void reference(int passIndex, ResourceTicket ticket) { * @param ticket * @return */ - public boolean referenceOptional(int passIndex, ResourceTicket ticket) { + public boolean referenceOptional(PassIndex passIndex, ResourceTicket ticket) { if (validate(ticket)) { reference(passIndex, ticket); return true; @@ -240,7 +241,7 @@ public boolean referenceOptional(int passIndex, ResourceTicket ticket) { * @param passIndex render pass index * @param tickets */ - public void reference(int passIndex, ResourceTicket... tickets) { + public void reference(PassIndex passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { reference(passIndex, t); } @@ -252,7 +253,7 @@ public void reference(int passIndex, ResourceTicket... tickets) { * @param passIndex render pass index * @param tickets */ - public void referenceOptional(int passIndex, ResourceTicket... tickets) { + public void referenceOptional(PassIndex passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { referenceOptional(passIndex, t); } @@ -543,52 +544,6 @@ public void setPrimitive(ResourceTicket ticket, T value) { locate(ticket).setPrimitive(value); } - protected T extract(RenderResource resource, ResourceTicket ticket) { - if (!resource.isUsed()) { - throw new IllegalStateException(resource+" was unexpectedly extracted."); - } - resource.getTicket().copyObjectTo(ticket); - return map.extract(resource); - } - - /** - * Permanently extracts the object from the object manager. - *

      - * Extracted objects are no longer tracked by the object manager, - * and can therefore not be reallocated for any task. - * - * @param - * @param ticket - * @return - */ - public T extract(ResourceTicket ticket) { - RenderResource resource = locate(ticket); - T object = extract(resource, ticket); - if (object == null) { - throw new NullPointerException("Failed to extract resource."); - } - return object; - } - - /** - * If the ticket is not null and has a positive or zero world index, an object - * will be extracted by the resource and returned. - *

      - * Otherwise, the given default value will be returned. - * - * @param - * @param ticket - * @param value - * @return - */ - public T extractOrElse(ResourceTicket ticket, T value) { - if (ticket != null && ticket.getWorldIndex() >= 0) { - T object = extract(locate(ticket), ticket); - if (object != null) return object; - } - return value; - } - /** * Releases the resource from use. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java index d9ffb49938..7637a849c0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java @@ -45,7 +45,7 @@ public interface ResourceProducer { * * @return */ - public int getExecutionIndex(); + public PassIndex getExecutionIndex(); /** * Dereferences this producer. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java index ba6ec2b958..6ea12fb753 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java @@ -39,7 +39,7 @@ import java.io.IOException; /** - * Represents an abstract connection between render passes. + * Represents an abstract connection between render passes that can be saved. * * @author codex */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java index 206b1a34bc..8238cc293b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java @@ -34,12 +34,16 @@ /** * Represents a period of time starting at the start of the indexed pass, and * lasting for the duration of a number of following passes. + *

      + * An asynchronous timeframe indicates that the end is unpredictable. * * @author codex */ public class TimeFrame { - private int index, length; + private int thread; + private int queue, length; + private boolean async = false; /** * @@ -47,13 +51,14 @@ public class TimeFrame { private TimeFrame() {} /** * - * @param passIndex + * @param index * @param length */ - public TimeFrame(int passIndex, int length) { - this.index = passIndex; + public TimeFrame(PassIndex index, int length) { + this.thread = index.getThreadIndex(); + this.queue = index.getQueueIndex(); this.length = length; - if (this.index < 0) { + if (this.queue < 0) { throw new IllegalArgumentException("Pass index cannot be negative."); } if (this.length < 0) { @@ -62,13 +67,16 @@ public TimeFrame(int passIndex, int length) { } /** - * Extends, but does not retract, the length so that this time frame - * includes the given index. + * Extends the length so that this time frame includes the given index. * * @param passIndex */ - public void extendTo(int passIndex) { - length = Math.max(length, passIndex-this.index); + public void extendTo(PassIndex passIndex) { + if (passIndex.getThreadIndex() != thread) { + async = true; + } else { + length = Math.max(length, passIndex.getQueueIndex()-this.queue); + } } /** * Copies this to the target time frame. @@ -80,18 +88,28 @@ public TimeFrame copyTo(TimeFrame target) { if (target == null) { target = new TimeFrame(); } - target.index = index; + target.thread = thread; + target.queue = queue; target.length = length; + target.async = async; return target; } + /** + * Gets the index of the thread this timeframe is based from. + * + * @return + */ + public int getThreadIndex() { + return thread; + } /** * Gets index of the first pass this time frame includes. * * @return */ - public int getStartIndex() { - return index; + public int getStartQueueIndex() { + return queue; } /** * Gets the length. @@ -106,8 +124,18 @@ public int getLength() { * * @return */ - public int getEndIndex() { - return index+length; + public int getEndQueueIndex() { + return queue+length; + } + /** + * Returns true if this timeframe is asynchronous. + *

      + * An asynchronous timeframe's end index is unreliable. + * + * @return + */ + public boolean isAsync() { + return async; } /** @@ -117,7 +145,7 @@ public int getEndIndex() { * @return */ public boolean overlaps(TimeFrame time) { - return index <= time.index+time.length && index+length >= time.index; + return queue <= time.queue+time.length && queue+length >= time.queue; } /** * Returns true if this time frame includes the given index. @@ -126,7 +154,7 @@ public boolean overlaps(TimeFrame time) { * @return */ public boolean includes(int index) { - return index <= index && index+length >= index; + return queue <= index && queue+length >= index; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java index c1de89125f..d4e0ee99fa 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java @@ -103,7 +103,7 @@ public void allocateSpecificFailed(RenderObject object, RenderResource resource) new Check("nullObject", () -> object != null, true), new Check("acquired", () -> !object.isAcquired()), new Check("constant", () -> !object.isConstant()), - new Check("conflicting", () -> object.isReservedAt(resource.getLifeTime().getStartIndex()) + new Check("conflicting", () -> object.isReservedAt(resource.getLifeTime().getStartQueueIndex()) || !object.isReservedWithin(resource.getLifeTime())) )); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 08bcfacac3..2e112eaa20 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -38,6 +38,7 @@ import com.jme3.export.Savable; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.PassIndex; import com.jme3.renderer.framegraph.ResourceList; import com.jme3.renderer.framegraph.ResourceProducer; import com.jme3.renderer.framegraph.ResourceTicket; @@ -66,7 +67,7 @@ public abstract class RenderPass implements ResourceProducer, Savable { private int exportId = -1; private String name; protected FrameGraph frameGraph; - private int index = -1; + private PassIndex index; private int refs = 0; private final LinkedList inputs = new LinkedList<>(); private final LinkedList outputs = new LinkedList<>(); @@ -81,7 +82,7 @@ public abstract class RenderPass implements ResourceProducer, Savable { * @param frameGraph * @param index execution index */ - public void initializePass(FrameGraph frameGraph, int index) { + public void initializePass(FrameGraph frameGraph, PassIndex index) { this.frameGraph = frameGraph; this.index = index; this.resources = frameGraph.getResources(); @@ -100,6 +101,14 @@ public void prepareRender(FGRenderContext context) { throw new IllegalStateException("Pass is not properly initialized for rendering."); } prepare(context); + } + /** + * + * @param context + * @return + */ + public boolean asyncWait(FGRenderContext context) { + } /** * Executes the pass. @@ -883,7 +892,7 @@ public int getNumGroups() { } @Override - public int getExecutionIndex() { + public PassIndex getExecutionIndex() { return index; } @Override From a3eee4c7c89426161f8cce1508a5c730169d10d6 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 26 Jun 2024 18:16:51 -0400 Subject: [PATCH 100/111] added multithreading --- .../java/com/jme3/renderer/RenderManager.java | 2 +- .../com/jme3/renderer/framegraph/Access.java | 53 ++++++++ .../renderer/framegraph/FGRenderContext.java | 2 +- .../jme3/renderer/framegraph/FrameGraph.java | 56 ++++++-- .../renderer/framegraph/FrameGraphData.java | 69 +++++----- .../framegraph/FrameGraphFactory.java | 10 +- .../jme3/renderer/framegraph/PassIndex.java | 14 +- .../framegraph/PassQueueExecutor.java | 127 +++++++++++++++--- .../renderer/framegraph/RenderObject.java | 73 +++++----- .../renderer/framegraph/RenderObjectMap.java | 35 +---- .../renderer/framegraph/RenderResource.java | 24 +++- .../renderer/framegraph/ResourceList.java | 104 +++++++------- .../framegraph/debug/GraphEventCapture.java | 16 +-- .../framegraph/passes/DeferredPass.java | 3 + .../framegraph/passes/GBufferPass.java | 13 -- .../framegraph/passes/RenderPass.java | 22 +-- .../framegraph/passes/SceneEnqueuePass.java | 25 +++- .../TestSimpleDeferredLighting.java | 2 +- 18 files changed, 413 insertions(+), 237 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.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 d22cbdf47e..1023798171 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -127,7 +127,7 @@ public class RenderManager { public RenderManager(Renderer renderer) { this.renderer = renderer; this.forcedOverrides.add(boundDrawBufferId); - this.renderObjects = new RenderObjectMap(this); + this.renderObjects = new RenderObjectMap(this, true); } /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java new file mode 100644 index 0000000000..3690e42b99 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java @@ -0,0 +1,53 @@ +/* + * 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 enum Access { + + /** + * Indicates that the resource is accessed for reading only. + */ + Read(true, false), + + /** + * Indicates that the resource is accessed for writing only. + */ + Write(false, true), + + /** + * Indicates that the resource is accessed for both reading and writing. + */ + ReadAndWrite(true, true); + + private final boolean read, write; + + private Access(boolean read, boolean write) { + this.read = read; + this.write = write; + } + + /** + * Returns true if the access is for reading. + * + * @return + */ + public boolean isRead() { + return read; + } + + /** + * Returns true if the access is for writing. + * + * @return + */ + public boolean isWrite() { + return write; + } + +} 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 73eb61542f..4a7e04a84c 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 @@ -326,7 +326,7 @@ public boolean isProfilerAvailable() { * * @return */ - public boolean isFrameCaptureActive() { + public boolean isGraphCaptureActive() { return renderManager.getGraphCapture() != null; } 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 6928ed2970..b744af0c81 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 @@ -40,14 +40,13 @@ import com.jme3.profile.FgStep; import com.jme3.profile.VpStep; import com.jme3.renderer.RenderManager; +import com.jme3.renderer.RendererException; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.client.GraphSetting; import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.passes.Attribute; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; /** * Manages render passes, dependencies, and resources in a node-based parameter system. @@ -101,6 +100,7 @@ public class FrameGraph { private final HashMap settings = new HashMap<>(); private String name = "FrameGraph"; private boolean rendered = false; + private Exception renderException; /** * Creates a new blank framegraph. @@ -109,7 +109,7 @@ public class FrameGraph { */ public FrameGraph(AssetManager assetManager) { this.assetManager = assetManager; - this.resources = new ResourceList(); + this.resources = new ResourceList(this); this.context = new FGRenderContext(this); this.queues.add(new PassQueueExecutor(this, RENDER_THREAD)); } @@ -197,9 +197,14 @@ public boolean execute() { // execute if (prof != null) prof.vpStep(VpStep.FrameGraphExecute, vp, null); context.pushRenderSettings(); + renderException = null; for (PassQueueExecutor p : queues) { p.execute(context); } + if (renderException != null) { + renderException.printStackTrace(System.err); + throw new RendererException("An uncaught rendering exception occured, forcing the application to shut down."); + } context.popFrameBuffer(); // reset if (prof != null) prof.vpStep(VpStep.FrameGraphReset, vp, null); @@ -228,6 +233,16 @@ public void renderingComplete() { rendered = false; } + private PassQueueExecutor getQueue(int i) { + if (i >= queues.size()) { + PassQueueExecutor queue = new PassQueueExecutor(this, i); + queues.add(queue); + return queue; + } else { + return queues.get(i); + } + } + /** * Adds the pass to end of the pass queue. * @@ -236,7 +251,18 @@ public void renderingComplete() { * @return given pass */ public T add(T pass) { - return queues.get(RENDER_THREAD).add(pass); + return getQueue(RENDER_THREAD).add(pass); + } + /** + * + * + * @param + * @param pass + * @param threadIndex + * @return + */ + public T add(T pass, int threadIndex) { + return getQueue(threadIndex).add(pass); } /** * Adds the pass at the index in the pass queue. @@ -247,11 +273,12 @@ public T add(T pass) { * * @param * @param pass - * @param index + * @param threadIndex + * @param queueIndex * @return */ - public T add(T pass, int index) { - return queues.get(RENDER_THREAD).add(pass, index); + public T add(T pass, int threadIndex, int queueIndex) { + return getQueue(threadIndex).add(pass, queueIndex); } /** * Creates and adds an Attribute pass and links it to the given ticket. @@ -263,7 +290,7 @@ public T add(T pass, int index) { * @return created Attribute */ public Attribute addAttribute(ResourceTicket ticket) { - return queues.get(RENDER_THREAD).addAttribute(ticket); + return getQueue(RENDER_THREAD).addAttribute(ticket); } /** @@ -466,6 +493,19 @@ public void setCLQueue(CommandQueue clQueue) { context.setCLQueue(clQueue); } + /** + * Called internally when a rendering exception occurs. + * + * @param ex + */ + public void interruptRendering(Exception ex) { + assert ex != null : "Interrupting exception cannot be null."; + renderException = ex; + for (PassQueueExecutor q : queues) { + q.interrupt(); + } + } + /** * * @return diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java index 2e144c9fae..abf4912805 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java @@ -39,7 +39,7 @@ import com.jme3.export.SavableObject; import com.jme3.renderer.framegraph.passes.RenderPass; import java.io.IOException; -import java.util.Collection; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; @@ -54,22 +54,22 @@ public class FrameGraphData implements Savable { private static final String DEF_NAME = "FrameGraph"; - private static final RenderPass[] DEF_PASSES = new RenderPass[0]; + private static final ArrayList DEF_QUEUES = new ArrayList<>(0); private static final SavablePassConnection[] DEF_CONNECTIONS = new SavablePassConnection[0]; private static final HashMap DEF_SETTINGS = new HashMap<>(); private final boolean export; private String name; - private RenderPass[] passes; + private ArrayList queues; private SavablePassConnection[] connections; private Map settings; public FrameGraphData() { export = false; } - public FrameGraphData(FrameGraph fg, Collection passes, Map settings) { + public FrameGraphData(FrameGraph fg, ArrayList queues, Map settings) { this.name = fg.getName(); - this.passes = passes.toArray(new RenderPass[0]); + this.queues = queues; this.settings = new HashMap<>(); for (String key : settings.keySet()) { this.settings.put(key, new SavableObject(settings.get(key))); @@ -82,36 +82,42 @@ public void write(JmeExporter ex) throws IOException { if (!export) { throw new IllegalStateException("Data is import only."); } - if (passes == null) { + if (queues == null) { throw new IllegalStateException("Data is already consumed."); } final HashMap idMap = new HashMap<>(); final LinkedList list = new LinkedList<>(); int nextId = 0; // remap ids - for (RenderPass p : passes) { - p.setExportId(nextId++); - idMap.put(p.getId(), p.getExportId()); + for (PassQueueExecutor q : queues) { + for (RenderPass p : q) { + p.setExportId(nextId++); + idMap.put(p.getId(), p.getExportId()); + } } // extract connections - for (RenderPass p : passes) for (ResourceTicket t : p.getInputTickets()) { - if (t.hasSource()) { - int outId = idMap.get(t.getSource().getPassId()); - list.add(new SavablePassConnection(p.getExportId(), outId, t.getName(), t.getSource().getName())); + for (PassQueueExecutor q : queues) { + for (RenderPass p : q) for (ResourceTicket t : p.getInputTickets()) { + if (t.hasSource()) { + int outId = idMap.get(t.getSource().getPassId()); + list.add(new SavablePassConnection(p.getExportId(), outId, t.getName(), t.getSource().getName())); + } } } OutputCapsule out = ex.getCapsule(this); out.write(name, "name", DEF_NAME); - out.write(passes, "passes", DEF_PASSES); + out.writeSavableArrayList(queues, "passes", DEF_QUEUES); out.write(list.toArray(new SavablePassConnection[0]), "connections", DEF_CONNECTIONS); out.writeStringSavableMap(settings, "settings", DEF_SETTINGS); // reset export ids - for (RenderPass p : passes) { - p.setExportId(-1); + for (PassQueueExecutor q : queues) { + for (RenderPass p : q) { + p.setExportId(-1); + } } idMap.clear(); list.clear(); - passes = null; + queues = null; settings.clear(); } @Override @@ -122,13 +128,13 @@ public void read(JmeImporter im) throws IOException { InputCapsule in = im.getCapsule(this); name = in.readString("name", "FrameGraph"); int baseId = RenderPass.getNextId(); - Savable[] array = in.readSavableArray("passes", new RenderPass[0]); - passes = new RenderPass[array.length]; - for (int i = 0; i < array.length; i++) { - RenderPass p = passes[i] = (RenderPass)array[i]; - p.shiftId(baseId); + queues = in.readSavableArrayList("passes", DEF_QUEUES); + for (PassQueueExecutor q : queues) { + for (RenderPass p : q) { + p.shiftId(baseId); + } } - array = in.readSavableArray("connections", new SavablePassConnection[0]); + Savable[] array = in.readSavableArray("connections", new SavablePassConnection[0]); connections = new SavablePassConnection[array.length]; for (int i = 0; i < array.length; i++) { SavablePassConnection c = connections[i] = (SavablePassConnection)array[i]; @@ -148,17 +154,17 @@ public void apply(FrameGraph fg) { if (export) { throw new IllegalStateException("Data is export only."); } - if (passes == null) { + if (queues == null) { throw new IllegalStateException("Data has already been consumed."); } fg.setName(name); - for (RenderPass p : passes) { - fg.add(p); - } // cache passes by id HashMap cache = new HashMap<>(); - for (RenderPass p : passes) { - cache.put(p.getId(), p); + for (PassQueueExecutor q : queues) { + for (RenderPass p : q) { + fg.add(p, q.getIndex()); + cache.put(p.getId(), p); + } } // read connections for (SavablePassConnection c : connections) { @@ -171,7 +177,7 @@ public void apply(FrameGraph fg) { fg.setSetting(key, settings.get(key).getObject()); } cache.clear(); - passes = null; + queues = null; connections = null; } @@ -183,13 +189,14 @@ public void apply(FrameGraph fg) { public boolean isExportOnly() { return export; } + /** * Returns true if this data has been consumed. * * @return */ public boolean isConsumed() { - return passes == null; + return queues == null; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 53ee9169dc..22b3bc04d3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -41,9 +41,7 @@ import com.jme3.renderer.framegraph.passes.LightImagePass; import com.jme3.renderer.framegraph.passes.OutputRenderPass; import com.jme3.renderer.framegraph.passes.OutputPass; -import com.jme3.renderer.framegraph.passes.PostProcessingRenderPass; import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; -import com.jme3.renderer.queue.RenderQueue; /** * Utility class for constructing common framegraphs. @@ -96,7 +94,7 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { GBufferPass gbuf = fg.add(new GBufferPass()); Attribute tileInfoAttr = fg.add(new Attribute()); Junction tileJunct1 = fg.add(new Junction(1, 1)); - LightImagePass lightImg = fg.add(new LightImagePass()); + LightImagePass lightImg = fg.add(new LightImagePass(), 1); Junction lightJunct = fg.add(new Junction(1, 6)); Junction tileJunct2 = fg.add(new Junction(1, 2)); DeferredPass deferred = fg.add(new DeferredPass()); @@ -116,8 +114,8 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { tileJunct1.makeInput(tileInfoAttr, Attribute.OUTPUT, Junction.getInput(0)); tileJunct1.setIndexSource(tileToggle); - lightImg.makeInput(gbuf, "Lights", "Lights"); - lightImg.makeInput(tileInfoAttr, Attribute.OUTPUT, "TileInfo"); + lightImg.makeInput(enqueue, "OpaqueLights", "Lights"); + lightImg.makeInput(tileJunct1, Junction.getOutput(), "TileInfo"); GraphSetting lightPackMethod = fg.setSetting("LightPackMethod", tiled ? 0 : -1, true); lightJunct.setName("LightPackMethod"); @@ -131,7 +129,7 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { tileJunct2.setIndexSource(tileToggle); deferred.makeGroupInput(gbuf, "GBufferData", "GBufferData"); - deferred.makeInput(gbuf, "Lights", "Lights"); + deferred.makeInput(enqueue, "OpaqueLights", "Lights"); deferred.makeGroupInput(lightJunct, Junction.getOutput(), "LightTextures", 0, 0, 3); deferred.makeInput(lightJunct, Junction.getOutput(3), "NumLights"); deferred.makeInput(lightJunct, Junction.getOutput(4), "Ambient"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java index 5b9bff668c..9eb670537f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java @@ -27,28 +27,30 @@ public PassIndex set(PassIndex index) { } /** - * Shifts the thread index down one if the thread index is greater + * Shifts the thread index up or down one if the thread index is greater * than the given index. * * @param i + * @param pos * @return new thread index */ - public int shiftThread(int i) { + public int shiftThread(int i, boolean pos) { if (threadIndex > i) { - threadIndex--; + threadIndex += pos ? 1 : -1; } return threadIndex; } /** - * Shifts the queue index down one if the thread index is greater than + * Shifts the queue index up or down one if the thread index is greater than * the given index. * * @param i + * @param pos * @return new queue index */ - public int shiftQueue(int i) { + public int shiftQueue(int i, boolean pos) { if (queueIndex > i) { - queueIndex--; + queueIndex += pos ? 1 : -1; } return queueIndex; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java index fc327c5253..29df3a77ac 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java @@ -4,24 +4,36 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.profile.FgStep; -import static com.jme3.renderer.framegraph.FrameGraph.RENDER_THREAD; import com.jme3.renderer.framegraph.passes.Attribute; import com.jme3.renderer.framegraph.passes.RenderPass; +import java.io.IOException; +import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; +import java.util.concurrent.TimeoutException; /** * * @author codex */ -public class PassQueueExecutor implements Runnable, Iterable { +public class PassQueueExecutor implements Runnable, Iterable, Savable { + + private static long threadTimeoutMillis = 5000; + private static final ArrayList DEF_QUEUE = new ArrayList<>(0); private final FrameGraph frameGraph; private final LinkedList queue = new LinkedList<>(); private int index; private Thread thread; private FGRenderContext context; + private boolean complete = false; + private boolean interrupted = false; public PassQueueExecutor(FrameGraph frameGraph, int index) { this.frameGraph = frameGraph; @@ -30,34 +42,87 @@ public PassQueueExecutor(FrameGraph frameGraph, int index) { @Override public void run() { - boolean async = isAsync(); - for (RenderPass p : queue) { - if (p.isUsed()) { - /*if (!async) { - if (context.isProfilerAvailable()) context.getProfiler().fgStep(FgStep.Execute, p.getProfilerName()); - if (cap != null) cap.executeRenderPass(p.getIndex(), p.getProfilerName()); - }*/ - p.executeRender(context); - if (!async) { - context.popRenderSettings(); - } - } + try { + execute(); + } catch (Exception ex) { + frameGraph.interruptRendering(ex); } } @Override public Iterator iterator() { return queue.iterator(); } + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + ArrayList list = new ArrayList<>(queue.size()); + list.addAll(queue); + out.writeSavableArrayList(list, "queue", DEF_QUEUE); + out.write(index, "index", 0); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + queue.addAll(in.readSavableArrayList("queue", DEF_QUEUE)); + index = in.readInt("index", 0); + } public void execute(FGRenderContext context) { - if (!isAsync()) { - run(); + complete = false; + this.context = context; + if (index == FrameGraph.RENDER_THREAD) { + execute(); } else { thread = new Thread(this); thread.start(); } } + @SuppressWarnings("UseSpecificCatch") + private void execute() { + try { + for (RenderPass p : queue) { + if (interrupted) { + return; + } + if (!p.isUsed()) { + continue; + } + if (index == FrameGraph.RENDER_THREAD) { + if (context.isProfilerAvailable()) { + context.getProfiler().fgStep(FgStep.Execute, p.getProfilerName()); + } + if (context.isGraphCaptureActive()) { + context.getGraphCapture().executeRenderPass(p.getIndex(), p.getProfilerName()); + } + } + if (frameGraph.isAsync()) { + // wait until all input resources are available for use before executing + long startMillis = System.currentTimeMillis(); + while (!p.allInputsAvailable(context)) { + if (interrupted) { + return; + } + if (System.currentTimeMillis()-startMillis >= threadTimeoutMillis) { + throw new TimeoutException("Execution thread "+index+" timed out on pass "+p); + } + } + } + p.executeRender(context); + if (index == FrameGraph.RENDER_THREAD) { + context.popRenderSettings(); + } + } + complete = true; + } catch (Exception ex) { + frameGraph.interruptRendering(ex); + } + } + + public void interrupt() { + interrupted = true; + } + /** * Adds the pass to end of the pass queue. * @@ -230,15 +295,41 @@ public void clear() { queue.clear(); } - public int shiftIndex(int i) { + public int shiftIndex(int i, boolean pos) { if (index > i) { - index--; + index += pos ? 1 : -1; } return index; } + public int size() { + return queue.size(); + } + public int getIndex() { + return index; + } public boolean isAsync() { return index != FrameGraph.RENDER_THREAD; } + public boolean isComplete() { + return complete; + } + + /** + * Sets the duration, in milliseconds, that executors will wait + * for pass inputs to be available before aborting execution. + *

      + * Timeouts can only occur when multiple threads are running. + *

      + * default=5000 (5 seconds) + * + * @param threadTimeoutMillis + */ + public static void setThreadTimeoutMillis(long threadTimeoutMillis) { + PassQueueExecutor.threadTimeoutMillis = threadTimeoutMillis; + } + public static long getThreadTimeoutMillis() { + return threadTimeoutMillis; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java index c317152abf..2cfcbc9e90 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java @@ -52,7 +52,7 @@ public class RenderObject { private final long id; private final T object; - private final LinkedList reservations = new LinkedList<>(); + private final LinkedList reservations = new LinkedList<>(); private int timeoutDuration; private int timeout = 0; private boolean acquired = false; @@ -128,7 +128,7 @@ public void release() { * @param index */ public void reserve(PassIndex index) { - reservations.add(index); + reservations.add(new Reservation(index)); } /** * Disposes the internal object. @@ -146,11 +146,20 @@ public void dispose() { * @return */ public boolean claimReservation(PassIndex index) { - for (Iterator it = reservations.iterator(); it.hasNext();) { - if (it.next().equals(index)) { - it.remove(); - return true; - } + for (Reservation r : reservations) { + if (r.claim(index)) return true; + } + return false; + } + /** + * Returns true if this render object is reserved within the time frame. + * + * @param frame + * @return + */ + public boolean isReservedWithin(TimeFrame frame) { + for (Reservation r : reservations) { + if (r.violates(frame)) return true; } return false; } @@ -203,34 +212,6 @@ public T getObject() { public boolean isAcquired() { return acquired; } - /** - * Returns true if this render object is reserved at the given - * render pass index. - * - * @param index - * @return - */ - public boolean isReservedAt(PassIndex index) { - return reservations.contains(index); - } - /** - * Returns true if this render object is reserved within the time frame. - * - * @param frame - * @return - */ - public boolean isReservedWithin(TimeFrame frame) { - if (frame.getStartQueueIndex() >= reservations.size()) { - return false; - } - int n = Math.min(reservations.size()-1, frame.getEndQueueIndex()); - for (int i = frame.getStartQueueIndex(); i <= n; i++) { - if (reservations.get(i)) { - return true; - } - } - return false; - } /** * Returns true if this render object is constant. * @@ -249,4 +230,26 @@ public static long getNextId() { return nextId; } + private static class Reservation { + + private final PassIndex index; + private boolean claimed = false; + + public Reservation(PassIndex index) { + this.index = index; + } + + public boolean claim(PassIndex index) { + if (this.index.equals(index)) { + claimed = true; + return true; + } + return false; + } + public boolean violates(TimeFrame frame) { + return !claimed && (frame.isAsync() || frame.getThreadIndex() != index.getThreadIndex()); + } + + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index ad8eb2c6be..6ec0a1c10b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -72,36 +72,15 @@ public RenderObjectMap(RenderManager renderManager, boolean async) { } } - /** - * Creates a new render object with a new internal object. - * - * @param - * @param def - * @return - */ - protected RenderObject create(ResourceDef def) { + private RenderObject create(ResourceDef def) { return create(def, def.createResource()); } - /** - * Creates a new render object with the given internal object. - * - * @param - * @param def - * @param value internal object - * @return - */ - protected RenderObject create(ResourceDef def, T value) { + private RenderObject create(ResourceDef def, T value) { RenderObject obj = new RenderObject(def, value, staticTimeout); objectMap.put(obj.getId(), obj); return obj; } - /** - * Returns true if the render object is available for reallocation. - * - * @param object - * @return - */ - protected boolean isAvailable(RenderObject object) { + private boolean isAvailable(RenderObject object) { return !object.isAcquired() && !object.isConstant(); } @@ -188,7 +167,7 @@ private boolean allocateSpecificSync(RenderResource resource) { RenderObject obj = objectMap.get(id); if (obj != null) { if (cap != null) cap.attemptReallocation(id, resource.getIndex()); - if (isAvailable(obj) && (obj.isReservedAt(resource.getLifeTime().getStartQueueIndex()) + if (isAvailable(obj) && (obj.claimReservation(resource.getProducer().getExecutionIndex()) || !obj.isReservedWithin(resource.getLifeTime()))) { // reserved object is only applied if it is accepted by the definition T r = def.applyDirectResource(obj.getObject()); @@ -204,7 +183,6 @@ private boolean allocateSpecificSync(RenderResource resource) { return true; } } - if (cap != null) cap.allocateSpecificFailed(obj, resource); } failedReservations++; return false; @@ -312,8 +290,8 @@ private boolean allocateSpecificAsync(RenderResource resource) { if (cap != null) cap.attemptReallocation(id, resource.getIndex()); if (isAvailable(obj)) synchronized (obj) { obj.startInspect(); - if ((obj.isReservedAt(resource.getLifeTime().getStartQueueIndex()) - || !obj.isReservedWithin(resource.getLifeTime()))) { + if (obj.claimReservation(resource.getProducer().getExecutionIndex()) + || !obj.isReservedWithin(resource.getLifeTime())) { // reserved object is only applied if it is accepted by the definition T r = def.applyDirectResource(obj.getObject()); if (r == null) { @@ -331,7 +309,6 @@ private boolean allocateSpecificAsync(RenderResource resource) { } obj.endInspect(); } - if (cap != null) cap.allocateSpecificFailed(obj, resource); } failedReservations++; return false; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index e7dbacdbb1..f324676088 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -42,21 +42,23 @@ */ public class RenderResource { - private ResourceProducer producer; - private ResourceDef def; - private ResourceTicket ticket; - private TimeFrame lifetime; + private final ResourceProducer producer; + private final ResourceDef def; + private final ResourceTicket ticket; + private final TimeFrame lifetime; private RenderObject object; private T resource; private int refs = 0; private boolean survivesRefCull = false; private boolean undefined = false; + private boolean written = false; /** * * @param producer * @param def * @param ticket + * @param async */ public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { this.producer = producer; @@ -74,11 +76,21 @@ public void reference(PassIndex index) { lifetime.extendTo(index); refs++; } + /** + * + * @return + */ + public boolean isAvailable() { + return (!lifetime.isAsync() || !written) && !isVirtual(); + } /** * Releases this resource from one user. + * + * @return true if this resource is used after the release */ - public void release() { - refs--; + public boolean release() { + written = false; + return --refs >= 0; } /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 26f6e1fe29..e3cd1fe02a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -48,45 +48,24 @@ public class ResourceList { private static final int INITIAL_SIZE = 20; + private final FrameGraph frameGraph; private RenderManager renderManager; private RenderObjectMap map; private GraphEventCapture cap; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); - private LinkedList references = new LinkedList<>(); private int nextSlot = 0; private int textureBinds = 0; - public ResourceList() {} - public ResourceList(RenderObjectMap map) { - this.map = map; + public ResourceList(FrameGraph frameGraph) { + this.frameGraph = frameGraph; } - /** - * Creates and adds a new render resource. - * - * @param - * @param producer - * @param def - * @return new render resource - */ - protected RenderResource create(ResourceProducer producer, ResourceDef def) { + private RenderResource create(ResourceProducer producer, ResourceDef def) { RenderResource res = new RenderResource<>(producer, def, new ResourceTicket<>()); res.getTicket().setLocalIndex(add(res)); return res; } - - /** - * Locates the resource associated with the ticket. - * - * @param - * @param ticket ticket to locate with (not null) - * @return located resource - * @throws NullPointerException if ticket is null - * @throws NullPointerException if ticket's world index is negative - * @throws NullPointerException if ticket points to a null resource - * @throws IndexOutOfBoundsException if ticket's world index is >= size - */ - protected RenderResource locate(ResourceTicket ticket) { + private RenderResource locate(ResourceTicket ticket) { if (ticket == null) { throw new NullPointerException("Ticket cannot be null."); } @@ -103,26 +82,7 @@ protected RenderResource locate(ResourceTicket ticket) { } throw new IndexOutOfBoundsException(ticket+" is out of bounds for size "+resources.size()); } - - /** - * Returns true if the ticket can be used to locate a resource. - *

      - * Use {@link ResourceTicket#validate(com.jme3.renderer.framegraph.ResourceTicket)} instead. - * - * @param ticket - * @return - */ - public boolean validate(ResourceTicket ticket) { - return ResourceTicket.validate(ticket); - } - - /** - * Adds the resource to the first available slot. - * - * @param res - * @return - */ - protected int add(RenderResource res) { + private int add(RenderResource res) { assert res != null; if (nextSlot >= resources.size()) { // addUserEvent resource to end of list @@ -143,14 +103,7 @@ protected int add(RenderResource res) { return i; } } - - /** - * Removes the resource at the index. - * - * @param index - * @return - */ - protected RenderResource remove(int index) { + private RenderResource remove(int index) { RenderResource prev = resources.set(index, null); if (prev != null && prev.isReferenced()) { throw new IllegalStateException("Cannot remove "+prev+" because it is referenced."); @@ -159,6 +112,18 @@ protected RenderResource remove(int index) { return prev; } + /** + * Returns true if the ticket can be used to locate a resource. + *

      + * Use {@link ResourceTicket#validate(com.jme3.renderer.framegraph.ResourceTicket)} instead. + * + * @param ticket + * @return + */ + public boolean validate(ResourceTicket ticket) { + return ResourceTicket.validate(ticket); + } + /** * Declares a new resource. * @@ -345,6 +310,34 @@ public boolean isVirtual(ResourceTicket ticket, boolean optional) { return true; } + /** + * Returns true if the resource at the ticket is available for use. + *

      + * This is used for asynchronous situations. + * + * @param ticket + * @return + */ + public boolean isAvailable(ResourceTicket ticket) { + if (ResourceTicket.validate(ticket)) { + return locate(ticket).isAvailable(); + } + return true; + } + + /** + * Returns true if the resource at the ticket is asynchronous. + * + * @param ticket + * @return + */ + public boolean isAsync(ResourceTicket ticket) { + if (ResourceTicket.validate(ticket)) { + return locate(ticket).getLifeTime().isAsync(); + } + return false; + } + /** * Acquires the object held by the given resource. *

      @@ -551,9 +544,8 @@ public void setPrimitive(ResourceTicket ticket, T value) { */ public void release(ResourceTicket ticket) { RenderResource resource = locate(ticket); - resource.release(); if (cap != null) cap.releaseResource(resource.getIndex(), ticket.getName()); - if (!resource.isUsed()) { + if (!resource.release()) { if (cap != null && resource.getObject() != null) { cap.releaseObject(resource.getObject().getId()); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java index d4e0ee99fa..b9ba7527b0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java @@ -6,6 +6,7 @@ import com.jme3.renderer.Camera; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.PassIndex; import com.jme3.renderer.framegraph.RenderObject; import com.jme3.renderer.framegraph.RenderResource; import com.jme3.texture.FrameBuffer; @@ -51,10 +52,10 @@ public void renderViewPort(ViewPort vp) { Camera cam = vp.getCamera(); add(new Event("SUPEREVENT", "StartViewPort", vp.getName(), cam.getWidth(), cam.getHeight())); } - public void prepareRenderPass(int index, String name) { + public void prepareRenderPass(PassIndex index, String name) { events.add(new Event("PrepareRenderPass", index, name)); } - public void executeRenderPass(int index, String name) { + public void executeRenderPass(PassIndex index, String name) { add(new Event("ExecuteRenderPass", index, name)); } public void createFrameBuffer(FrameBuffer fb) { @@ -83,7 +84,7 @@ public void bindTexture(int index, String ticket) { add(new Event("BindTexture", index, ticket)); } - public void reserveObject(long id, int index) { + public void reserveObject(long id, PassIndex index) { add(new Event("ReserveObject", id, index)); } public void createObject(long id, int index, String type) { @@ -98,15 +99,6 @@ public void reallocateObject(long id, int index, String type) { public void attemptReallocation(long id, int index) { add(new Event("AttemptSpecificReallocation", id, index)); } - public void allocateSpecificFailed(RenderObject object, RenderResource resource) { - add(new Failure("AllocateSpecific", - new Check("nullObject", () -> object != null, true), - new Check("acquired", () -> !object.isAcquired()), - new Check("constant", () -> !object.isConstant()), - new Check("conflicting", () -> object.isReservedAt(resource.getLifeTime().getStartQueueIndex()) - || !object.isReservedWithin(resource.getLifeTime())) - )); - } public void setObjectConstant(long id) { add(new Event("SetObjectConstant", id)); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 70023b6e77..f2e81b8950 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -186,6 +186,9 @@ protected void cleanup(FrameGraph frameGraph) {} public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { // defines should only be set in this method + if (defines.size() == 0) { + defs.config(material.getActiveTechnique().getDef()); + } if (lightTextures[0] == null) { ColorRGBA amb = resources.acquireOrElse(ambient, null); if (amb == null) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 451b0a760a..346fa4b6ac 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -66,9 +66,7 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private ResourceTicket geometry; private ResourceTicket[] gbuffers; - private ResourceTicket lights; private ResourceTicket numRendersTicket; - private ValueDef lightDef; private final TextureDef[] texDefs = new TextureDef[5]; private int numRenders = 0; @@ -76,7 +74,6 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { protected void initialize(FrameGraph frameGraph) { geometry = addInput("Geometry"); gbuffers = addOutputGroup("GBufferData", 5); - lights = addOutput("Lights"); numRendersTicket = addOutput("NumRenders"); Function tex = img -> new Texture2D(img); texDefs[0] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); @@ -84,8 +81,6 @@ protected void initialize(FrameGraph frameGraph) { texDefs[2] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA16F); texDefs[3] = new TextureDef<>(Texture2D.class, tex, Image.Format.RGBA32F); texDefs[4] = new TextureDef<>(Texture2D.class, tex, Image.Format.Depth); - lightDef = new ValueDef(LightList.class, n -> new LightList(null)); - lightDef.setReviser(list -> list.clear()); } @Override protected void prepare(FGRenderContext context) { @@ -94,7 +89,6 @@ protected void prepare(FGRenderContext context) { texDefs[i].setSize(w, h); declare(texDefs[i], gbuffers[i]); } - declare(lightDef, lights); declare(null, numRendersTicket); reserve(gbuffers); reference(geometry); @@ -110,18 +104,11 @@ protected void execute(FGRenderContext context) { resources.acquireDepthTarget(fb, gbuffers[4]); context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); - LightList lightList = resources.acquire(lights); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); context.getRenderManager().setForcedTechnique(GBUFFER_PASS); context.getRenderManager().setGeometryRenderHandler(this); GeometryList bucket = resources.acquire(geometry); context.renderGeometryList(bucket, null, this); - // get lights for all rendered geometries - for (Spatial s : new ParentIterator(bucket)) { - for (Light l : s.getLocalLightList()) { - lightList.add(l); - } - } resources.setPrimitive(numRendersTicket, numRenders); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 2e112eaa20..96b975880d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -97,18 +97,24 @@ public void initializePass(FrameGraph frameGraph, PassIndex index) { * @param context */ public void prepareRender(FGRenderContext context) { - if (index < 0) { + if (index == null) { throw new IllegalStateException("Pass is not properly initialized for rendering."); } prepare(context); + // set the flag for checking if resources are available } /** * * @param context * @return */ - public boolean asyncWait(FGRenderContext context) { - + public boolean allInputsAvailable(FGRenderContext context) { + for (ResourceTicket t : inputs) { + if (!resources.isAvailable(t)) { + return false; + } + } + return true; } /** * Executes the pass. @@ -147,7 +153,7 @@ public void cleanupPass(FrameGraph frameGraph) { inputs.clear(); outputs.clear(); groups.clear(); - index = -1; + index = null; this.frameGraph = null; } @@ -795,9 +801,7 @@ public void countReferences() { * @param positive */ public void shiftExecutionIndex(int threshold, boolean positive) { - if (index > threshold) { - index += (positive ? 1 : -1); - } + index.shiftQueue(threshold, positive); } /** * Shifts the id of this pass. @@ -871,7 +875,7 @@ public int getExportId() { * * @return */ - public int getIndex() { + public PassIndex getIndex() { return index; } /** @@ -880,7 +884,7 @@ public int getIndex() { * @return */ public boolean isAssigned() { - return index >= 0; + return index != null; } /** * Gets the number of ticket groups. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java index 1ea93c8678..6312654062 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java @@ -8,6 +8,8 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; +import com.jme3.light.Light; +import com.jme3.light.LightList; import com.jme3.renderer.Camera; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.FGRenderContext; @@ -51,13 +53,15 @@ public SceneEnqueuePass(boolean runControlRender) { @Override protected void initialize(FrameGraph frameGraph) { for (Bucket b : buckets) { - b.ticket = addOutput(b.name); + b.geometry = addOutput(b.name); + b.lights = addOutput(b.name+"Lights"); } } @Override protected void prepare(FGRenderContext context) { for (Bucket b : buckets) { - declare(null, b.ticket); + declare(null, b.geometry); + declare(null, b.lights); } } @Override @@ -69,13 +73,15 @@ protected void execute(FGRenderContext context) { queueSubScene(context, scenes.get(i), null); } for (Bucket b : buckets) { - resources.setPrimitive(b.ticket, b.queue); + resources.setPrimitive(b.geometry, b.queue); + resources.setPrimitive(b.lights, b.lightList); } } @Override protected void reset(FGRenderContext context) { for (Bucket b : buckets) { b.queue.clear(); + b.lightList.clear(); } } @Override @@ -111,6 +117,12 @@ private void queueSubScene(FGRenderContext context, Spatial scene, RenderQueue.B b = scene.getQueueBucket(); } } + // accumulate lights + Bucket bucket = getBucket(b); + for (Light l : scene.getLocalLightList()) { + bucket.lightList.add(l); + } + // add to bucket if (scene instanceof Node) { Node n = (Node)scene; int camState = cam.getPlaneState(); @@ -125,7 +137,7 @@ private void queueSubScene(FGRenderContext context, Spatial scene, RenderQueue.B if (g.getMaterial() == null) { throw new IllegalStateException("No material is set for Geometry: " + g.getName()); } - getBucket(b).queue.add(g); + bucket.queue.add(g); } } private Bucket getBucket(RenderQueue.Bucket bucket) { @@ -143,11 +155,14 @@ private static class Bucket { public final String name; public final GeometryList queue; - public ResourceTicket ticket; + public final LightList lightList; + public ResourceTicket geometry; + public ResourceTicket lights; public Bucket(String name, GeometryComparator comparator) { this.name = name; this.queue = new GeometryList(comparator); + this.lightList = new LightList(null); } } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java index 30add22d54..031eff38fa 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java @@ -662,7 +662,7 @@ public void simpleInitApp() { //guiViewPort.setEnabled(false); //FrameGraph graph = RenderPipelineFactory.create(this, RenderManager.RenderPath.Deferred); - //FrameGraph forward = new FrameGraph(assetManager, "Common/FrameGraphs/Forward.j3g"); + FrameGraph forward = FrameGraphFactory.forward(assetManager); //forward.setName("forward"); //FrameGraph deferred = new FrameGraph(assetManager, "Common/FrameGraphs/Deferred.j3g"); FrameGraph deferred = FrameGraphFactory.deferred(assetManager, false); From 60cc5230a390c2f9d9e219d2374062fb04b3797e Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Wed, 26 Jun 2024 20:07:55 -0400 Subject: [PATCH 101/111] fix referencing bug --- .../jme3/renderer/framegraph/FrameGraph.java | 18 +++- .../framegraph/FrameGraphFactory.java | 18 +++- .../framegraph/PassQueueExecutor.java | 5 +- .../renderer/framegraph/RenderObjectMap.java | 11 +-- .../renderer/framegraph/ResourceList.java | 82 +++++++++++++++---- .../framegraph/passes/DeferredPass.java | 4 +- .../framegraph/passes/RenderPass.java | 5 +- .../renderpath/TestDeferredShading.java | 61 +++++++++----- 8 files changed, 149 insertions(+), 55 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 b744af0c81..73064a8fd2 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 @@ -47,6 +47,8 @@ import com.jme3.renderer.framegraph.passes.Attribute; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; /** * Manages render passes, dependencies, and resources in a node-based parameter system. @@ -98,6 +100,7 @@ public class FrameGraph { private final FGRenderContext context; private final ArrayList queues = new ArrayList<>(1); private final HashMap settings = new HashMap<>(); + private final LinkedList sync = new LinkedList<>(); private String name = "FrameGraph"; private boolean rendered = false; private Exception renderException; @@ -186,6 +189,7 @@ public boolean execute() { p.prepareRender(context); } } + resources.applyFutureReferences(); // cull passes and resources if (prof != null) prof.vpStep(VpStep.FrameGraphCull, vp, null); for (PassQueueExecutor queue : queues) { @@ -198,8 +202,8 @@ public boolean execute() { if (prof != null) prof.vpStep(VpStep.FrameGraphExecute, vp, null); context.pushRenderSettings(); renderException = null; - for (PassQueueExecutor p : queues) { - p.execute(context); + for (int i = queues.size()-1; i >= 0; i--) { + queues.get(i).execute(context); } if (renderException != null) { renderException.printStackTrace(System.err); @@ -493,6 +497,16 @@ public void setCLQueue(CommandQueue clQueue) { context.setCLQueue(clQueue); } + /** + * Called internally to + * + * @param pass + */ + public void registerSynchronized(RenderPass pass) { + synchronized (sync) { + sync.add(pass); + } + } /** * Called internally when a rendering exception occurs. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 22b3bc04d3..8a5b0a1f7a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -82,19 +82,31 @@ public static FrameGraph forward(AssetManager assetManager) { * Constructs a deferred or tiled deferred framegraph. * * @param assetManager - * @param tiled true to construct advanced tiled deferred + * @param tiled true to enable tiled lighting * @return deferred framegraph */ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { + return deferred(assetManager, tiled, false); + } + + /** + * Constructs a deferred framegraph. + * + * @param assetManager + * @param tiled true to enable tiled lighting + * @param async true to enable multithreading optimizations + * @return deferred framegraph + */ + public static FrameGraph deferred(AssetManager assetManager, boolean tiled, boolean async) { FrameGraph fg = new FrameGraph(assetManager); fg.setName(tiled ? "TiledDeferred" : "Deferred"); SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass()); - GBufferPass gbuf = fg.add(new GBufferPass()); Attribute tileInfoAttr = fg.add(new Attribute()); Junction tileJunct1 = fg.add(new Junction(1, 1)); - LightImagePass lightImg = fg.add(new LightImagePass(), 1); + GBufferPass gbuf = fg.add(new GBufferPass()); + LightImagePass lightImg = fg.add(new LightImagePass(), (async ? 1 : FrameGraph.RENDER_THREAD)); Junction lightJunct = fg.add(new Junction(1, 6)); Junction tileJunct2 = fg.add(new Junction(1, 2)); DeferredPass deferred = fg.add(new DeferredPass()); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java index 29df3a77ac..e96d114ca1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java @@ -77,7 +77,6 @@ public void execute(FGRenderContext context) { thread.start(); } } - @SuppressWarnings("UseSpecificCatch") private void execute() { try { @@ -88,6 +87,8 @@ private void execute() { if (!p.isUsed()) { continue; } + long start = System.currentTimeMillis(); + System.out.println(p+" started at "+start+"ms"); if (index == FrameGraph.RENDER_THREAD) { if (context.isProfilerAvailable()) { context.getProfiler().fgStep(FgStep.Execute, p.getProfilerName()); @@ -109,6 +110,8 @@ private void execute() { } } p.executeRender(context); + long end = System.currentTimeMillis(); + System.out.println(p+" ended at "+end+" and took "+(end-start)+"ms"); if (index == FrameGraph.RENDER_THREAD) { context.popRenderSettings(); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 6ec0a1c10b..57802aab51 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -49,7 +49,6 @@ public class RenderObjectMap { private final RenderManager renderManager; private final Map objectMap; - private final boolean async; private int staticTimeout = 1; // statistics @@ -64,12 +63,7 @@ public class RenderObjectMap { public RenderObjectMap(RenderManager renderManager, boolean async) { this.renderManager = renderManager; - this.async = async; - if (this.async) { - objectMap = new ConcurrentHashMap<>(); - } else { - objectMap = new HashMap<>(); - } + objectMap = new ConcurrentHashMap<>(); } private RenderObject create(ResourceDef def) { @@ -96,8 +90,9 @@ private boolean isAvailable(RenderObject object) { * * @param * @param resource + * @param async true to execute asynchronous methods */ - public void allocate(RenderResource resource) { + public void allocate(RenderResource resource, boolean async) { if (async) { allocateAsync(resource); } else { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index e3cd1fe02a..ef17ee4dcb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -36,6 +36,7 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture; +import com.jme3.util.SafeArrayList; import java.util.ArrayList; import java.util.LinkedList; @@ -53,6 +54,7 @@ public class ResourceList { private RenderObjectMap map; private GraphEventCapture cap; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); + private LinkedList futureRefs = new LinkedList<>(); private int nextSlot = 0; private int textureBinds = 0; @@ -66,21 +68,35 @@ private RenderResource create(ResourceProducer producer, ResourceDef d return res; } private RenderResource locate(ResourceTicket ticket) { + return locate(ticket, true); + } + private RenderResource locate(ResourceTicket ticket, boolean failOnMiss) { if (ticket == null) { - throw new NullPointerException("Ticket cannot be null."); + if (failOnMiss) { + throw new NullPointerException("Ticket cannot be null."); + } + return null; } final int i = ticket.getWorldIndex(); if (i < 0) { - throw new NullPointerException(ticket+" does not point to any resource (negative index)."); + if (failOnMiss) { + throw new NullPointerException(ticket+" does not point to any resource (negative index)."); + } + return null; } if (i < resources.size()) { RenderResource res = resources.get(i); if (res != null) { return res; } - throw new NullPointerException(ticket+" points to null resource."); + if (failOnMiss) { + throw new NullPointerException(ticket+" points to null resource."); + } } - throw new IndexOutOfBoundsException(ticket+" is out of bounds for size "+resources.size()); + if (failOnMiss) { + throw new IndexOutOfBoundsException(ticket+" is out of bounds for size "+resources.size()); + } + return null; } private int add(RenderResource res) { assert res != null; @@ -168,6 +184,17 @@ public void reserve(PassIndex passIndex, ResourceTicket... tickets) { } } + private void reference(PassIndex passIndex, ResourceTicket ticket, boolean optional) { + RenderResource resource = locate(ticket, false); + if (resource != null) { + resource.reference(passIndex); + if (cap != null) cap.referenceResource(resource.getIndex(), ticket.getName()); + } else { + // save for later, since the resource hasn't been declared yet + futureRefs.add(new FutureReference(passIndex, ticket, optional)); + } + } + /** * References the resource associated with the ticket. *

      @@ -179,9 +206,7 @@ public void reserve(PassIndex passIndex, ResourceTicket... tickets) { * @param ticket */ public void reference(PassIndex passIndex, ResourceTicket ticket) { - RenderResource resource = locate(ticket); - resource.reference(passIndex); - if (cap != null) cap.referenceResource(resource.getIndex(), ticket.getName()); + reference(passIndex, ticket, false); } /** @@ -190,14 +215,9 @@ public void reference(PassIndex passIndex, ResourceTicket ticket) { * * @param passIndex render pass index * @param ticket - * @return */ - public boolean referenceOptional(PassIndex passIndex, ResourceTicket ticket) { - if (validate(ticket)) { - reference(passIndex, ticket); - return true; - } - return false; + public void referenceOptional(PassIndex passIndex, ResourceTicket ticket) { + reference(passIndex, ticket, true); } /** @@ -208,7 +228,7 @@ public boolean referenceOptional(PassIndex passIndex, ResourceTicket ticket) { */ public void reference(PassIndex passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { - reference(passIndex, t); + reference(passIndex, t, false); } } @@ -220,7 +240,7 @@ public void reference(PassIndex passIndex, ResourceTicket... tickets) { */ public void referenceOptional(PassIndex passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { - referenceOptional(passIndex, t); + reference(passIndex, t, true); } } @@ -356,7 +376,7 @@ protected T acquire(RenderResource resource, ResourceTicket ticket) { throw new IllegalStateException(resource+" was unexpectedly acquired."); } if (resource.isVirtual()) { - map.allocate(resource); + map.allocate(resource, frameGraph.isAsync()); } if (cap != null) cap.acquireResource(resource.getIndex(), ticket.getName()); resource.getTicket().copyObjectTo(ticket); @@ -572,7 +592,7 @@ public void release(ResourceTicket ticket) { * @return */ public boolean releaseOptional(ResourceTicket ticket) { - if (ticket != null && ticket.getWorldIndex() >= 0) { + if (ResourceTicket.validate(ticket)) { release(ticket); return true; } @@ -610,6 +630,18 @@ public void beginRenderingSession() { textureBinds = 0; } + /** + * Applies all missed references. + */ + public void applyFutureReferences() { + for (FutureReference ref : futureRefs) { + if (!ref.optional || ResourceTicket.validate(ref.ticket)) { + locate(ref.ticket).reference(ref.index); + } + } + futureRefs.clear(); + } + /** * Culls all resources and resource producers found to be unused. *

      @@ -686,4 +718,18 @@ public void setRenderManager(RenderManager renderManager) { this.cap = this.renderManager.getGraphCapture(); } + private static class FutureReference { + + public final PassIndex index; + public final ResourceTicket ticket; + public final boolean optional; + + public FutureReference(PassIndex index, ResourceTicket ticket, boolean optional) { + this.index = index; + this.ticket = ticket; + this.optional = optional; + } + + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index f2e81b8950..cbc99371c6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -165,8 +165,10 @@ protected void execute(FGRenderContext context) { material.getActiveTechnique().getDef().setLogic(this); acquireArrayOrElse("LightTextures", lightTextures, null); if (lightTextures[0] == null) { + System.out.println("use light buffers"); context.getScreen().render(context.getRenderManager(), material, resources.acquire(lights)); } else { + System.out.println("use light textures"); for (int i = 1; i <= lightTextures.length; i++) { material.setTexture("LightTex"+i, lightTextures[i-1]); } @@ -185,7 +187,7 @@ protected void cleanup(FrameGraph frameGraph) {} @Override public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { - // defines should only be set in this method + // if the technique def somehow wasn't configured, configure it if (defines.size() == 0) { defs.config(material.getActiveTechnique().getDef()); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 96b975880d..0ccd1bcb70 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -284,10 +284,9 @@ protected void reference(ResourceTicket... tickets) { * null and contains a non-negative world index. * * @param ticket - * @return */ - protected boolean referenceOptional(ResourceTicket ticket) { - return resources.referenceOptional(index, ticket); + protected void referenceOptional(ResourceTicket ticket) { + resources.referenceOptional(index, ticket); } /** * Optionally references each resource associated with the tickets. diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java index 6ce6e05571..e928a71df7 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java @@ -1,5 +1,6 @@ package jme3test.renderpath; +import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; import com.jme3.light.PointLight; import com.jme3.material.Material; @@ -9,22 +10,43 @@ import com.jme3.post.FilterPostProcessor; import com.jme3.post.filters.BloomFilter; import com.jme3.post.filters.ToneMapFilter; +import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; +import com.jme3.renderer.framegraph.light.TiledRenderGrid; +import com.jme3.renderer.framegraph.passes.LightImagePass; 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://en.wikipedia.org/wiki/Deferred_shading/ * @author JohnKkk */ public class TestDeferredShading extends SimpleApplication { + private Material material; + + public static void main(String[] args) { + TestDeferredShading app = new TestDeferredShading(); + AppSettings settings = new AppSettings(true); + settings.setWidth(768); + settings.setHeight(768); + app.setSettings(settings); + app.start(); + } + @Override public void simpleInitApp() { - viewPort.setFrameGraph(FrameGraphFactory.deferred(assetManager, false)); + FrameGraph fg = FrameGraphFactory.deferred(assetManager, true, false); + fg.setJunctionSetting("LightPackMethod", true); + fg.get(LightImagePass.class).setMaxLights(4096); + fg.setSetting("TileInfo", new TiledRenderGrid(4, -1)); + viewPort.setFrameGraph(fg); + + stateManager.attach(new DetailedProfilerState()); // Test Forward // renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); @@ -33,7 +55,7 @@ public void simpleInitApp() { //renderManager.setMaxDeferredShadingLights(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); + Quad quad = new Quad(20, 20); Geometry geo = new Geometry("Floor", quad); material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); material.setFloat("Shininess", 25); @@ -43,28 +65,28 @@ public void simpleInitApp() { material.setBoolean("UseMaterialColors", true); geo.setMaterial(material); geo.rotate((float) Math.toRadians(-90), 0, 0); - geo.setLocalTranslation(-7, 0, -7); + geo.setLocalTranslation(-10, 0, 10); 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, + 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++){ + for (int i = 0;i < 2000;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(FastMath.nextRandomFloat(-5.0f, 5.0f), 0.1f, FastMath.nextRandomFloat(-5.0f, 5.0f))); // pl.setPosition(new Vector3f(0, 1, 0)); pl.setRadius(1.0f); rootNode.addLight(pl); @@ -86,10 +108,10 @@ public void simpleInitApp() { // rootNode.addLight(sun); - cam.setLocation(new Vector3f(0, 2, 0)); + //cam.setLocation(new Vector3f(0, 2, 0)); cam.lookAtDirection(Vector3f.UNIT_Z.negate(), Vector3f.UNIT_Y); flyCam.setMoveSpeed(10.0f); - + flyCam.setDragToRotate(true); FilterPostProcessor fpp = new FilterPostProcessor(assetManager); int numSamples = context.getSettings().getSamples(); @@ -108,9 +130,10 @@ public void simpleInitApp() { 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(); + + @Override + public void simpleUpdate(float tpf) { + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); } + } From d10bfc6c1d75deda3a8f142d791250ebf01fb468 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:03:08 -0400 Subject: [PATCH 102/111] added fix for missing defines --- .../framegraph/PassQueueExecutor.java | 12 +------ .../renderer/framegraph/RenderResource.java | 36 ++++++++++--------- .../renderer/framegraph/ResourceList.java | 16 +++++---- .../framegraph/passes/DeferredPass.java | 17 ++++----- .../framegraph/passes/RenderPass.java | 26 +++++++------- .../main/java/com/jme3/shader/DefineList.java | 10 ++++-- .../com/jme3/material/plugins/J3MLoader.java | 2 -- .../renderpath/TestDeferredShading.java | 4 ++- 8 files changed, 62 insertions(+), 61 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java index e96d114ca1..efbb869233 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java @@ -88,7 +88,6 @@ private void execute() { continue; } long start = System.currentTimeMillis(); - System.out.println(p+" started at "+start+"ms"); if (index == FrameGraph.RENDER_THREAD) { if (context.isProfilerAvailable()) { context.getProfiler().fgStep(FgStep.Execute, p.getProfilerName()); @@ -99,19 +98,10 @@ private void execute() { } if (frameGraph.isAsync()) { // wait until all input resources are available for use before executing - long startMillis = System.currentTimeMillis(); - while (!p.allInputsAvailable(context)) { - if (interrupted) { - return; - } - if (System.currentTimeMillis()-startMillis >= threadTimeoutMillis) { - throw new TimeoutException("Execution thread "+index+" timed out on pass "+p); - } - } + p.waitForInputs(); } p.executeRender(context); long end = System.currentTimeMillis(); - System.out.println(p+" ended at "+end+" and took "+(end-start)+"ms"); if (index == FrameGraph.RENDER_THREAD) { context.popRenderSettings(); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index f324676088..189df7b92e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -33,6 +33,8 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; /** * Represents an existing or future resource used for rendering. @@ -51,7 +53,7 @@ public class RenderResource { private int refs = 0; private boolean survivesRefCull = false; private boolean undefined = false; - private boolean written = false; + private final AtomicBoolean released = new AtomicBoolean(false); /** * @@ -76,20 +78,13 @@ public void reference(PassIndex index) { lifetime.extendTo(index); refs++; } - /** - * - * @return - */ - public boolean isAvailable() { - return (!lifetime.isAsync() || !written) && !isVirtual(); - } /** * Releases this resource from one user. * * @return true if this resource is used after the release */ public boolean release() { - written = false; + released.compareAndExchange(false, true); return --refs >= 0; } @@ -150,6 +145,14 @@ public void setUndefined() { } undefined = true; } + /** + * Returns true if this resource always survives cull by reference. + * + * @param survivesRefCull + */ + public void setSurvivesRefCull(boolean survivesRefCull) { + this.survivesRefCull = survivesRefCull; + } /** * Gets this resource's producer. @@ -215,14 +218,6 @@ public int getIndex() { public int getNumReferences() { return refs; } - /** - * Returns true if this resource always survives cull by reference. - * - * @param survivesRefCull - */ - public void setSurvivesRefCull(boolean survivesRefCull) { - this.survivesRefCull = survivesRefCull; - } /** * Returns true if this resource is virtual. @@ -279,6 +274,13 @@ public boolean isUndefined() { public boolean isSurvivesRefCull() { return survivesRefCull; } + /** + * + * @return + */ + public boolean isAvailable() { + return released.get(); + } @Override public String toString() { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index ef17ee4dcb..33efe7200f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -36,9 +36,9 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture; -import com.jme3.util.SafeArrayList; import java.util.ArrayList; import java.util.LinkedList; +import java.util.concurrent.locks.Lock; /** * Manages render resource declarations, references, and releases for a framegraph. @@ -331,18 +331,20 @@ public boolean isVirtual(ResourceTicket ticket, boolean optional) { } /** - * Returns true if the resource at the ticket is available for use. + * Forces the current thread to wait until the resource at the ticket is + * available. *

      - * This is used for asynchronous situations. + * A resource becomes available after being released by the declaring pass. * * @param ticket - * @return */ - public boolean isAvailable(ResourceTicket ticket) { + public void wait(ResourceTicket ticket) { if (ResourceTicket.validate(ticket)) { - return locate(ticket).isAvailable(); + RenderResource res = locate(ticket); + while (!res.isAvailable()) { + Thread.onSpinWait(); + } } - return true; } /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index cbc99371c6..cbf64eb129 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -107,6 +107,7 @@ public class DeferredPass extends RenderPass implements TechniqueDefLogic { private final Texture2D[] tileTextures = new Texture2D[2]; private final ColorRGBA ambientColor = new ColorRGBA(); private List probeList; + private TechniqueDef active; public DeferredPass() {} public DeferredPass(boolean tiled) { @@ -134,9 +135,9 @@ protected void initialize(FrameGraph frameGraph) { material = new Material(assetManager, "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); if (defs == null) { defs = new Defines(); - for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { - defs.config(t); - } +// for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { +// defs.config(t); +// } } } @Override @@ -163,12 +164,14 @@ protected void execute(FGRenderContext context) { } material.selectTechnique("DeferredPass", context.getRenderManager()); material.getActiveTechnique().getDef().setLogic(this); + active = material.getActiveTechnique().getDef(); + if (active.getDefineNames().length == 0) { + defs.config(active); + } acquireArrayOrElse("LightTextures", lightTextures, null); if (lightTextures[0] == null) { - System.out.println("use light buffers"); context.getScreen().render(context.getRenderManager(), material, resources.acquire(lights)); } else { - System.out.println("use light textures"); for (int i = 1; i <= lightTextures.length; i++) { material.setTexture("LightTex"+i, lightTextures[i-1]); } @@ -188,9 +191,7 @@ protected void cleanup(FrameGraph frameGraph) {} public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { // if the technique def somehow wasn't configured, configure it - if (defines.size() == 0) { - defs.config(material.getActiveTechnique().getDef()); - } + System.out.println("using "+(active == material.getActiveTechnique().getDef())); if (lightTextures[0] == null) { ColorRGBA amb = resources.acquireOrElse(ambient, null); if (amb == null) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 0ccd1bcb70..2718964cc7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -103,19 +103,6 @@ public void prepareRender(FGRenderContext context) { prepare(context); // set the flag for checking if resources are available } - /** - * - * @param context - * @return - */ - public boolean allInputsAvailable(FGRenderContext context) { - for (ResourceTicket t : inputs) { - if (!resources.isAvailable(t)) { - return false; - } - } - return true; - } /** * Executes the pass. * @@ -299,6 +286,19 @@ protected void referenceOptional(ResourceTicket... tickets) { } } + /** + * Forces this thread to wait until all inputs are available for this pass. + * + * @param context + * @return + */ + public boolean waitForInputs() { + for (ResourceTicket t : inputs) { + resources.wait(t); + } + return true; + } + /** * Acquires a set of resources from a ticket group and stores them in * the array. 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 f981fdd841..b527730564 100644 --- a/jme3-core/src/main/java/com/jme3/shader/DefineList.java +++ b/jme3-core/src/main/java/com/jme3/shader/DefineList.java @@ -43,7 +43,7 @@ public final class DefineList { private final BitSet isSet; - private final int[] values; + private int[] values; public DefineList(int numValues) { if (numValues < 0) { @@ -60,7 +60,13 @@ private DefineList(DefineList original) { } private void rangeCheck(int id) { - assert 0 <= id && id < values.length; + //assert 0 <= id && id < values.length; + assert id >= 0 : "Define id cannot be less than zero."; + if (id > values.length) { + int[] temp = new int[id+1]; + System.arraycopy(values, 0, temp, 0, values.length); + values = temp; + } } public boolean isSet(int id) { 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 a5afea5e03..08ab7985ae 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 @@ -51,8 +51,6 @@ import com.jme3.util.blockparser.Statement; import com.jme3.util.clone.Cloner; import jme3tools.shader.Preprocessor; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.*; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java index e928a71df7..b930a9964d 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java @@ -33,6 +33,8 @@ public static void main(String[] args) { AppSettings settings = new AppSettings(true); settings.setWidth(768); settings.setHeight(768); + settings.setVSync(false); + settings.setFrameRate(-1); app.setSettings(settings); app.start(); } @@ -83,7 +85,7 @@ public void simpleInitApp() { }; InstancedNode instancedNode = new InstancedNode("sp"); - for (int i = 0;i < 2000;i++) { + for(int i = 0;i < 2000;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(-5.0f, 5.0f))); From 482022ab44bdf423645e71e7f76ceb3c0a8e64f5 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:08:36 -0400 Subject: [PATCH 103/111] test async --- .../src/main/java/jme3test/renderpath/TestDeferredShading.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java index b930a9964d..1d50cc8049 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java @@ -42,7 +42,7 @@ public static void main(String[] args) { @Override public void simpleInitApp() { - FrameGraph fg = FrameGraphFactory.deferred(assetManager, true, false); + FrameGraph fg = FrameGraphFactory.deferred(assetManager, true, true); fg.setJunctionSetting("LightPackMethod", true); fg.get(LightImagePass.class).setMaxLights(4096); fg.setSetting("TileInfo", new TiledRenderGrid(4, -1)); From 4c3052796cd4f829d4b658618f1a9a4c40fef464 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:13:48 -0400 Subject: [PATCH 104/111] fix dependency on java 9 --- .../main/java/com/jme3/renderer/framegraph/ResourceList.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 33efe7200f..1dcb853a60 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -341,9 +341,8 @@ public boolean isVirtual(ResourceTicket ticket, boolean optional) { public void wait(ResourceTicket ticket) { if (ResourceTicket.validate(ticket)) { RenderResource res = locate(ticket); - while (!res.isAvailable()) { - Thread.onSpinWait(); - } + // wait for resource to become available to this context + while (!res.isAvailable()) {} } } From d70e4cd416b552946f3005477678935254de6eba Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:17:08 -0400 Subject: [PATCH 105/111] removed unnecessary atomic boolean --- .../com/jme3/renderer/framegraph/RenderResource.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 189df7b92e..88c3a8eb3c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -34,7 +34,6 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; /** * Represents an existing or future resource used for rendering. @@ -53,7 +52,7 @@ public class RenderResource { private int refs = 0; private boolean survivesRefCull = false; private boolean undefined = false; - private final AtomicBoolean released = new AtomicBoolean(false); + private boolean released = false; /** * @@ -84,8 +83,9 @@ public void reference(PassIndex index) { * @return true if this resource is used after the release */ public boolean release() { - released.compareAndExchange(false, true); - return --refs >= 0; + refs--; + released = true; + return refs >= 0; } /** @@ -279,7 +279,7 @@ public boolean isSurvivesRefCull() { * @return */ public boolean isAvailable() { - return released.get(); + return released; } @Override From d1cbd3350eb85a18cfbf5d7d92caffa425442882 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 28 Jun 2024 09:26:07 -0400 Subject: [PATCH 106/111] fixed more async issues --- .../com/jme3/renderer/framegraph/Access.java | 36 ++++--- .../jme3/renderer/framegraph/FrameGraph.java | 17 ++-- .../framegraph/PassQueueExecutor.java | 96 +++++++++++++++---- .../renderer/framegraph/RenderResource.java | 27 ++++-- .../renderer/framegraph/ResourceList.java | 42 ++++++-- .../definitions/AbstractResourceDef.java | 21 ++++ .../framegraph/definitions/ResourceDef.java | 9 ++ .../framegraph/passes/DeferredPass.java | 1 - .../framegraph/passes/RenderPass.java | 11 ++- 9 files changed, 193 insertions(+), 67 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java index 3690e42b99..e38fc35c36 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java @@ -5,48 +5,44 @@ package com.jme3.renderer.framegraph; /** - * + * Defines when a resource can be accessed for reading or writing. + * * @author codex */ public enum Access { /** - * Indicates that the resource is accessed for reading only. + * Indicates no concurrency. */ - Read(true, false), + NoConcurrency(false, false), /** - * Indicates that the resource is accessed for writing only. + * Indicates concurrency for reading only. */ - Write(false, true), + ConcurrentRead(true, false), /** - * Indicates that the resource is accessed for both reading and writing. + * Indicates concurrency for writing only. */ - ReadAndWrite(true, true); + ConcurrentWrite(false, true), - private final boolean read, write; + /** + * Indicates concurrency for reading and writing. + */ + Concurrent(true, true); + private final boolean read, write; + private Access(boolean read, boolean write) { this.read = read; this.write = write; } - /** - * Returns true if the access is for reading. - * - * @return - */ - public boolean isRead() { + public boolean isReadConcurrent() { return read; } - /** - * Returns true if the access is for writing. - * - * @return - */ - public boolean isWrite() { + public boolean isWriteConcurrent() { return write; } 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 73064a8fd2..95a15257ea 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 @@ -47,8 +47,8 @@ import com.jme3.renderer.framegraph.passes.Attribute; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicInteger; /** * Manages render passes, dependencies, and resources in a node-based parameter system. @@ -100,7 +100,7 @@ public class FrameGraph { private final FGRenderContext context; private final ArrayList queues = new ArrayList<>(1); private final HashMap settings = new HashMap<>(); - private final LinkedList sync = new LinkedList<>(); + private final AtomicInteger incompleteQueues = new AtomicInteger(0); private String name = "FrameGraph"; private boolean rendered = false; private Exception renderException; @@ -202,6 +202,7 @@ public boolean execute() { if (prof != null) prof.vpStep(VpStep.FrameGraphExecute, vp, null); context.pushRenderSettings(); renderException = null; + incompleteQueues.set(queues.size()); for (int i = queues.size()-1; i >= 0; i--) { queues.get(i).execute(context); } @@ -498,13 +499,15 @@ public void setCLQueue(CommandQueue clQueue) { } /** - * Called internally to + * Called internally to notify the framegraph that a queue has completed execution. * - * @param pass + * @param queue */ - public void registerSynchronized(RenderPass pass) { - synchronized (sync) { - sync.add(pass); + public void notifyComplete(PassQueueExecutor queue) { + if (incompleteQueues.decrementAndGet() == 1) { + for (PassQueueExecutor q : queues) { + q.notifyLast(); + } } } /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java index efbb869233..6644830a3c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java @@ -25,6 +25,7 @@ public class PassQueueExecutor implements Runnable, Iterable, Savable { private static long threadTimeoutMillis = 5000; + private static int threadTimeoutAttempts = 100; private static final ArrayList DEF_QUEUE = new ArrayList<>(0); private final FrameGraph frameGraph; @@ -32,7 +33,7 @@ public class PassQueueExecutor implements Runnable, Iterable, Savabl private int index; private Thread thread; private FGRenderContext context; - private boolean complete = false; + private boolean async = false; private boolean interrupted = false; public PassQueueExecutor(FrameGraph frameGraph, int index) { @@ -67,19 +68,24 @@ public void read(JmeImporter im) throws IOException { index = in.readInt("index", 0); } + /** + * Executes this queue with the context. + * + * @param context + */ public void execute(FGRenderContext context) { - complete = false; + async = frameGraph.isAsync(); this.context = context; - if (index == FrameGraph.RENDER_THREAD) { + if (isMainThread()) { execute(); } else { thread = new Thread(this); thread.start(); } } - @SuppressWarnings("UseSpecificCatch") private void execute() { try { + boolean main = isMainThread(); for (RenderPass p : queue) { if (interrupted) { return; @@ -87,8 +93,7 @@ private void execute() { if (!p.isUsed()) { continue; } - long start = System.currentTimeMillis(); - if (index == FrameGraph.RENDER_THREAD) { + if (main) { if (context.isProfilerAvailable()) { context.getProfiler().fgStep(FgStep.Execute, p.getProfilerName()); } @@ -96,22 +101,32 @@ private void execute() { context.getGraphCapture().executeRenderPass(p.getIndex(), p.getProfilerName()); } } - if (frameGraph.isAsync()) { + if (async) { // wait until all input resources are available for use before executing - p.waitForInputs(); + p.waitForInputs(threadTimeoutMillis, threadTimeoutAttempts); } p.executeRender(context); - long end = System.currentTimeMillis(); - if (index == FrameGraph.RENDER_THREAD) { + if (main) { context.popRenderSettings(); } } - complete = true; + frameGraph.notifyComplete(this); } catch (Exception ex) { - frameGraph.interruptRendering(ex); + if (!interrupted) { + frameGraph.interruptRendering(ex); + } } } + /** + * Notifies the queue that all other queues have completed execution. + */ + public void notifyLast() { + async = false; + } + /** + * Interrupts this queue from executing the next pass. + */ public void interrupt() { interrupted = true; } @@ -288,24 +303,46 @@ public void clear() { queue.clear(); } - public int shiftIndex(int i, boolean pos) { + /** + * Shifts the thread index if the thread index is above {@code i}. + * + * @param i + * @param pos + * @return + */ + public int shiftThreadIndex(int i, boolean pos) { if (index > i) { index += pos ? 1 : -1; } + for (RenderPass p : queue) { + p.getIndex().shiftThread(i, pos); + } return index; } + /** + * Gets the number of passes in this queue. + * + * @return + */ public int size() { return queue.size(); } + /** + * Gets the thread index of this queue. + * + * @return + */ public int getIndex() { return index; } - public boolean isAsync() { - return index != FrameGraph.RENDER_THREAD; - } - public boolean isComplete() { - return complete; + /** + * Returns true if this queue is running on the main render thread. + * + * @return + */ + public boolean isMainThread() { + return index == FrameGraph.RENDER_THREAD; } /** @@ -321,8 +358,31 @@ public boolean isComplete() { public static void setThreadTimeoutMillis(long threadTimeoutMillis) { PassQueueExecutor.threadTimeoutMillis = threadTimeoutMillis; } + /** + * Sets the maximum number of attempts executors will make + * for pass inputs to be available before aboring execution. + *

      + * default=100 + * + * @param threadTimeoutAttempts + */ + public static void setThreadTimeoutAttempts(int threadTimeoutAttempts) { + PassQueueExecutor.threadTimeoutAttempts = threadTimeoutAttempts; + } + + /** + * + * @return + */ public static long getThreadTimeoutMillis() { return threadTimeoutMillis; } + /** + * + * @return + */ + public static int getThreadTimeoutAttempts() { + return threadTimeoutAttempts; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java index 88c3a8eb3c..fe09ddf8ca 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java @@ -52,7 +52,7 @@ public class RenderResource { private int refs = 0; private boolean survivesRefCull = false; private boolean undefined = false; - private boolean released = false; + private final AtomicBoolean released = new AtomicBoolean(false); /** * @@ -84,9 +84,17 @@ public void reference(PassIndex index) { */ public boolean release() { refs--; - released = true; + released.set(true); return refs >= 0; } + /** + * Claims the resource for reading. + * + * @return + */ + public boolean claimReadPermissions() { + return (def.isReadConcurrent() && released.get()) || released.getAndSet(false); + } /** * Sets the render object held by this resource. @@ -275,16 +283,19 @@ public boolean isSurvivesRefCull() { return survivesRefCull; } /** + * Return true if this resource is available for reading. + *

      + * This is true typically after the first release occurs. * * @return */ - public boolean isAvailable() { - return released; + public boolean isReadAvailable() { + return released.get(); } - @Override - public String toString() { - return "RenderResource[index="+ticket.getWorldIndex()+"]"; - } +// @Override +// public String toString() { +// return "RenderResource[index="+ticket.getWorldIndex()+"]"; +// } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 1dcb853a60..4a6e231b20 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -38,7 +38,7 @@ import com.jme3.texture.Texture; import java.util.ArrayList; import java.util.LinkedList; -import java.util.concurrent.locks.Lock; +import java.util.concurrent.TimeoutException; /** * Manages render resource declarations, references, and releases for a framegraph. @@ -54,7 +54,7 @@ public class ResourceList { private RenderObjectMap map; private GraphEventCapture cap; private ArrayList resources = new ArrayList<>(INITIAL_SIZE); - private LinkedList futureRefs = new LinkedList<>(); + private final LinkedList futureRefs = new LinkedList<>(); private int nextSlot = 0; private int textureBinds = 0; @@ -98,6 +98,9 @@ private RenderResource locate(ResourceTicket ticket, boolean failOnMis } return null; } + private RenderResource fastLocate(ResourceTicket ticket) { + return resources.get(ticket.getWorldIndex()); + } private int add(RenderResource res) { assert res != null; if (nextSlot >= resources.size()) { @@ -332,17 +335,40 @@ public boolean isVirtual(ResourceTicket ticket, boolean optional) { /** * Forces the current thread to wait until the resource at the ticket is - * available. + * available for reading or a timeout occurs. + *

      + * A resource becomes available for reading after being released by the declaring pass. + * Then all waiting passes may access it for reading only. *

      - * A resource becomes available after being released by the declaring pass. + * The operation is skipped if the ticket is invalid. * - * @param ticket + * @param ticket ticket to locate resource with + * @param thread current thread + * @param attempts + * @param timeoutMillis maximum wait time (in milliseconds) before throwing a timeout exception + * @throws java.util.concurrent.TimeoutException if wait times out */ - public void wait(ResourceTicket ticket) { + public void wait(ResourceTicket ticket, int thread, long timeoutMillis, int attempts) throws TimeoutException { if (ResourceTicket.validate(ticket)) { - RenderResource res = locate(ticket); + if (attempts <= 0) { + throw new TimeoutException("Thread "+thread+": Resource at "+ticket+" was assumed " + + "unreachable after a number of unsuccessful attempts."); + } // wait for resource to become available to this context - while (!res.isAvailable()) {} + long start = System.currentTimeMillis(); + RenderResource res; + // TODO: determine why not locating the resource on each try results in timeouts. + while (!(res = fastLocate(ticket)).isReadAvailable()) { + if (System.currentTimeMillis()-start >= timeoutMillis) { + throw new TimeoutException("Thread "+thread+": Resource at "+ticket+" was assumed " + + "unreachable after "+timeoutMillis+" milliseconds."); + } + } + // claim read permisions + // for resources that are read concurrent, this won't matter + if (!res.claimReadPermissions()) { + wait(ticket, thread, timeoutMillis, --attempts); + } } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java index 863a162018..29bebb8969 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java @@ -44,24 +44,33 @@ public abstract class AbstractResourceDef implements ResourceDef { private int staticTimeout = -1; private boolean useExisting = true; private boolean disposeOnRelease = false; + private boolean readConcurrent = true; @Override public int getStaticTimeout() { return staticTimeout; } + @Override public Consumer getDisposalMethod() { return disposalMethod; } + @Override public boolean isUseExisting() { return useExisting; } + @Override public boolean isDisposeOnRelease() { return disposeOnRelease; } + @Override + public boolean isReadConcurrent() { + return readConcurrent; + } + /** * Sets the consumer responsible for disposing the resource. *

      @@ -72,6 +81,7 @@ public boolean isDisposeOnRelease() { public void setDisposalMethod(Consumer disposalMethod) { this.disposalMethod = disposalMethod; } + /** * Sets the number of frames the resource can be static before being * disposed. @@ -83,6 +93,7 @@ public void setDisposalMethod(Consumer disposalMethod) { public void setStaticTimeout(int staticTimout) { this.staticTimeout = staticTimout; } + /** * Sets this definition to allow for use of reallocated objects. *

      @@ -93,6 +104,7 @@ public void setStaticTimeout(int staticTimout) { public void setUseExisting(boolean useExisting) { this.useExisting = useExisting; } + /** * Sets the resource to be disposed when it is unused. *

      @@ -104,4 +116,13 @@ public void setDisposeOnRelease(boolean disposeOnRelease) { this.disposeOnRelease = disposeOnRelease; } + /** + * Sets the resource as able to be read concurrently. + * + * @param readConcurrent + */ + public void setReadConcurrent(boolean readConcurrent) { + this.readConcurrent = readConcurrent; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index 43eee9e065..6ad502ef76 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -109,6 +109,15 @@ public default boolean isDisposeOnRelease() { return false; } + /** + * Returns true if the resource can be read concurrently. + * + * @return + */ + public default boolean isReadConcurrent() { + return true; + } + /** * Disposes the resource using the disposal method, if not null. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index cbf64eb129..7e29c37283 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -191,7 +191,6 @@ protected void cleanup(FrameGraph frameGraph) {} public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { // if the technique def somehow wasn't configured, configure it - System.out.println("using "+(active == material.getActiveTechnique().getDef())); if (lightTextures[0] == null) { ColorRGBA amb = resources.acquireOrElse(ambient, null); if (amb == null) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 2718964cc7..7fe62483b4 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -51,6 +51,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeoutException; import java.util.function.Function; /** @@ -289,14 +290,14 @@ protected void referenceOptional(ResourceTicket... tickets) { /** * Forces this thread to wait until all inputs are available for this pass. * - * @param context - * @return + * @param timeout maximum wait time for each ticket before a timeout exception is thrown + * @param attempts maximum attempts for each ticket before a timeout exception is thrown + * @throws java.util.concurrent.TimeoutException if wait times out */ - public boolean waitForInputs() { + public void waitForInputs(long timeout, int attempts) throws TimeoutException { for (ResourceTicket t : inputs) { - resources.wait(t); + resources.wait(t, index.getThreadIndex(), timeout, attempts); } - return true; } /** From 2956c9d3e912767bc995a9863ffdf75ee79b03ef Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 29 Jun 2024 12:17:39 -0400 Subject: [PATCH 107/111] fixed camera size when rendering to smaller textures --- .../main/java/com/jme3/renderer/Camera.java | 19 +++++ .../renderer/framegraph/FGRenderContext.java | 25 +++++++ .../renderer/framegraph/FullScreenQuad.java | 5 ++ .../framegraph/PassQueueExecutor.java | 6 +- .../renderer/framegraph/ResourceList.java | 10 ++- .../framegraph/definitions/ResourceDef.java | 3 +- .../framegraph/passes/OutputPass.java | 4 +- .../framegraph/passes/RenderPass.java | 15 ++-- .../resources/Common/FrameGraphs/Forward.j3g | Bin 1039 -> 1128 bytes .../Common/MatDefs/ShadingCommon/Screen.vert | 6 +- .../ShadingCommon/TextureTransfer.j3md | 1 + .../TerrainTestAdvancedRenderPath.java | 2 +- .../TerrainTestAndroidRenderPath.java | 2 +- .../TestDeferredPBRShading.java | 2 +- .../TestDeferredShading.java | 2 +- .../TestDeferredShadingPathShadow.java | 2 +- .../TestFrameGraphImportExport.java | 4 +- .../TestFrameGraphLoadingSpeeds.java | 2 +- .../TestPBRTerrainAdvancedRenderPath.java | 2 +- .../TestPBRTerrainRenderPath.java | 2 +- ...thPointDirectionalAndSpotLightShadows.java | 2 +- .../TestShadingModel.java | 2 +- .../TestSimpleDeferredLighting.java | 2 +- .../TestTileBasedDeferredShading.java | 2 +- .../framegraph/examples/DownsamplingPass.java | 67 ++++++++++++++++++ .../examples/HelloCustomFrameGraph.java | 58 +++++++++++++++ .../framegraph/examples/HelloFrameGraph.java | 61 ++++++++++++++++ .../sandbox/Main.java | 2 +- 28 files changed, 275 insertions(+), 35 deletions(-) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TerrainTestAdvancedRenderPath.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TerrainTestAndroidRenderPath.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestDeferredPBRShading.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestDeferredShading.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestDeferredShadingPathShadow.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestFrameGraphImportExport.java (97%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestFrameGraphLoadingSpeeds.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestPBRTerrainAdvancedRenderPath.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestPBRTerrainRenderPath.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestRenderPathPointDirectionalAndSpotLightShadows.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestShadingModel.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestSimpleDeferredLighting.java (99%) rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/TestTileBasedDeferredShading.java (99%) create mode 100644 jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java create mode 100644 jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java create mode 100644 jme3-examples/src/main/java/jme3test/framegraph/examples/HelloFrameGraph.java rename jme3-examples/src/main/java/jme3test/{renderpath => framegraph}/sandbox/Main.java (99%) diff --git a/jme3-core/src/main/java/com/jme3/renderer/Camera.java b/jme3-core/src/main/java/com/jme3/renderer/Camera.java index eb7cca3ae4..af48217267 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Camera.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Camera.java @@ -518,6 +518,25 @@ public void resize(int width, int height, boolean fixAspect) { onFrustumChange(); } } + + /** + * Resizes the camera's view to the width and height only if the + * that would change the camera's view size. + * + * @param width + * @param height + * @param fixAspect + * @param force + * @return true if camera was resized (or forced) + * @see #resize(int, int, boolean) + */ + public boolean resize(int width, int height, boolean fixAspect, boolean force) { + if (force || this.width != width || this.height != height) { + resize(width, height, fixAspect); + return true; + } + return false; + } /** * Returns the value of the bottom frustum 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 4a7e04a84c..b53f67ea4a 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 @@ -73,6 +73,7 @@ public class FGRenderContext { private GeometryRenderHandler geomRender; private Predicate geomFilter; private RenderState renderState; + private int camWidth, camHeight; public FGRenderContext(FrameGraph frameGraph) { this(frameGraph, null); @@ -119,6 +120,8 @@ public void pushRenderSettings() { geomRender = renderManager.getGeometryRenderHandler(); geomFilter = renderManager.getRenderFilter(); renderState = renderManager.getForcedRenderState(); + camWidth = viewPort.getCamera().getWidth(); + camHeight = viewPort.getCamera().getHeight(); } /** * Applies saved render settings, except the framebuffer. @@ -131,6 +134,7 @@ public void popRenderSettings() { renderManager.setRenderFilter(geomFilter); renderManager.setForcedRenderState(renderState); renderManager.getRenderer().setDepthRange(0, 1); + resizeCamera(camWidth, camHeight, true, false, false); if (viewPort.isClearColor()) { renderManager.getRenderer().setBackgroundColor(viewPort.getBackgroundColor()); } @@ -192,9 +196,30 @@ public void renderFullscreen(Material mat) { * @param depth depth texture, or null */ public void renderTextures(Texture2D color, Texture2D depth) { + if (color != null) { + //resizeCamera(color.getImage().getWidth(), color.getImage().getHeight(), false, false); + } else if (depth != null) { + //resizeCamera(depth.getImage().getWidth(), depth.getImage().getHeight(), false, false); + } screen.render(renderManager, color, depth); } + /** + * Resizes the camera to the width and height. + * + * @param w new camera width + * @param h new camera height + * @param fixAspect true to fix camera aspect + * @param ortho true to use parallel projection + * @param force true to force setting the width and height + */ + public void resizeCamera(int w, int h, boolean fixAspect, boolean ortho, boolean force) { + Camera cam = viewPort.getCamera(); + if (cam.resize(w, h, fixAspect, force)) { + renderManager.setCamera(cam, ortho); + } + } + /** * Sets the OpenCL context for compute shading. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java index e467260f7d..c791bf8a37 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java @@ -34,6 +34,7 @@ import com.jme3.asset.AssetManager; import com.jme3.light.LightList; import com.jme3.material.Material; +import com.jme3.math.Vector2f; import com.jme3.renderer.RenderManager; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -119,10 +120,14 @@ public void render(RenderManager rm, Texture2D color, Texture2D depth) { transferMat.getAdditionalRenderState().setDepthTest(writeDepth); transferMat.getAdditionalRenderState().setDepthWrite(writeDepth); render(rm, transferMat); + setQuadScale(Vector2f.UNIT_XY); setAlphaDiscard(null); } } + public void setQuadScale(Vector2f scale) { + transferMat.setVector2("Scale", scale); + } public void setAlphaDiscard(Float alphaDiscard) { if (alphaDiscard == null) { transferMat.clearParam("AlphaDiscard"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java index 6644830a3c..18d80e0e29 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java @@ -16,7 +16,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; -import java.util.concurrent.TimeoutException; /** * @@ -28,14 +27,15 @@ public class PassQueueExecutor implements Runnable, Iterable, Savabl private static int threadTimeoutAttempts = 100; private static final ArrayList DEF_QUEUE = new ArrayList<>(0); - private final FrameGraph frameGraph; + private FrameGraph frameGraph; private final LinkedList queue = new LinkedList<>(); private int index; private Thread thread; private FGRenderContext context; private boolean async = false; private boolean interrupted = false; - + + private PassQueueExecutor() {} public PassQueueExecutor(FrameGraph frameGraph, int index) { this.frameGraph = frameGraph; this.index = index; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 4a6e231b20..44869fd43c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -114,8 +114,7 @@ private int add(RenderResource res) { resources.set(i, res); // find next available slot while (++nextSlot < resources.size()) { - RenderResource r = resources.get(nextSlot); - if (r == null) { + if (resources.get(nextSlot) == null) { break; } } @@ -735,7 +734,7 @@ public int getTextureBinds() { } /** - * Sets the render object map. + * Sets the render manager. * * @param renderManager */ @@ -745,6 +744,11 @@ public void setRenderManager(RenderManager renderManager) { this.cap = this.renderManager.getGraphCapture(); } + /** + * Represents a reference that is made in the future. + *

      + * Used primarily with asynchronous framegraphs. + */ private static class FutureReference { public final PassIndex index; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index 6ad502ef76..2f91e6dcf7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -54,7 +54,8 @@ public interface ResourceDef { * a certain type. *

      * For reallocation, direct resources are preferred over indirect - * resources. Usually because direct resources are more performant. + * resources. Usually because direct resources require fewer changes + * to be usable. * * @param resource * @return diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java index 06178549fa..b7c5257e9c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputPass.java @@ -35,7 +35,6 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; @@ -77,6 +76,9 @@ protected void execute(FGRenderContext context) { if (alphaDiscard != null) { context.getScreen().setAlphaDiscard(alphaDiscard); } + //System.out.println("camera: "+context.getWidth()+" "+context.getHeight()); + //System.out.println("texture: "+colorTex.getImage().getWidth()+" "+colorTex.getImage().getHeight()); + //context.resizeCamera(context.getWidth(), context.getHeight(), true, false, true); context.renderTextures(colorTex, depthTex); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 7fe62483b4..d7d1b7bbdf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -102,7 +102,6 @@ public void prepareRender(FGRenderContext context) { throw new IllegalStateException("Pass is not properly initialized for rendering."); } prepare(context); - // set the flag for checking if resources are available } /** * Executes the pass. @@ -624,9 +623,7 @@ public void makeInput(RenderPass sourcePass, String sourceTicket, String targetT ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); if (targetTicket.startsWith(LIST_PREFIX)) { TicketGroup g = Objects.requireNonNull(groups.get(targetTicket.substring(LIST_PREFIX.length())), "List group cannot be null."); - if (!g.list) { - throw new IllegalStateException("Group must be a list."); - } + g.requireAsList(true); g.add().setSource(source); } else { ResourceTicket target = Objects.requireNonNull(getInput(targetTicket), "Target ticket cannot be null."); @@ -643,9 +640,7 @@ public void makeInput(RenderPass sourcePass, String sourceTicket, String targetT public void makeInputToList(RenderPass sourcePass, String sourceTicket, String targetGroup) { ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); TicketGroup target = Objects.requireNonNull(groups.get(targetGroup), "Target group cannot be null."); - if (!target.list) { - throw new IllegalStateException("Target group must be indefinite."); - } + target.requireAsList(true); target.add().setSource(source); } /** @@ -662,7 +657,7 @@ public ResourceTicket addTicketSlot(String group) { if (g == null) { throw new NullPointerException("Ticket group cannot be null."); } - g.requireAs(false); + g.requireAsList(false); return g.add(); } @@ -1026,7 +1021,7 @@ public ResourceTicket add() { return (array[array.length-1] = create(array.length-1)); } public int remove(ResourceTicket t) { - requireAs(true); + requireAsList(true); int i = array.length-1; for (; i >= 0; i--) { if (array[i] == t) break; @@ -1044,7 +1039,7 @@ public int remove(ResourceTicket t) { return i; } - public void requireAs(boolean asList) { + public void requireAsList(boolean asList) { if (list != asList) { throw new IllegalStateException("Group must be "+(asList ? "a list" : "an array")+" in this context."); } diff --git a/jme3-core/src/main/resources/Common/FrameGraphs/Forward.j3g b/jme3-core/src/main/resources/Common/FrameGraphs/Forward.j3g index f18b8b870e072bcf30c22c70f6e81799b6251e7e..98f0faecd39fa9abcebe01aaf982e8a1d70696c7 100644 GIT binary patch literal 1128 zcmb7EO>fgc5Z&3e9k))K9smg;Aufmml94DEB%~f_5)}y*lAhqS*h}iRS)28`&>KI1 zGyj91!kPcUnK#Y{N{Aw1>Fp#lJ8#~Mcm3*h|4;~_fJhQne$uR*rWaFlm^x!~pbyjjrprjcH8(i^&>aI%JT@v4)@6tt4~IpJ!XCDo~j^9cRXxzHPIa9l4SQ zSObfyVwe9HIW6Qp-pV;(r9)PFti5Iub%8amjrWC})Wk}oS!J;-BHzQCWTmwx^F?Xv zXi@Fy)@oyYtv_5DR{e6B%ta+rCxxvVe^z9d#w&Jo%f>G~ZDXBw%Sle$WjqU? z@U$f!weM>_!$7_RXPBGHpZ^`FdcndfU~! zJn>Hj0WdvaLC38;_yq=dS(NBh)cHLR>BC?Z7xVjYTUm;JYy;9&h! zvhF(wAhbSg4&4DeejA_?KPMj%uehdqZ;_;f9?&O6WlM zlH#E$r^dS*MbT-cak)5(>bT}BQ8m82;m~~+wi-&#oVInP@fq;*>|kw+8aBl|8}e3& LXW3T`ZnysfJ1FyB delta 355 zcmW-dy-EW?6ou!^&+a7Ije=~zMJtZE}U?TxprtuAY z6ie|fEVT0hJU0X1J;ThobMKvR|LW7T^TDA~$`Gf+8xET15?9S%A1>s$hv8WT8xlQw z=+XotOOt&fi9=$^lsNK4BC;Scc_*HHkQVtOZSq4pd{XuawNFi{r&QL$gevtQVMiS! zKAFw$#`7r+Cd^FEkzdS4M$__QIj|)36u+b~YmA>}lkt~c7rfnO+_kxv(YM63VzcPF HX64&|)HEyM diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert index c010f034f3..e0c179c139 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert @@ -2,11 +2,13 @@ #import "Common/ShaderLib/GLSLCompat.glsllib" attribute vec3 inPosition; - varying vec2 texCoord; +uniform vec2 m_Scale; void main() { texCoord = inPosition.xy; - gl_Position = vec4(sign(inPosition.xy - vec2(0.5)), 0.0, 1.0); + vec2 pos = inPosition.xy * vec2(2.0) * m_Scale; + pos -= vec2(1.0); + gl_Position = vec4(pos, 0.0, 1.0); } diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md index cca116177f..4339d99e6c 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TextureTransfer.j3md @@ -3,6 +3,7 @@ MaterialDef TextureTransfer { MaterialParameters { Texture2D ColorMap Texture2D DepthMap + Vector2 Scale : 1.0 1.0 Float AlphaDiscard Boolean Debug } diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/framegraph/TerrainTestAdvancedRenderPath.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java rename to jme3-examples/src/main/java/jme3test/framegraph/TerrainTestAdvancedRenderPath.java index a71f5c8855..56c0a7ca03 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TerrainTestAdvancedRenderPath.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.renderpath; +package jme3test.framegraph; import com.jme3.app.SimpleApplication; import com.jme3.asset.TextureKey; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java b/jme3-examples/src/main/java/jme3test/framegraph/TerrainTestAndroidRenderPath.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java rename to jme3-examples/src/main/java/jme3test/framegraph/TerrainTestAndroidRenderPath.java index 29f043db34..b51f2db996 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TerrainTestAndroidRenderPath.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.renderpath; +package jme3test.framegraph; import com.jme3.app.SimpleApplication; import com.jme3.font.BitmapText; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredPBRShading.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestDeferredPBRShading.java index 2b1fb42a96..d67ceab37a 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredPBRShading.java @@ -1,4 +1,4 @@ -package jme3test.renderpath; +package jme3test.framegraph; import com.jme3.app.SimpleApplication; import com.jme3.environment.EnvironmentProbeControl; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java index 1d50cc8049..7f6e85b77b 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java @@ -1,4 +1,4 @@ -package jme3test.renderpath; +package jme3test.framegraph; import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShadingPathShadow.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShadingPathShadow.java index 738e5f9abc..24a5c89981 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShadingPathShadow.java @@ -1,4 +1,4 @@ -package jme3test.renderpath; +package jme3test.framegraph; import com.jme3.app.SimpleApplication; import com.jme3.font.BitmapText; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java b/jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphImportExport.java similarity index 97% rename from jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphImportExport.java index 804bd1422a..45acba407b 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphImportExport.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphImportExport.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.renderpath; +package jme3test.framegraph; import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; @@ -80,7 +80,7 @@ public void simpleInitApp() { final File file = new File(path+"."+(xml ? "xml" : "j3g")); if (export) { - FrameGraph graph = FrameGraphFactory.deferred(assetManager, true); + FrameGraph graph = FrameGraphFactory.forward(assetManager); try { if (xml) { XMLExporter.getInstance().save(graph.createData(), file); diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java b/jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphLoadingSpeeds.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphLoadingSpeeds.java index 0ed325cae3..d1ac0a61be 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestFrameGraphLoadingSpeeds.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphLoadingSpeeds.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.renderpath; +package jme3test.framegraph; import com.jme3.app.SimpleApplication; import com.jme3.renderer.framegraph.FrameGraph; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainAdvancedRenderPath.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainAdvancedRenderPath.java index f1e928c9f2..29e0b3c380 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/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.renderpath; +package jme3test.framegraph; import com.jme3.app.SimpleApplication; import com.jme3.asset.TextureKey; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java index 16b1d415fa..a06347c4be 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java @@ -1,4 +1,4 @@ -package jme3test.renderpath; +package jme3test.framegraph; /* * Copyright (c) 2009-2021 jMonkeyEngine diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/framegraph/TestRenderPathPointDirectionalAndSpotLightShadows.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestRenderPathPointDirectionalAndSpotLightShadows.java index 6efdec4de3..67aeb4f359 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestRenderPathPointDirectionalAndSpotLightShadows.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.renderpath; +package jme3test.framegraph; import com.jme3.app.SimpleApplication; import com.jme3.light.DirectionalLight; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/framegraph/TestShadingModel.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestShadingModel.java index dd8b2911a0..3de0c03dcc 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestShadingModel.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.renderpath; +package jme3test.framegraph; import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java index 031eff38fa..fd92854b43 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java @@ -30,7 +30,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package jme3test.renderpath; +package jme3test.framegraph; import com.jme3.app.ChaseCameraAppState; import com.jme3.app.DetailedProfilerState; diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java b/jme3-examples/src/main/java/jme3test/framegraph/TestTileBasedDeferredShading.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java rename to jme3-examples/src/main/java/jme3test/framegraph/TestTileBasedDeferredShading.java index 1dc2aa1f0f..bfcfa383a1 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestTileBasedDeferredShading.java @@ -1,4 +1,4 @@ -package jme3test.renderpath; +package jme3test.framegraph; import com.jme3.app.SimpleApplication; import com.jme3.light.PointLight; diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java new file mode 100644 index 0000000000..b80309c41b --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java @@ -0,0 +1,67 @@ +/* + * 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.framegraph.examples; + +import com.jme3.renderer.Camera; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.renderer.framegraph.passes.RenderPass; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; + +/** + * + * @author codex + */ +public class DownsamplingPass extends RenderPass { + + private ResourceTicket in; + private ResourceTicket out; + private final TextureDef texDef = TextureDef.texture2D(); + + @Override + protected void initialize(FrameGraph frameGraph) { + in = addInput("Input"); + out = addOutput("Output"); + texDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); + texDef.setMagFilter(Texture.MagFilter.Nearest); + } + @Override + protected void prepare(FGRenderContext context) { + declare(texDef, out); + reserve(out); + reference(in); + } + @Override + protected void execute(FGRenderContext context) { + + Texture2D inTex = resources.acquire(in); + Image img = inTex.getImage(); + + int w = img.getWidth() / 2; + int h = img.getHeight() / 2; + texDef.setSize(w, h); + + texDef.setFormat(img.getFormat()); + + FrameBuffer fb = getFrameBuffer(context, 1); + resources.acquireColorTarget(fb, out); + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + + context.resizeCamera(w, h, false, false, false); + context.renderTextures(inTex, null); + + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + +} diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java new file mode 100644 index 0000000000..3341afd8fb --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java @@ -0,0 +1,58 @@ +/* + * 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.framegraph.examples; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; + +/** + * + * @author codex + */ +public class HelloCustomFrameGraph extends SimpleApplication { + + public static void main(String[] args) { + HelloCustomFrameGraph app = new HelloCustomFrameGraph(); + AppSettings settings = new AppSettings(true); + settings.setWidth(700); + settings.setHeight(700); + app.setSettings(settings); + app.start(); + } + + @Override + public void simpleInitApp() { + + + + Geometry box = new Geometry("box", new Box(1, 1, 1)); + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Diffuse", ColorRGBA.Blue); + box.setMaterial(mat); + rootNode.attachChild(box); + + PointLight pl = new PointLight(); + pl.setPosition(new Vector3f(2, 5, 5)); + pl.setRadius(100); + rootNode.addLight(pl); + + flyCam.setMoveSpeed(15); + flyCam.setDragToRotate(true); + + } + + @Override + public void simpleUpdate(float tpf) { + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + } + +} diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloFrameGraph.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloFrameGraph.java new file mode 100644 index 0000000000..5f5959bcd9 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloFrameGraph.java @@ -0,0 +1,61 @@ +/* + * 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.framegraph.examples; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.PointLight; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector3f; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.FrameGraphFactory; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; + +/** + * + * @author codex + */ +public class HelloFrameGraph extends SimpleApplication { + + public static void main(String[] args) { + HelloFrameGraph app = new HelloFrameGraph(); + AppSettings settings = new AppSettings(true); + settings.setWidth(700); + settings.setHeight(700); + app.setSettings(settings); + app.start(); + } + + @Override + public void simpleInitApp() { + + FrameGraph frameGraph = FrameGraphFactory.forward(assetManager); + viewPort.setFrameGraph(frameGraph); + + Geometry box = new Geometry("box", new Box(1, 1, 1)); + Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + mat.setBoolean("UseMaterialColors", true); + mat.setColor("Diffuse", ColorRGBA.Blue); + box.setMaterial(mat); + rootNode.attachChild(box); + + PointLight pl = new PointLight(); + pl.setPosition(new Vector3f(2, 5, 5)); + pl.setRadius(100); + rootNode.addLight(pl); + + flyCam.setMoveSpeed(10); + flyCam.setDragToRotate(true); + + } + + @Override + public void simpleUpdate(float tpf) { + cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y); + } + +} diff --git a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java b/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java similarity index 99% rename from jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java rename to jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java index aee0824850..1620392948 100644 --- a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/Main.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java @@ -2,7 +2,7 @@ * 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; +package jme3test.framegraph.sandbox; import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; From a198a8017d0f7ebd1609c9b2ae9587f1ccdc8b74 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sat, 29 Jun 2024 15:11:08 -0400 Subject: [PATCH 108/111] added addLoop --- .../jme3/renderer/framegraph/FrameGraph.java | 47 ++++++++++++++++++- .../framegraph/PassQueueExecutor.java | 37 ++++++++++++++- .../framegraph/examples/DownsamplingPass.java | 3 +- .../examples/HelloCustomFrameGraph.java | 18 +++++++ 4 files changed, 101 insertions(+), 4 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 95a15257ea..6e6e4a4a9e 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 @@ -47,8 +47,8 @@ import com.jme3.renderer.framegraph.passes.Attribute; import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; /** * Manages render passes, dependencies, and resources in a node-based parameter system. @@ -297,6 +297,51 @@ public T add(T pass, int threadIndex, int queueIndex) { public Attribute addAttribute(ResourceTicket ticket) { return getQueue(RENDER_THREAD).addAttribute(ticket); } + /** + * + * @param + * @param array + * @param supplier + * @param inTicket + * @param outTicket + * @return + * @see PassQueueExecutor#addLoop(T[], int, java.util.function.Supplier, java.lang.String, java.lang.String) + */ + public T[] addLoop(T[] array, Supplier supplier, + String inTicket, String outTicket) { + return queues.get(RENDER_THREAD).addLoop(array, -1, supplier, inTicket, outTicket); + } + /** + * + * @param + * @param array + * @param threadIndex + * @param supplier + * @param inTicket + * @param outTicket + * @return + * @see PassQueueExecutor#addLoop(T[], int, java.util.function.Supplier, java.lang.String, java.lang.String) + */ + public T[] addLoop(T[] array, int threadIndex, + Supplier supplier, String inTicket, String outTicket) { + return queues.get(threadIndex).addLoop(array, -1, supplier, inTicket, outTicket); + } + /** + * + * @param + * @param array + * @param threadIndex + * @param passIndex + * @param supplier + * @param inTicket + * @param outTicket + * @return + * @see PassQueueExecutor#addLoop(T[], int, java.util.function.Supplier, java.lang.String, java.lang.String) + */ + public T[] addLoop(T[] array, int threadIndex, int passIndex, + Supplier supplier, String inTicket, String outTicket) { + return queues.get(threadIndex).addLoop(array, passIndex, supplier, inTicket, outTicket); + } /** * Gets the first pass that is of or a subclass of the given class. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java index 18d80e0e29..b6e0e13d4b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; +import java.util.function.Supplier; /** * @@ -35,7 +36,7 @@ public class PassQueueExecutor implements Runnable, Iterable, Savabl private boolean async = false; private boolean interrupted = false; - private PassQueueExecutor() {} + public PassQueueExecutor() {} public PassQueueExecutor(FrameGraph frameGraph, int index) { this.frameGraph = frameGraph; this.index = index; @@ -183,6 +184,40 @@ public Attribute addAttribute(ResourceTicket ticket) { attr.getInput(Attribute.INPUT).setSource(ticket); return attr; } + /** + * Adds a series (loop) of passes at the index. + *

      + * Passes in the loop are connecting the next and previous pass in the loop + * if they exist using the ticket names given. + * + * @param + * @param array + * @param index index to start adding passes at + * @param supplier creates render passes, or null to use what is already + * in the array. + * @param inTicket the input ticket for each pass to connect with the + * previous pass in the loop + * @param outTicket the output ticket for each pass to connect with + * the next pass in the loop + * @return pass array + */ + public T[] addLoop(T[] array, int index, + Supplier supplier, String inTicket, String outTicket) { + for (int i = 0; i < array.length; i++) { + if (supplier != null) { + array[i] = supplier.get(); + } + if (index < 0) { + add(array[i]); + } else { + add(array[i], index++); + } + } + for (int i = 1; i < array.length; i++) { + array[i].makeInput(array[i-1], outTicket, inTicket); + } + return array; + } /** * Gets the first pass that is of or a subclass of the given class. diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java index b80309c41b..0f930f445a 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java @@ -4,7 +4,6 @@ */ package jme3test.framegraph.examples; -import com.jme3.renderer.Camera; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.ResourceTicket; @@ -29,8 +28,8 @@ public class DownsamplingPass extends RenderPass { protected void initialize(FrameGraph frameGraph) { in = addInput("Input"); out = addOutput("Output"); - texDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); texDef.setMagFilter(Texture.MagFilter.Nearest); + texDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); } @Override protected void prepare(FGRenderContext context) { diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java index 3341afd8fb..a408aa1672 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java @@ -9,6 +9,11 @@ import com.jme3.material.Material; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.passes.BucketPass; +import com.jme3.renderer.framegraph.passes.OutputPass; +import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; +import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; import com.jme3.system.AppSettings; @@ -31,7 +36,20 @@ public static void main(String[] args) { @Override public void simpleInitApp() { + FrameGraph fg = new FrameGraph(assetManager); + SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass()); + BucketPass opaque = fg.add(new BucketPass()); + DownsamplingPass[] downsamples = fg.addLoop(new DownsamplingPass[2], + () -> new DownsamplingPass(), "Input", "Output"); + OutputPass out = fg.add(new OutputPass()); + + opaque.makeInput(enqueue, "Opaque", "Geometry"); + downsamples[0].makeInput(opaque, "Color", "Input"); + out.makeInput(downsamples[downsamples.length-1], "Output", "Color"); + + viewPort.setFrameGraph(fg); + viewPort.setBackgroundColor(ColorRGBA.White.mult(0.05f)); Geometry box = new Geometry("box", new Box(1, 1, 1)); Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); From 15eb3bc6861e153abc994415daaa9dab9c39ee20 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Thu, 4 Jul 2024 10:52:21 -0400 Subject: [PATCH 109/111] add faze pass --- .../com/jme3/renderer/framegraph/Access.java | 49 ---- .../renderer/framegraph/FGRenderContext.java | 26 +- .../jme3/renderer/framegraph/FrameGraph.java | 196 ++++++-------- .../renderer/framegraph/FrameGraphData.java | 18 +- .../framegraph/FrameGraphFactory.java | 7 +- .../renderer/framegraph/GeometryQueue.java | 241 ++++++++++++++++++ .../jme3/renderer/framegraph/PassIndex.java | 120 ++++++++- .../jme3/renderer/framegraph/PassLocator.java | 60 +++++ ...PassQueueExecutor.java => PassThread.java} | 171 +++++-------- .../renderer/framegraph/RenderObjectMap.java | 5 +- .../framegraph/passes/BucketPass.java | 7 +- .../framegraph/passes/GBufferPass.java | 13 +- .../framegraph/passes/OutputRenderPass.java | 8 +- ...QueueJoinPass.java => QueueMergePass.java} | 50 ++-- .../framegraph/passes/SceneEnqueuePass.java | 217 ++++++++++++---- .../renderer/queue/GeometryComparator.java | 13 +- .../com/jme3/renderer/queue/GeometryList.java | 17 +- .../com/jme3/post/framegraph/BloomPass.java | 8 +- .../com/jme3/post/framegraph/FazePass.java | 74 ++++++ .../framegraph/TestDeferredShading.java | 3 +- .../framegraph/TestPBRTerrainRenderPath.java | 5 +- .../TestSimpleDeferredLighting.java | 4 +- .../framegraph/examples/DownsamplingPass.java | 4 +- .../examples/HelloCustomFrameGraph.java | 29 ++- 24 files changed, 926 insertions(+), 419 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{PassQueueExecutor.java => PassThread.java} (79%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/{QueueJoinPass.java => QueueMergePass.java} (57%) create mode 100644 jme3-effects/src/main/java/com/jme3/post/framegraph/FazePass.java diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java deleted file mode 100644 index e38fc35c36..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/Access.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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; - -/** - * Defines when a resource can be accessed for reading or writing. - * - * @author codex - */ -public enum Access { - - /** - * Indicates no concurrency. - */ - NoConcurrency(false, false), - - /** - * Indicates concurrency for reading only. - */ - ConcurrentRead(true, false), - - /** - * Indicates concurrency for writing only. - */ - ConcurrentWrite(false, true), - - /** - * Indicates concurrency for reading and writing. - */ - Concurrent(true, true); - - private final boolean read, write; - - private Access(boolean read, boolean write) { - this.read = read; - this.write = write; - } - - public boolean isReadConcurrent() { - return read; - } - - public boolean isWriteConcurrent() { - return write; - } - -} 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 b53f67ea4a..90d0bb3240 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 @@ -146,36 +146,20 @@ public void popFrameBuffer() { renderManager.getRenderer().setFrameBuffer(frameBuffer); } - /** - * Renders the specified queue bucket. - * - * @param bucket queue bucket to render (not null and not {@link RenderQueue.Bucket#Inherit}) - * @param clear true to flush the bucket - */ - public void renderViewPortQueue(RenderQueue.Bucket bucket, boolean clear) { - viewPort.getQueue().renderQueue(bucket, renderManager, viewPort.getCamera(), clear); - } /** * Renders the given geometry list with the camera and render handler. * - * @param list list of geometry to render (not null) + * @param queue queue of geometry to render (not null) * @param cam camera to render with (or null to render with the current viewport camera) * @param handler handler to render with (or null to render with {@link GeometryRenderHandler#DEFAULT}) */ - public void renderGeometryList(GeometryList list, Camera cam, GeometryRenderHandler handler) { + public void renderGeometry(GeometryQueue queue, Camera cam, GeometryRenderHandler handler) { if (cam == null) { cam = viewPort.getCamera(); } - if (handler == null) { - handler = GeometryRenderHandler.DEFAULT; - } - list.setCamera(cam); - list.sort(); - for (Geometry g : list) { - assert g != null; - handler.renderGeometry(renderManager, g); - g.queueDistance = Float.NEGATIVE_INFINITY; - } + queue.setCamera(cam); + queue.sort(); + queue.render(renderManager, handler); } /** * Renders the material on a fullscreen quad. 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 6e6e4a4a9e..53663a2d62 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 @@ -48,6 +48,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import java.util.function.Supplier; /** @@ -98,7 +99,7 @@ public class FrameGraph { private final AssetManager assetManager; private final ResourceList resources; private final FGRenderContext context; - private final ArrayList queues = new ArrayList<>(1); + private final ArrayList threads = new ArrayList<>(1); private final HashMap settings = new HashMap<>(); private final AtomicInteger incompleteQueues = new AtomicInteger(0); private String name = "FrameGraph"; @@ -114,7 +115,7 @@ public FrameGraph(AssetManager assetManager) { this.assetManager = assetManager; this.resources = new ResourceList(this); this.context = new FGRenderContext(this); - this.queues.add(new PassQueueExecutor(this, RENDER_THREAD)); + this.threads.add(new PassThread(this, RENDER_THREAD)); } /** * Creates a new framegraph from the given data. @@ -146,7 +147,7 @@ public FrameGraph(AssetManager assetManager, String dataAsset) { } /** - * Configures the framegraph rendering context. + * Configures the rendering context. * * @param rm * @param vp viewport to render (not null) @@ -182,7 +183,7 @@ public boolean execute() { if (!rendered) { resources.beginRenderingSession(); } - for (PassQueueExecutor queue : queues) { + for (PassThread queue : threads) { for (RenderPass p : queue) { if (prof != null) prof.fgStep(FgStep.Prepare, p.getProfilerName()); if (cap != null) cap.prepareRenderPass(p.getIndex(), p.getProfilerName()); @@ -192,7 +193,7 @@ public boolean execute() { resources.applyFutureReferences(); // cull passes and resources if (prof != null) prof.vpStep(VpStep.FrameGraphCull, vp, null); - for (PassQueueExecutor queue : queues) { + for (PassThread queue : threads) { for (RenderPass p : queue) { p.countReferences(); } @@ -202,9 +203,9 @@ public boolean execute() { if (prof != null) prof.vpStep(VpStep.FrameGraphExecute, vp, null); context.pushRenderSettings(); renderException = null; - incompleteQueues.set(queues.size()); - for (int i = queues.size()-1; i >= 0; i--) { - queues.get(i).execute(context); + incompleteQueues.set(threads.size()); + for (int i = threads.size()-1; i >= 0; i--) { + threads.get(i).execute(context); } if (renderException != null) { renderException.printStackTrace(System.err); @@ -213,7 +214,7 @@ public boolean execute() { context.popFrameBuffer(); // reset if (prof != null) prof.vpStep(VpStep.FrameGraphReset, vp, null); - for (PassQueueExecutor queue : queues) { + for (PassThread queue : threads) { for (RenderPass p : queue) { if (prof != null) prof.fgStep(FgStep.Reset, p.getProfilerName()); p.resetRender(context); @@ -229,7 +230,7 @@ public boolean execute() { */ public void renderingComplete() { // notify passes - for (PassQueueExecutor queue : queues) { + for (PassThread queue : threads) { for (RenderPass p : queue) { p.renderingComplete(); } @@ -238,13 +239,15 @@ public void renderingComplete() { rendered = false; } - private PassQueueExecutor getQueue(int i) { - if (i >= queues.size()) { - PassQueueExecutor queue = new PassQueueExecutor(this, i); - queues.add(queue); + private PassThread getQueue(int i) { + if (i >= threads.size()) { + PassThread queue = new PassThread(this, i); + threads.add(queue); return queue; + } else if (i >= 0) { + return threads.get(i); } else { - return queues.get(i); + return threads.get(RENDER_THREAD); } } @@ -258,17 +261,6 @@ private PassQueueExecutor getQueue(int i) { public T add(T pass) { return getQueue(RENDER_THREAD).add(pass); } - /** - * - * - * @param - * @param pass - * @param threadIndex - * @return - */ - public T add(T pass, int threadIndex) { - return getQueue(threadIndex).add(pass); - } /** * Adds the pass at the index in the pass queue. *

      @@ -278,12 +270,11 @@ public T add(T pass, int threadIndex) { * * @param * @param pass - * @param threadIndex - * @param queueIndex + * @param index * @return */ - public T add(T pass, int threadIndex, int queueIndex) { - return getQueue(threadIndex).add(pass, queueIndex); + public T add(T pass, PassIndex index) { + return getQueue(index.getThreadIndex()).add(pass, index); } /** * Creates and adds an Attribute pass and links it to the given ticket. @@ -297,98 +288,81 @@ public T add(T pass, int threadIndex, int queueIndex) { public Attribute addAttribute(ResourceTicket ticket) { return getQueue(RENDER_THREAD).addAttribute(ticket); } + /** + * Adds an array of passes connected in series to the framegraph. + *

      + * The named input ticket on each pass (except the first) is connected to + * the named output ticket on the previous pass. * * @param - * @param array - * @param supplier - * @param inTicket - * @param outTicket - * @return - * @see PassQueueExecutor#addLoop(T[], int, java.util.function.Supplier, java.lang.String, java.lang.String) - */ - public T[] addLoop(T[] array, Supplier supplier, + * @param array array of passes (elements may be null) + * @param function creates passes where array elements are null (may be null) + * @param inTicket name of the input ticket on each pass + * @param outTicket name of the output ticket on each pass + * @return array of passes + * @see PassThread#addLoop(T[], int, java.util.function.Supplier, java.lang.String, java.lang.String) + */ + public T[] addLoop(T[] array, Function function, String inTicket, String outTicket) { - return queues.get(RENDER_THREAD).addLoop(array, -1, supplier, inTicket, outTicket); - } - /** - * - * @param - * @param array - * @param threadIndex - * @param supplier - * @param inTicket - * @param outTicket - * @return - * @see PassQueueExecutor#addLoop(T[], int, java.util.function.Supplier, java.lang.String, java.lang.String) - */ - public T[] addLoop(T[] array, int threadIndex, - Supplier supplier, String inTicket, String outTicket) { - return queues.get(threadIndex).addLoop(array, -1, supplier, inTicket, outTicket); + return threads.get(RENDER_THREAD).addLoop(array, PassIndex.PASSIVE, function, inTicket, outTicket); } /** + * Adds an array of passes connected in series to the framegraph. + *

      + * The named input ticket on each pass (except the first) is connected to + * the named output ticket on the previous pass. * * @param - * @param array - * @param threadIndex - * @param passIndex - * @param supplier - * @param inTicket - * @param outTicket - * @return - * @see PassQueueExecutor#addLoop(T[], int, java.util.function.Supplier, java.lang.String, java.lang.String) - */ - public T[] addLoop(T[] array, int threadIndex, int passIndex, - Supplier supplier, String inTicket, String outTicket) { - return queues.get(threadIndex).addLoop(array, passIndex, supplier, inTicket, outTicket); + * @param array array of passes (elements may be null) + * @param index index that passes are added to + * @param function creates passes where array elements are null (may be null) + * @param inTicket name of the input ticket on each pass + * @param outTicket name of the output ticket on each pass + * @return array of passes + * @see PassThread#addLoop(T[], int, java.util.function.Supplier, java.lang.String, java.lang.String) + */ + public T[] addLoop(T[] array, PassIndex index, + Function function, String inTicket, String outTicket) { + return threads.get(index.queueIndex).addLoop(array, index, function, inTicket, outTicket); } /** - * Gets the first pass that is of or a subclass of the given class. - * - * @param - * @param type - * @return first qualifying pass, or null - */ - public T get(Class type) { - for (PassQueueExecutor q : queues) { - T p = q.get(type); - if (p != null) { - return p; + * Adds the passes from the given framegraph to this framegraph. + *

      + * The retargeting array determines where each pass thread in the given + * framegraph is added. + * + * @param frameGraph + * @param retarget indices to retarget threads to (not null, elements unaffected) + */ + public void add(FrameGraph frameGraph, PassIndex... retarget) { + final PassIndex index = new PassIndex(); + for (int i = 0; i < frameGraph.threads.size(); i++) { + PassThread source = frameGraph.threads.get(i); + index.set(retarget[i]); + PassThread target = getQueue(index.threadIndex); + for (RenderPass p : source) { + target.add(p, index); + if (!index.useDefaultThread()) { + index.queueIndex++; + } } } - return null; } + /** - * Gets the first pass of the given class that is named as given. + * Gets the first pass that qualifies. * * @param - * @param type - * @param name + * @param by * @return first qualifying pass, or null */ - public T get(Class type, String name) { - for (PassQueueExecutor q : queues) { - T p = q.get(type, name); - if (p != null) { - return p; - } - } - return null; - } - /** - * Gets the pass that holds the given id number. - * - * @param - * @param type - * @param id - * @return pass of the id, or null - */ - public T get(Class type, int id) { - for (PassQueueExecutor q : queues) { - T p = q.get(type, id); - if (p != null) { - return p; + public T get(PassLocator by) { + for (PassThread q : threads) { + T a = q.get(by); + if (a != null) { + return a; } } return null; @@ -404,7 +378,7 @@ public T get(Class type, int id) { * @throws IndexOutOfBoundsException if the index is less than zero or >= the queue size */ public RenderPass remove(int i) { - return queues.get(RENDER_THREAD).remove(i); + return threads.get(RENDER_THREAD).remove(i); } /** * Removes the given pass from the queue. @@ -415,7 +389,7 @@ public RenderPass remove(int i) { * @return true if the pass was removed from the queue */ public boolean remove(RenderPass pass) { - for (PassQueueExecutor queue : queues) { + for (PassThread queue : threads) { if (queue.remove(pass)) { return true; } @@ -426,7 +400,7 @@ public boolean remove(RenderPass pass) { * Clears all passes from the pass queue. */ public void clear() { - for (PassQueueExecutor queue : queues) { + for (PassThread queue : threads) { queue.clear(); } } @@ -548,9 +522,9 @@ public void setCLQueue(CommandQueue clQueue) { * * @param queue */ - public void notifyComplete(PassQueueExecutor queue) { + public void notifyComplete(PassThread queue) { if (incompleteQueues.decrementAndGet() == 1) { - for (PassQueueExecutor q : queues) { + for (PassThread q : threads) { q.notifyLast(); } } @@ -563,7 +537,7 @@ public void notifyComplete(PassQueueExecutor queue) { public void interruptRendering(Exception ex) { assert ex != null : "Interrupting exception cannot be null."; renderException = ex; - for (PassQueueExecutor q : queues) { + for (PassThread q : threads) { q.interrupt(); } } @@ -620,7 +594,7 @@ public String getName() { * @return */ public boolean isAsync() { - return queues.size() > 1; + return threads.size() > 1; } /** @@ -676,7 +650,7 @@ public FrameGraph loadData(String assetPath) { * @return */ public FrameGraphData createData() { - return new FrameGraphData(this, queues, settings); + return new FrameGraphData(this, threads, settings); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java index abf4912805..0015611a29 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java @@ -54,20 +54,20 @@ public class FrameGraphData implements Savable { private static final String DEF_NAME = "FrameGraph"; - private static final ArrayList DEF_QUEUES = new ArrayList<>(0); + private static final ArrayList DEF_QUEUES = new ArrayList<>(0); private static final SavablePassConnection[] DEF_CONNECTIONS = new SavablePassConnection[0]; private static final HashMap DEF_SETTINGS = new HashMap<>(); private final boolean export; private String name; - private ArrayList queues; + private ArrayList queues; private SavablePassConnection[] connections; private Map settings; public FrameGraphData() { export = false; } - public FrameGraphData(FrameGraph fg, ArrayList queues, Map settings) { + public FrameGraphData(FrameGraph fg, ArrayList queues, Map settings) { this.name = fg.getName(); this.queues = queues; this.settings = new HashMap<>(); @@ -89,14 +89,14 @@ public void write(JmeExporter ex) throws IOException { final LinkedList list = new LinkedList<>(); int nextId = 0; // remap ids - for (PassQueueExecutor q : queues) { + for (PassThread q : queues) { for (RenderPass p : q) { p.setExportId(nextId++); idMap.put(p.getId(), p.getExportId()); } } // extract connections - for (PassQueueExecutor q : queues) { + for (PassThread q : queues) { for (RenderPass p : q) for (ResourceTicket t : p.getInputTickets()) { if (t.hasSource()) { int outId = idMap.get(t.getSource().getPassId()); @@ -110,7 +110,7 @@ public void write(JmeExporter ex) throws IOException { out.write(list.toArray(new SavablePassConnection[0]), "connections", DEF_CONNECTIONS); out.writeStringSavableMap(settings, "settings", DEF_SETTINGS); // reset export ids - for (PassQueueExecutor q : queues) { + for (PassThread q : queues) { for (RenderPass p : q) { p.setExportId(-1); } @@ -129,7 +129,7 @@ public void read(JmeImporter im) throws IOException { name = in.readString("name", "FrameGraph"); int baseId = RenderPass.getNextId(); queues = in.readSavableArrayList("passes", DEF_QUEUES); - for (PassQueueExecutor q : queues) { + for (PassThread q : queues) { for (RenderPass p : q) { p.shiftId(baseId); } @@ -160,9 +160,9 @@ public void apply(FrameGraph fg) { fg.setName(name); // cache passes by id HashMap cache = new HashMap<>(); - for (PassQueueExecutor q : queues) { + for (PassThread q : queues) { for (RenderPass p : q) { - fg.add(p, q.getIndex()); + fg.add(p, new PassIndex().setThreadIndex(q.getIndex())); cache.put(p.getId(), p); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 8a5b0a1f7a..211861dbf9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -61,7 +61,7 @@ public static FrameGraph forward(AssetManager assetManager) { FrameGraph fg = new FrameGraph(assetManager); fg.setName("Forward"); - SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass()); + SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass(true, true)); OutputRenderPass opaque = fg.add(new OutputRenderPass()); OutputRenderPass sky = fg.add(new OutputRenderPass(DepthRange.REAR)); OutputRenderPass transparent = fg.add(new OutputRenderPass()); @@ -102,11 +102,12 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled, bool FrameGraph fg = new FrameGraph(assetManager); fg.setName(tiled ? "TiledDeferred" : "Deferred"); - SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass()); + SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass(true, true)); Attribute tileInfoAttr = fg.add(new Attribute()); Junction tileJunct1 = fg.add(new Junction(1, 1)); GBufferPass gbuf = fg.add(new GBufferPass()); - LightImagePass lightImg = fg.add(new LightImagePass(), (async ? 1 : FrameGraph.RENDER_THREAD)); + LightImagePass lightImg = fg.add(new LightImagePass(), + new PassIndex().setThreadIndex(async ? 1 : FrameGraph.RENDER_THREAD)); Junction lightJunct = fg.add(new Junction(1, 6)); Junction tileJunct2 = fg.add(new Junction(1, 2)); DeferredPass deferred = fg.add(new DeferredPass()); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java new file mode 100644 index 0000000000..9eb127995c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java @@ -0,0 +1,241 @@ +/* + * 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.Camera; +import com.jme3.renderer.GeometryRenderHandler; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.queue.GeometryComparator; +import com.jme3.renderer.queue.NullComparator; +import com.jme3.scene.Geometry; +import com.jme3.util.ListSort; +import java.util.ArrayList; + +/** + * Holds a queue of geometries and an internal list of geometry queues. + * + * @author codex + */ +public class GeometryQueue { + + private static final int DEFAULT_SIZE = 32; + + private Geometry[] geometries; + private GeometryComparator comparator; + private final ListSort listSort; + private final ArrayList internalQueues = new ArrayList<>(); + private final DepthRange depth = new DepthRange(); + private boolean updateFlag = true; + private Camera cam; + private int size; + private boolean perspective = true; + + public GeometryQueue() { + this(new NullComparator()); + } + public GeometryQueue(GeometryComparator comparator) { + size = 0; + geometries = new Geometry[DEFAULT_SIZE]; + this.comparator = comparator; + listSort = new ListSort(); + } + + /** + * Sorts this queue and all internal queues. + */ + public void sort() { + if (updateFlag && size > 1) { + // sort the spatial list using the comparator + if (listSort.getLength() != size) { + listSort.allocateStack(size); + } + listSort.sort(geometries, comparator); + updateFlag = false; + } + for (GeometryQueue q : internalQueues) { + q.sort(); + } + } + /** + * Renders this queue and all internal queues. + * + * @param renderManager + * @param handler + */ + public void render(RenderManager renderManager, GeometryRenderHandler handler) { + GeometryRenderHandler h; + if (handler == null) { + h = GeometryRenderHandler.DEFAULT; + } else { + h = handler; + } + renderManager.getRenderer().setDepthRange(depth); + if (!perspective) { + renderManager.setCamera(cam, true); + } + for (Geometry g : geometries) { + assert g != null; + h.renderGeometry(renderManager, g); + g.queueDistance = Float.NEGATIVE_INFINITY; + } + if (!perspective) { + renderManager.setCamera(cam, false); + } + renderManager.getRenderer().setDepthRange(DepthRange.IDENTITY); + for (GeometryQueue q : internalQueues) { + q.render(renderManager, handler); + } + } + + /** + * Adds the geometry to the queue. + * + * @param g + */ + public void add(Geometry g) { + if (size == geometries.length) { + Geometry[] temp = new Geometry[size * 2]; + System.arraycopy(geometries, 0, temp, 0, size); + geometries = temp; // original list replaced by double-size list + } + geometries[size++] = g; + updateFlag = true; + } + /** + * Sets the element at the given index. + * + * @param index The index to set + * @param value The value + */ + public void set(int index, Geometry value) { + geometries[index] = value; + updateFlag = true; + } + /** + * Adds the geometry queue. + * + * @param q + */ + public void add(GeometryQueue q) { + internalQueues.add(q); + } + /** + * Adds the geometry queue at the index. + * + * @param q + * @param index + */ + public void add(GeometryQueue q, int index) { + internalQueues.add(index, q); + } + + /** + * Resets list size to 0. + *

      + * Clears internal queue list, but does not clear internal queues. + */ + public void clear() { + for (int i = 0; i < size; i++) { + geometries[i] = null; + } + internalQueues.clear(); + updateFlag = true; + size = 0; + } + + /** + * Marks this list as requiring sorting. + */ + public void setUpdateNeeded() { + updateFlag = true; + } + /** + * Sets the comparator used to sort geometries. + * + * @param comparator + */ + public void setComparator(GeometryComparator comparator) { + if (this.comparator != comparator) { + this.comparator = comparator; + updateFlag = true; + } + } + /** + * Set the camera that will be set on the geometry comparators + * via {@link GeometryComparator#setCamera(com.jme3.renderer.Camera)}. + * + * @param cam Camera to use for sorting. + */ + public void setCamera(Camera cam) { + if (this.cam != cam) { + this.cam = cam; + comparator.setCamera(this.cam); + updateFlag = true; + } + for (GeometryQueue q : internalQueues) { + q.setCamera(cam); + } + } + /** + * Sets the depth range geometries in this queue (not internal queues) + * are rendered at. + * + * @param depth + */ + public void setDepth(DepthRange depth) { + this.depth.set(depth); + } + /** + * Sets this queue (not internal queues) to render in perspective mode + * (as opposed to parallel projection or orthogonal). + * + * @param perspective + */ + public void setPerspective(boolean perspective) { + this.perspective = perspective; + } + + /** + * Returns the GeometryComparator that this Geometry list uses + * for sorting. + * + * @return the pre-existing instance + */ + public GeometryComparator getComparator() { + return comparator; + } + /** + * Returns the number of elements in this GeometryList. + * + * @return Number of elements in the list + */ + public int size() { + return size; + } + /** + * Returns the element at the given index. + * + * @param index The index to lookup + * @return Geometry at the index + */ + public Geometry get(int index) { + return geometries[index]; + } + /** + * + * @return + */ + public DepthRange getDepth() { + return depth; + } + /** + * + * @return + */ + public boolean isPerspective() { + return perspective; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java index 9eb670537f..1524838346 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java @@ -5,26 +5,97 @@ package com.jme3.renderer.framegraph; /** - * + * Holds indices to a render pass within a framegraph. + *

      + * Negative indices denote using defaults. + * * @author codex */ -public class PassIndex { +public final class PassIndex { - private int threadIndex, queueIndex; + /** + * Index that conforms to defaults only. + */ + public static final PassIndex PASSIVE = new PassIndex(-1, -1); + /** + * Index of the thread the pass is executed on. + */ + public int threadIndex; + /** + * Index in the thread the pass is executed at. + */ + public int queueIndex; + + /** + * Creates a pass index with all defaults (negative indices). + */ + public PassIndex() { + this(-1, -1); + } + /** + * + * @param queueIndex + */ public PassIndex(int queueIndex) { this(FrameGraph.RENDER_THREAD, queueIndex); } + /** + * + * @param threadIndex + * @param queueIndex + */ public PassIndex(int threadIndex, int queueIndex) { this.threadIndex = threadIndex; this.queueIndex = queueIndex; } + /** + * + * @param index + */ + public PassIndex(PassIndex index) { + this(index.threadIndex, index.queueIndex); + } + /** + * + * @param index index to set to (not null) + * @return this + */ public PassIndex set(PassIndex index) { threadIndex = index.threadIndex; queueIndex = index.queueIndex; return this; } + /** + * + * @param threadIndex + * @param queueIndex + * @return this + */ + public PassIndex set(int threadIndex, int queueIndex) { + this.threadIndex = threadIndex; + this.queueIndex = queueIndex; + return this; + } + /** + * + * @param threadIndex + * @return this + */ + public PassIndex setThreadIndex(int threadIndex) { + this.threadIndex = threadIndex; + return this; + } + /** + * + * @param queueIndex + * @return this + */ + public PassIndex setQueueIndex(int queueIndex) { + this.queueIndex = queueIndex; + return this; + } /** * Shifts the thread index up or down one if the thread index is greater @@ -55,12 +126,51 @@ public int shiftQueue(int i, boolean pos) { return queueIndex; } + /** + * Gets the index of the thread the pass is executed on. + * + * @return + */ public int getThreadIndex() { return threadIndex; } + /** + * Gets the index of the pass in a queue. + * + * @return + */ public int getQueueIndex() { return queueIndex; } + + /** + * Returns true if the default thread index is used (thread index is negative). + * + * @return + */ + public boolean useDefaultThread() { + return threadIndex < 0; + } + /** + * Returns true if the default queue index is used (queue index is negative). + * + * @return + */ + public boolean useDefaultQueueIndex() { + return queueIndex < 0; + } + + /** + * Throws an exception if either index is less than zero. + */ + public void requirePositive() { + if (threadIndex < 0) { + throw new IndexOutOfBoundsException("Thread index cannot be negative in this context."); + } + if (queueIndex < 0) { + throw new IndexOutOfBoundsException("Queue index cannot be negative in this context."); + } + } @Override public int hashCode() { @@ -90,5 +200,9 @@ public boolean equals(Object obj) { public String toString() { return PassIndex.class.getSimpleName()+"[thread="+threadIndex+", queue="+queueIndex+']'; } + @Override + public PassIndex clone() { + return new PassIndex(threadIndex, queueIndex); + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java new file mode 100644 index 0000000000..d6c730a02c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java @@ -0,0 +1,60 @@ +/* + * 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 com.jme3.renderer.framegraph.passes.RenderPass; + +/** + * Locates a pass. + * + * @author codex + * @param + */ +public interface PassLocator { + + /** + * Determines if the pass qualifies for this locator. + * + * @param pass + * @return pass, or null if not accepted + */ + public T accept(RenderPass pass); + + /** + * Locates a pass by its type. + * + * @param + * @param type + * @return + */ + public static PassLocator by(Class type) { + return pass -> { + if (type.isAssignableFrom(pass.getClass())) { + return (R)pass; + } else { + return null; + } + }; + } + + /** + * Locates a pass by its type and name. + * + * @param + * @param type + * @param name + * @return + */ + public static PassLocator by(Class type, String name) { + return pass -> { + if (name.equals(pass.getName()) && type.isAssignableFrom(pass.getClass())) { + return (R)pass; + } else { + return null; + } + }; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.java similarity index 79% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.java index b6e0e13d4b..e760b428f2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassQueueExecutor.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.java @@ -16,19 +16,20 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; -import java.util.function.Supplier; +import java.util.Objects; +import java.util.function.Function; /** * * @author codex */ -public class PassQueueExecutor implements Runnable, Iterable, Savable { +public class PassThread implements Runnable, Iterable, Savable { private static long threadTimeoutMillis = 5000; private static int threadTimeoutAttempts = 100; private static final ArrayList DEF_QUEUE = new ArrayList<>(0); - private FrameGraph frameGraph; + private final FrameGraph frameGraph; private final LinkedList queue = new LinkedList<>(); private int index; private Thread thread; @@ -36,8 +37,10 @@ public class PassQueueExecutor implements Runnable, Iterable, Savabl private boolean async = false; private boolean interrupted = false; - public PassQueueExecutor() {} - public PassQueueExecutor(FrameGraph frameGraph, int index) { + public PassThread() { + frameGraph = null; + } + public PassThread(FrameGraph frameGraph, int index) { this.frameGraph = frameGraph; this.index = index; } @@ -45,9 +48,36 @@ public PassQueueExecutor(FrameGraph frameGraph, int index) { @Override public void run() { try { - execute(); + boolean main = isMainThread(); + for (RenderPass p : queue) { + if (interrupted) { + return; + } + if (!p.isUsed()) { + continue; + } + if (main) { + if (context.isProfilerAvailable()) { + context.getProfiler().fgStep(FgStep.Execute, p.getProfilerName()); + } + if (context.isGraphCaptureActive()) { + context.getGraphCapture().executeRenderPass(p.getIndex(), p.getProfilerName()); + } + } + if (async) { + // wait until all input resources are available for use before executing + p.waitForInputs(threadTimeoutMillis, threadTimeoutAttempts); + } + p.executeRender(context); + if (main) { + context.popRenderSettings(); + } + } + frameGraph.notifyComplete(this); } catch (Exception ex) { - frameGraph.interruptRendering(ex); + if (!interrupted) { + frameGraph.interruptRendering(ex); + } } } @Override @@ -78,46 +108,12 @@ public void execute(FGRenderContext context) { async = frameGraph.isAsync(); this.context = context; if (isMainThread()) { - execute(); + run(); } else { thread = new Thread(this); thread.start(); } } - private void execute() { - try { - boolean main = isMainThread(); - for (RenderPass p : queue) { - if (interrupted) { - return; - } - if (!p.isUsed()) { - continue; - } - if (main) { - if (context.isProfilerAvailable()) { - context.getProfiler().fgStep(FgStep.Execute, p.getProfilerName()); - } - if (context.isGraphCaptureActive()) { - context.getGraphCapture().executeRenderPass(p.getIndex(), p.getProfilerName()); - } - } - if (async) { - // wait until all input resources are available for use before executing - p.waitForInputs(threadTimeoutMillis, threadTimeoutAttempts); - } - p.executeRender(context); - if (main) { - context.popRenderSettings(); - } - } - frameGraph.notifyComplete(this); - } catch (Exception ex) { - if (!interrupted) { - frameGraph.interruptRendering(ex); - } - } - } /** * Notifies the queue that all other queues have completed execution. @@ -140,6 +136,7 @@ public void interrupt() { * @return given pass */ public T add(T pass) { + Objects.requireNonNull(pass, "Pass to add cannot be null."); queue.addLast(pass); pass.initializePass(frameGraph, new PassIndex(index, queue.size()-1)); return pass; @@ -147,26 +144,25 @@ public T add(T pass) { /** * Adds the pass at the index in the pass queue. *

      - * If the index is >= the current queue size, the pass will + * If the queue index is >= the current queue size, the pass will * be added to the end of the queue. Passes above the added pass - * will have their indexes shifted. + * will have their queue indices shifted. * * @param * @param pass * @param index * @return */ - public T add(T pass, int index) { - if (index < 0) { - throw new IndexOutOfBoundsException("Index cannot be negative."); - } - if (index >= queue.size()) { + public T add(T pass, PassIndex index) { + Objects.requireNonNull(pass, "Pass to add cannot be null."); + int i = index.getQueueIndex(); + if (i < 0 || i >= queue.size()) { return add(pass); } - queue.add(index, pass); - pass.initializePass(frameGraph, new PassIndex(this.index, index)); + queue.add(i, pass); + pass.initializePass(frameGraph, new PassIndex(this.index, i)); for (RenderPass p : queue) { - p.shiftExecutionIndex(index, true); + p.shiftExecutionIndex(i, true); } return pass; } @@ -192,8 +188,8 @@ public Attribute addAttribute(ResourceTicket ticket) { * * @param * @param array - * @param index index to start adding passes at - * @param supplier creates render passes, or null to use what is already + * @param index index to start adding passes at (unaffected) + * @param function creates render passes, or null to use what is already * in the array. * @param inTicket the input ticket for each pass to connect with the * previous pass in the loop @@ -201,67 +197,38 @@ public Attribute addAttribute(ResourceTicket ticket) { * the next pass in the loop * @return pass array */ - public T[] addLoop(T[] array, int index, - Supplier supplier, String inTicket, String outTicket) { + public T[] addLoop(T[] array, PassIndex index, + Function function, String inTicket, String outTicket) { + PassIndex ind = new PassIndex(index); for (int i = 0; i < array.length; i++) { - if (supplier != null) { - array[i] = supplier.get(); + if (function != null && array[i] == null) { + array[i] = function.apply(i); } - if (index < 0) { + if (index.queueIndex < 0) { add(array[i]); } else { - add(array[i], index++); + add(array[i], ind); + ind.queueIndex++; + } + if (i > 0) { + array[i].makeInput(array[i-1], outTicket, inTicket); } - } - for (int i = 1; i < array.length; i++) { - array[i].makeInput(array[i-1], outTicket, inTicket); } return array; } /** - * Gets the first pass that is of or a subclass of the given class. + * Gets the first pass that qualifies. * * @param - * @param type + * @param by * @return first qualifying pass, or null */ - public T get(Class type) { - for (RenderPass p : queue) { - if (type.isAssignableFrom(p.getClass())) { - return (T)p; - } - } - return null; - } - /** - * Gets the first pass of the given class that is named as given. - * - * @param - * @param type - * @param name - * @return first qualifying pass, or null - */ - public T get(Class type, String name) { - for (RenderPass p : queue) { - if (name.equals(p.getName()) && type.isAssignableFrom(p.getClass())) { - return (T)p; - } - } - return null; - } - /** - * Gets the pass that holds the given id number. - * - * @param - * @param type - * @param id - * @return pass of the id, or null - */ - public T get(Class type, int id) { + public T get(PassLocator by) { for (RenderPass p : queue) { - if (id == p.getId() && type.isAssignableFrom(p.getClass())) { - return (T)p; + T a = by.accept(p); + if (a != null) { + return a; } } return null; @@ -391,7 +358,7 @@ public boolean isMainThread() { * @param threadTimeoutMillis */ public static void setThreadTimeoutMillis(long threadTimeoutMillis) { - PassQueueExecutor.threadTimeoutMillis = threadTimeoutMillis; + PassThread.threadTimeoutMillis = threadTimeoutMillis; } /** * Sets the maximum number of attempts executors will make @@ -402,7 +369,7 @@ public static void setThreadTimeoutMillis(long threadTimeoutMillis) { * @param threadTimeoutAttempts */ public static void setThreadTimeoutAttempts(int threadTimeoutAttempts) { - PassQueueExecutor.threadTimeoutAttempts = threadTimeoutAttempts; + PassThread.threadTimeoutAttempts = threadTimeoutAttempts; } /** diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 57802aab51..078afac085 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -124,11 +124,10 @@ private void allocateSync(RenderResource resource) { if (cap != null) cap.reallocateObject(obj.getId(), resource.getIndex(), resource.getResource().getClass().getSimpleName()); objectsReallocated++; - obj.endInspect(); return; } // then try applying an indirect resource, which is not as desirable - if (!obj.isPrioritized() && indirectObj == null) { + if (indirectObj == null) { indirectRes = def.applyIndirectResource(obj.getObject()); if (indirectRes != null) { indirectObj = obj; @@ -138,12 +137,10 @@ private void allocateSync(RenderResource resource) { } // allocate indirect object if (indirectObj != null) { - indirectObj.startInspect(); resource.setObject(indirectObj, indirectRes); if (cap != null) cap.reallocateObject(indirectObj.getId(), resource.getIndex(), resource.getResource().getClass().getSimpleName()); objectsReallocated++; - indirectObj.endInspect(); return; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java index 14a99358a3..2b63ae4e98 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java @@ -39,10 +39,9 @@ import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.GeometryQueue; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.TextureDef; -import com.jme3.renderer.queue.GeometryList; -import com.jme3.renderer.queue.RenderQueue.Bucket; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; @@ -57,7 +56,7 @@ public class BucketPass extends RenderPass { private final DepthRange depth = new DepthRange(); private ResourceTicket inColor, inDepth, outColor, outDepth; - private ResourceTicket geometry; + private ResourceTicket geometry; private TextureDef colorDef, depthDef; private boolean perspective; @@ -109,7 +108,7 @@ protected void execute(FGRenderContext context) { if (!perspective) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); } - context.renderGeometryList(resources.acquire(geometry), null, null); + context.renderGeometry(resources.acquire(geometry), null, null); if (!perspective) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index 346fa4b6ac..d06b8cc1f0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -31,9 +31,6 @@ */ package com.jme3.renderer.framegraph.passes; -import com.jme3.renderer.framegraph.definitions.ValueDef; -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; @@ -45,12 +42,10 @@ import com.jme3.texture.FrameBuffer; import com.jme3.texture.Image; import com.jme3.texture.Texture2D; -import java.util.LinkedList; import java.util.function.Function; import com.jme3.renderer.GeometryRenderHandler; +import com.jme3.renderer.framegraph.GeometryQueue; import com.jme3.renderer.queue.GeometryList; -import com.jme3.scene.ParentIterator; -import com.jme3.scene.Spatial; /** * Renders diffuse, specular, emissive, normal, and depth information to a set of @@ -64,7 +59,7 @@ public class GBufferPass extends RenderPass implements GeometryRenderHandler { private final static String GBUFFER_PASS = "GBufferPass"; - private ResourceTicket geometry; + private ResourceTicket geometry; private ResourceTicket[] gbuffers; private ResourceTicket numRendersTicket; private final TextureDef[] texDefs = new TextureDef[5]; @@ -107,8 +102,8 @@ protected void execute(FGRenderContext context) { context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); context.getRenderManager().setForcedTechnique(GBUFFER_PASS); context.getRenderManager().setGeometryRenderHandler(this); - GeometryList bucket = resources.acquire(geometry); - context.renderGeometryList(bucket, null, this); + GeometryQueue bucket = resources.acquire(geometry); + context.renderGeometry(bucket, null, this); resources.setPrimitive(numRendersTicket, numRenders); } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java index cac053dfcf..7ad66e5e51 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java @@ -35,13 +35,11 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.GeometryQueue; import com.jme3.renderer.framegraph.ResourceTicket; -import com.jme3.renderer.queue.GeometryList; -import com.jme3.renderer.queue.RenderQueue.Bucket; import java.io.IOException; /** @@ -51,7 +49,7 @@ */ public class OutputRenderPass extends RenderPass { - private ResourceTicket geometry; + private ResourceTicket geometry; private DepthRange depth; private boolean perspective = true; @@ -83,7 +81,7 @@ protected void execute(FGRenderContext context) { } context.getRenderer().setDepthRange(depth); //context.renderViewPortQueue(bucket, true); - context.renderGeometryList(resources.acquire(geometry), null, null); + context.renderGeometry(resources.acquire(geometry), null, null); if (!perspective) { context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueJoinPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java similarity index 57% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueJoinPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java index bb914346c0..d96b544c31 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueJoinPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java @@ -10,61 +10,55 @@ import com.jme3.export.OutputCapsule; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.GeometryQueue; import com.jme3.renderer.framegraph.ResourceTicket; -import com.jme3.renderer.framegraph.definitions.ValueDef; import com.jme3.renderer.queue.GeometryList; -import com.jme3.renderer.queue.NullComparator; import java.io.IOException; /** - * Joins a number of geometry lists into one. - * + * * @author codex */ -public class QueueJoinPass extends RenderPass { +public class QueueMergePass extends RenderPass { private int groupSize = 2; - private ResourceTicket result; - private ValueDef listDef; - - public QueueJoinPass() {} - public QueueJoinPass(int groupSize) { + private ResourceTicket result; + private final GeometryQueue target = new GeometryQueue(); + + public QueueMergePass() {} + public QueueMergePass(int groupSize) { this.groupSize = groupSize; } @Override protected void initialize(FrameGraph frameGraph) { - addInputGroup("Input", groupSize); + addInputGroup("Queues", groupSize); result = addOutput("Result"); - listDef = new ValueDef<>(GeometryList.class, obj -> new GeometryList(new NullComparator())); - listDef.setReviser(list -> list.clear()); } @Override protected void prepare(FGRenderContext context) { - declare(listDef, result); - reference(getGroupArray("Input")); + declare(null, result); + referenceOptional(getGroupArray("Queues")); } @Override protected void execute(FGRenderContext context) { - GeometryList target = resources.acquire(result); - GeometryList[] sources = acquireArray("Input", GeometryList[]::new); - for (GeometryList s : sources) { - target.addList(s); + GeometryQueue[] queues = acquireArray("Queues", n -> new GeometryQueue[n]); + for (GeometryQueue q : queues) { + target.add(q); } + resources.setPrimitive(result, target); } @Override - protected void reset(FGRenderContext context) {} + protected void reset(FGRenderContext context) { + target.clear(); + } @Override protected void cleanup(FrameGraph frameGraph) {} @Override public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule out = ex.getCapsule(this); - if (isAssigned()) { - out.write(getGroupArray("Input").length, "groupSize", 2); - } else { - out.write(groupSize, "groupSize", 2); - } + out.write(groupSize, "groupSize", 2); } @Override public void read(JmeImporter im) throws IOException { @@ -75,9 +69,13 @@ public void read(JmeImporter im) throws IOException { public void setGroupSize(int groupSize) { if (isAssigned()) { - throw new IllegalStateException("Cannot resize group while assigned to a framegraph."); + throw new IllegalStateException("Cannot alter group size while assigned to a framegraph."); } this.groupSize = groupSize; } + public int getGroupSize() { + return groupSize; + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java index 6312654062..e51f64c9f9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java @@ -8,12 +8,15 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; import com.jme3.light.Light; import com.jme3.light.LightList; import com.jme3.renderer.Camera; import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.GeometryQueue; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.queue.GeometryComparator; import com.jme3.renderer.queue.GeometryList; @@ -21,12 +24,13 @@ import com.jme3.renderer.queue.NullComparator; import com.jme3.renderer.queue.OpaqueComparator; import com.jme3.renderer.queue.RenderQueue; -import static com.jme3.renderer.queue.RenderQueue.Bucket.Opaque; import com.jme3.renderer.queue.TransparentComparator; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; /** @@ -35,31 +39,49 @@ */ public class SceneEnqueuePass extends RenderPass { - private final Bucket[] buckets = { - new Bucket("Opaque", new OpaqueComparator()), - new Bucket("Gui", new GuiComparator()), - new Bucket("Transparent", new TransparentComparator()), - new Bucket("Translucent", new TransparentComparator()), - new Bucket("Sky", new NullComparator()), - }; + /** + * Userdata key for denoting the bucket the spatial should be sorted into. + */ + public static final String BUCKET = "RenderQueue.Bucket"; + + /** + * Userdata value for inheriting the bucket of the spatial's parent. + */ + public static final String INHERIT = RenderQueue.Bucket.Inherit.name(); + + public static final String + OPAQUE = "Opaque", + SKY = "Sky", + TRANSPARENT = "Transparent", + GUI = "Gui", + TRANSLUCENT = "Translucent"; private boolean runControlRender = true; + private final HashMap buckets = new HashMap<>(); + private String defaultBucket = OPAQUE; public SceneEnqueuePass() {} - public SceneEnqueuePass(boolean runControlRender) { + public SceneEnqueuePass(boolean runControlRender, boolean useDefaultBuckets) { this.runControlRender = runControlRender; + if (useDefaultBuckets) { + add(OPAQUE, new OpaqueComparator()); + add(SKY, null); + add(TRANSPARENT, new TransparentComparator()); + add(GUI, new GuiComparator()); + add(TRANSLUCENT, new TransparentComparator()); + } } @Override protected void initialize(FrameGraph frameGraph) { - for (Bucket b : buckets) { + for (Queue b : buckets.values()) { b.geometry = addOutput(b.name); b.lights = addOutput(b.name+"Lights"); } } @Override protected void prepare(FGRenderContext context) { - for (Bucket b : buckets) { + for (Queue b : buckets.values()) { declare(null, b.geometry); declare(null, b.lights); } @@ -72,14 +94,14 @@ protected void execute(FGRenderContext context) { vp.getCamera().setPlaneState(0); queueSubScene(context, scenes.get(i), null); } - for (Bucket b : buckets) { + for (Queue b : buckets.values()) { resources.setPrimitive(b.geometry, b.queue); resources.setPrimitive(b.lights, b.lightList); } } @Override protected void reset(FGRenderContext context) { - for (Bucket b : buckets) { + for (Queue b : buckets.values()) { b.queue.clear(); b.lightList.clear(); } @@ -91,78 +113,177 @@ public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule out = ex.getCapsule(this); out.write(runControlRender, "runControlRender", true); + ArrayList list = new ArrayList<>(); + list.addAll(buckets.values()); + out.writeSavableArrayList(list, "buckets", new ArrayList<>()); + out.write(defaultBucket, "defaultBucket", OPAQUE); } @Override public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule in = im.getCapsule(this); runControlRender = in.readBoolean("runControlRender", true); + ArrayList list = in.readSavableArrayList("buckets", new ArrayList<>()); + for (Savable s : list) { + Queue b = (Queue)s; + buckets.put(b.name, b); + } + defaultBucket = in.readString("defaultBucket", OPAQUE); } - private void queueSubScene(FGRenderContext context, Spatial scene, RenderQueue.Bucket parentBucket) { + private void queueSubScene(FGRenderContext context, Spatial spatial, String parentBucket) { // check culling Camera cam = context.getViewPort().getCamera(); - if (!scene.checkCulling(cam)) { + if (!spatial.checkCulling(cam)) { return; } // render controls if (runControlRender) { - scene.runControlRender(context.getRenderManager(), context.getViewPort()); + spatial.runControlRender(context.getRenderManager(), context.getViewPort()); } // get target bucket - RenderQueue.Bucket b = scene.getLocalQueueBucket(); - if (b == RenderQueue.Bucket.Inherit) { - b = parentBucket; - if (b == null) { - b = scene.getQueueBucket(); - } - } + String value = getSpatialBucket(spatial, parentBucket); + Queue bucket = (value != null ? buckets.get(value) : null); // accumulate lights - Bucket bucket = getBucket(b); - for (Light l : scene.getLocalLightList()) { + if (bucket != null) for (Light l : spatial.getLocalLightList()) { bucket.lightList.add(l); } - // add to bucket - if (scene instanceof Node) { - Node n = (Node)scene; + if (spatial instanceof Node) { int camState = cam.getPlaneState(); - for (Spatial s : n.getChildren()) { + for (Spatial s : ((Node)spatial).getChildren()) { // restore cam state before queueing children cam.setPlaneState(camState); - queueSubScene(context, s, b); + queueSubScene(context, s, value); } - } else if (scene instanceof Geometry) { + } else if (bucket != null && spatial instanceof Geometry) { // add to the render queue - Geometry g = (Geometry)scene; + Geometry g = (Geometry)spatial; if (g.getMaterial() == null) { throw new IllegalStateException("No material is set for Geometry: " + g.getName()); } bucket.queue.add(g); } } - private Bucket getBucket(RenderQueue.Bucket bucket) { - switch (bucket) { - case Opaque: return buckets[0]; - case Gui: return buckets[1]; - case Transparent: return buckets[2]; - case Translucent: return buckets[3]; - case Sky: return buckets[4]; - default: throw new IllegalArgumentException(bucket+" does not have a corresponding geometry list."); + private String getSpatialBucket(Spatial spatial, String parentValue) { + String value = spatial.getUserData(BUCKET); + if (value == null) { + value = spatial.getLocalQueueBucket().name(); + } + if (value.equals(INHERIT)) { + if (parentValue != null) { + value = parentValue; + } else if (spatial.getParent() != null) { + value = getSpatialBucket(spatial.getParent(), null); + } else { + value = defaultBucket; + } + } + return value; + } + + /** + * Adds a bucket with the name and comparator. + *

      + * If a bucket already exists under the name, it will be replaced. + * + * @param name + * @param comparator + * @return + * @throws IllegalStateException if called while assigned to a framegraph + */ + public SceneEnqueuePass add(String name, GeometryComparator comparator) { + return add(name, comparator, DepthRange.IDENTITY, true); + } + /** + * Adds a bucket with the name and comparator. + * + * @param name + * @param comparator + * @param depth range in which geometries in the bucket will be rendered within + * @param perspective true to render geometries in the bucket in perspective mode (versus orthogonal) + * @return this + */ + public final SceneEnqueuePass add(String name, GeometryComparator comparator, DepthRange depth, boolean perspective) { + if (isAssigned()) { + throw new IllegalStateException("Cannot add buckets while assigned to a framegraph."); } + buckets.put(name, new Queue(name, comparator, depth, perspective)); + return this; } - private static class Bucket { + /** + * Sets this pass to render controls when traversing the scene. + *

      + * default=true + * + * @param runControlRender + */ + public void setRunControlRender(boolean runControlRender) { + this.runControlRender = runControlRender; + } + /** + * Sets the default bucket geometries are added to if their + * hierarchy only calls for {@link #INHERIT}. + *

      + * default={@link #OPAQUE} + * + * @param defaultBucket + */ + public void setDefaultBucket(String defaultBucket) { + this.defaultBucket = defaultBucket; + } + + /** + * + * @return + */ + public boolean isRunControlRender() { + return runControlRender; + } + /** + * + * @return + */ + public String getDefaultBucket() { + return defaultBucket; + } + + private static class Queue implements Savable { + + public static final NullComparator NULL_COMPARATOR = new NullComparator(); - public final String name; - public final GeometryList queue; - public final LightList lightList; - public ResourceTicket geometry; + public String name; + public GeometryQueue queue; + public final LightList lightList = new LightList(null); + public ResourceTicket geometry; public ResourceTicket lights; - public Bucket(String name, GeometryComparator comparator) { + public Queue() {} + public Queue(String name, GeometryComparator comparator, DepthRange depth, boolean perspective) { + if (comparator == null) { + comparator = Queue.NULL_COMPARATOR; + } this.name = name; - this.queue = new GeometryList(comparator); - this.lightList = new LightList(null); + this.queue = new GeometryQueue(comparator); + this.queue.setDepth(depth); + this.queue.setPerspective(perspective); + } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(name, "name", "Opaque"); + out.write(queue.getComparator(), "comparator", NULL_COMPARATOR); + out.write(queue.getDepth(), "depth", DepthRange.IDENTITY); + out.write(queue.isPerspective(), "perspective", true); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + name = in.readString("name", "Opaque"); + queue = new GeometryQueue(in.readSavable("comparator", GeometryComparator.class, NULL_COMPARATOR)); + queue.setDepth(in.readSavable("depth", DepthRange.class, DepthRange.IDENTITY)); + queue.setPerspective(in.readBoolean("perspective", true)); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryComparator.java b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryComparator.java index 39a8fdf82c..ed5a0e2b48 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryComparator.java +++ b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryComparator.java @@ -31,8 +31,12 @@ */ package com.jme3.renderer.queue; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.Savable; import com.jme3.renderer.Camera; import com.jme3.scene.Geometry; +import java.io.IOException; import java.util.Comparator; /** @@ -41,7 +45,7 @@ * * @author Kirill Vainer */ -public interface GeometryComparator extends Comparator { +public interface GeometryComparator extends Comparator, Savable { /** * Set the camera to use for sorting. @@ -49,4 +53,11 @@ public interface GeometryComparator extends Comparator { * @param cam The camera to use for sorting */ public void setCamera(Camera cam); + + @Override + public default void write(JmeExporter ex) throws IOException {} + + @Override + public default void read(JmeImporter im) throws IOException {} + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java index 9a5af3d58f..e5f02e1007 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/queue/GeometryList.java @@ -32,9 +32,9 @@ package com.jme3.renderer.queue; import java.util.Iterator; -import java.util.NoSuchElementException; import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; import com.jme3.scene.Geometry; import com.jme3.util.ListSort; import java.util.ArrayList; @@ -184,7 +184,6 @@ public void clear() { /** * Sorts the elements in the list according to their Comparator. */ - @SuppressWarnings("unchecked") public void sort() { if (updateFlag && size > 1) { // sort the spatial list using the comparator @@ -198,6 +197,20 @@ public void sort() { l.sort(); } } + + /** + * Renders the geometries in this list and in internal lists. + * + * @param rm + */ + public void render(RenderManager rm) { + for (Geometry g : geometries) { + rm.renderGeometry(g); + } + for (GeometryList l : lists) { + l.render(rm); + } + } @Override public Iterator iterator() { diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java index 0a2d46e16c..1748b3ecdb 100644 --- a/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java @@ -13,10 +13,10 @@ import com.jme3.math.ColorRGBA; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.GeometryQueue; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.framegraph.definitions.TextureDef; import com.jme3.renderer.framegraph.passes.RenderPass; -import com.jme3.renderer.queue.GeometryList; import com.jme3.texture.FrameBuffer; import com.jme3.texture.Texture2D; import java.io.IOException; @@ -28,7 +28,7 @@ public class BloomPass extends RenderPass { private ResourceTicket inColor; - private ResourceTicket objects; + private ResourceTicket objects; private ResourceTicket midTex; private ResourceTicket result; private final TextureDef texDef = TextureDef.texture2D(); @@ -68,7 +68,7 @@ protected void execute(FGRenderContext context) { FrameBuffer midFb = getFrameBuffer("mid", w, h, 1); declare(texDef, midTex); Texture2D midTarget = resources.acquireColorTarget(midFb, midTex); - GeometryList geometry = resources.acquireOrElse(objects, null); + GeometryQueue geometry = resources.acquireOrElse(objects, null); Texture2D scene = resources.acquireOrElse(inColor, null); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); // geometry render @@ -76,7 +76,7 @@ protected void execute(FGRenderContext context) { context.getRenderer().setFrameBuffer(outFb); context.getRenderer().clearBuffers(true, true, true); context.getRenderManager().setForcedTechnique("Glow"); - context.renderGeometryList(geometry, null, null); + context.renderGeometry(geometry, null, null); context.getRenderManager().setForcedTechnique(null); extractMat.setTexture("GlowMap", outTarget); } else { diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/FazePass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/FazePass.java new file mode 100644 index 0000000000..86dda1f78e --- /dev/null +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/FazePass.java @@ -0,0 +1,74 @@ +/* + * 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.post.framegraph; + +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.renderer.framegraph.passes.RenderPass; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; + +/** + * Similar to fog, but does not affect sky visibility. + * + * @author codex + */ +public class FazePass extends RenderPass { + + private ResourceTicket inColor, inDepth, result; + private final TextureDef texDef = TextureDef.texture2D(); + private Material material; + private ColorRGBA color; + + @Override + protected void initialize(FrameGraph frameGraph) { + inColor = addInput("Color"); + inDepth = addInput("Depth"); + result = addOutput("Result"); + texDef.setMagFilter(Texture.MagFilter.Bilinear); + texDef.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/Post/Faze.j3md"); + material.setColor("FazeColor", color); + } + @Override + protected void prepare(FGRenderContext context) { + declare(texDef, result); + reserve(result); + reference(inColor, inDepth); + } + @Override + protected void execute(FGRenderContext context) { + + Texture2D colorTex = resources.acquire(inColor); + Texture2D depthTex = resources.acquire(inDepth); + material.setTexture("ColorMap", colorTex); + material.setTexture("DepthMap", depthTex); + + int w = colorTex.getImage().getWidth(); + int h = colorTex.getImage().getHeight(); + texDef.setSize(w, h); + texDef.setFormat(colorTex.getImage().getFormat()); + + FrameBuffer fb = getFrameBuffer(w, h, 1); + resources.acquireColorTarget(fb, result); + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + context.resizeCamera(w, h, false, false, false); + + context.getScreen().render(context.getRenderManager(), material); + + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + +} diff --git a/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java index 7f6e85b77b..0d974134da 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java @@ -12,6 +12,7 @@ import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; +import com.jme3.renderer.framegraph.PassLocator; import com.jme3.renderer.framegraph.light.TiledRenderGrid; import com.jme3.renderer.framegraph.passes.LightImagePass; import com.jme3.scene.Geometry; @@ -44,7 +45,7 @@ public void simpleInitApp() { FrameGraph fg = FrameGraphFactory.deferred(assetManager, true, true); fg.setJunctionSetting("LightPackMethod", true); - fg.get(LightImagePass.class).setMaxLights(4096); + fg.get(PassLocator.by(LightImagePass.class)).setMaxLights(4096); fg.setSetting("TileInfo", new TiledRenderGrid(4, -1)); viewPort.setFrameGraph(fg); diff --git a/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java index a06347c4be..a1240011df 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java @@ -33,9 +33,7 @@ */ import com.jme3.app.DetailedProfilerState; import com.jme3.app.SimpleApplication; -import com.jme3.asset.ModelKey; import com.jme3.asset.TextureKey; -import com.jme3.asset.cache.AssetCache; import com.jme3.font.BitmapText; import com.jme3.input.KeyInput; import com.jme3.input.controls.ActionListener; @@ -52,6 +50,7 @@ import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; +import com.jme3.renderer.framegraph.PassLocator; import com.jme3.renderer.framegraph.light.TiledRenderGrid; import com.jme3.renderer.framegraph.passes.LightImagePass; import com.jme3.system.AppSettings; @@ -202,7 +201,7 @@ else if(name.equals("addPointLight") && !pressed){ public void simpleInitApp() { FrameGraph fg = FrameGraphFactory.deferred(assetManager, true); - fg.get(LightImagePass.class).setMaxLights(1024); + fg.get(PassLocator.by(LightImagePass.class)).setMaxLights(1024); fg.setSetting("TileInfo", new TiledRenderGrid(7, -1)); //viewPort.setFrameGraph(fg); flyCam.setDragToRotate(true); diff --git a/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java index fd92854b43..893fabae54 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java @@ -54,8 +54,8 @@ import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; +import com.jme3.renderer.framegraph.PassLocator; import com.jme3.renderer.framegraph.debug.GraphEventCapture; -import com.jme3.renderer.framegraph.client.GraphSetting; import com.jme3.renderer.framegraph.passes.Junction; import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; @@ -677,7 +677,7 @@ public void simpleInitApp() { rootNode.addLight(new AmbientLight(ColorRGBA.White)); - Junction lightingMethod = deferred.get(Junction.class, "LightPackMethod"); + Junction lightingMethod = deferred.get(PassLocator.by(Junction.class, "LightPackMethod")); //lightingMethod.setIndexSource((fg, vp) -> 0); File capTarget = new File(System.getProperty("user.home")+"/earlyFrameCapture.txt"); diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java index 0f930f445a..9329b6517b 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java @@ -28,8 +28,8 @@ public class DownsamplingPass extends RenderPass { protected void initialize(FrameGraph frameGraph) { in = addInput("Input"); out = addOutput("Output"); - texDef.setMagFilter(Texture.MagFilter.Nearest); texDef.setMinFilter(Texture.MinFilter.NearestNoMipMaps); + texDef.setMagFilter(Texture.MagFilter.Nearest); } @Override protected void prepare(FGRenderContext context) { @@ -49,7 +49,7 @@ protected void execute(FGRenderContext context) { texDef.setFormat(img.getFormat()); - FrameBuffer fb = getFrameBuffer(context, 1); + FrameBuffer fb = getFrameBuffer(w, h, 1); resources.acquireColorTarget(fb, out); context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java index a408aa1672..d0e5fd7291 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java @@ -10,10 +10,10 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.passes.QueueMergePass; import com.jme3.renderer.framegraph.passes.BucketPass; import com.jme3.renderer.framegraph.passes.OutputPass; import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; -import com.jme3.renderer.queue.RenderQueue; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Box; import com.jme3.system.AppSettings; @@ -37,19 +37,27 @@ public static void main(String[] args) { public void simpleInitApp() { FrameGraph fg = new FrameGraph(assetManager); + viewPort.setFrameGraph(fg); - SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass()); - BucketPass opaque = fg.add(new BucketPass()); - DownsamplingPass[] downsamples = fg.addLoop(new DownsamplingPass[2], - () -> new DownsamplingPass(), "Input", "Output"); + SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass(true, true)); + QueueMergePass merge = fg.add(new QueueMergePass(5)); + BucketPass bucket = fg.add(new BucketPass()); + DownsamplingPass[] downsamples = fg.addLoop(new DownsamplingPass[4], + (i) -> new DownsamplingPass(), "Input", "Output"); OutputPass out = fg.add(new OutputPass()); - opaque.makeInput(enqueue, "Opaque", "Geometry"); - downsamples[0].makeInput(opaque, "Color", "Input"); - out.makeInput(downsamples[downsamples.length-1], "Output", "Color"); + merge.makeInput(enqueue, "Opaque", "Queues[0]"); + merge.makeInput(enqueue, "Sky", "Queues[1]"); + merge.makeInput(enqueue, "Transparent", "Queues[2]"); + merge.makeInput(enqueue, "Gui", "Queues[3]"); + merge.makeInput(enqueue, "Translucent", "Queues[4]"); - viewPort.setFrameGraph(fg); - viewPort.setBackgroundColor(ColorRGBA.White.mult(0.05f)); + bucket.makeInput(merge, "Result", "Geometry"); + + downsamples[0].makeInput(bucket, "Color", "Input"); + + out.makeInput(downsamples[downsamples.length-1], "Output", "Color"); + out.makeInput(bucket, "Depth", "Depth"); Geometry box = new Geometry("box", new Box(1, 1, 1)); Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); @@ -65,6 +73,7 @@ public void simpleInitApp() { flyCam.setMoveSpeed(15); flyCam.setDragToRotate(true); + viewPort.setBackgroundColor(ColorRGBA.White.mult(0.05f)); } From 443643ec521011e2751cbb037e6bdab4d031daa4 Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:08:01 -0400 Subject: [PATCH 110/111] improved javadoc and fixed issue with deferred techniquedefs --- .../java/com/jme3/export/InputCapsule.java | 3 + .../java/com/jme3/export/SavableObject.java | 114 ++++----- .../jme3/renderer/framegraph/DepthRange.java | 3 +- .../renderer/framegraph/FGRenderContext.java | 19 +- .../jme3/renderer/framegraph/FrameGraph.java | 100 ++++---- .../renderer/framegraph/FrameGraphData.java | 11 +- .../framegraph/FrameGraphFactory.java | 53 ++-- .../renderer/framegraph/FullScreenQuad.java | 16 +- .../renderer/framegraph/GeometryQueue.java | 53 +++- .../jme3/renderer/framegraph/PassIndex.java | 38 ++- .../jme3/renderer/framegraph/PassLocator.java | 31 ++- .../jme3/renderer/framegraph/PassThread.java | 44 +++- .../renderer/framegraph/RenderModule.java | 13 - .../renderer/framegraph/RenderObject.java | 58 ++++- .../renderer/framegraph/RenderObjectMap.java | 42 ++-- .../renderer/framegraph/ResourceList.java | 67 +++--- .../renderer/framegraph/ResourceProducer.java | 2 + .../renderer/framegraph/ResourceTicket.java | 9 +- ...{RenderResource.java => ResourceView.java} | 11 +- .../framegraph/SavablePassConnection.java | 5 +- .../jme3/renderer/framegraph/TimeFrame.java | 6 +- .../framegraph/client/GraphSetting.java | 67 +++++- .../framegraph/client/GraphSource.java | 32 ++- .../framegraph/client/GraphTarget.java | 7 +- .../framegraph/client/GraphValue.java | 99 ++++++++ .../client/MatParamTargetControl.java | 28 ++- .../framegraph/client/ViewPortFilter.java | 50 +++- .../framegraph/debug/GraphEventCapture.java | 227 ++++++++++++++++-- .../definitions/AbstractResourceDef.java | 15 +- .../framegraph/definitions/ResourceDef.java | 23 +- .../framegraph/definitions/TextureDef.java | 25 +- .../framegraph/filters/SoftBloomPass.java | 13 - .../framegraph/light/LightFrustum.java | 82 ++++++- .../framegraph/light/LightImagePacker.java | 65 ++++- .../framegraph/light/TiledRenderGrid.java | 8 +- .../renderer/framegraph/passes/Attribute.java | 10 + .../renderer/framegraph/passes/BlitPass.java | 33 ++- .../framegraph/passes/DeferredPass.java | 97 +++++--- .../framegraph/passes/FilterPass.java | 15 -- .../framegraph/passes/GBufferPass.java | 15 +- .../{BucketPass.java => GeometryPass.java} | 34 ++- .../framegraph/passes/GroupAttribute.java | 99 +++++++- .../renderer/framegraph/passes/Junction.java | 33 ++- .../framegraph/passes/LegacyFilterPass.java | 142 ----------- .../framegraph/passes/LightImagePass.java | 50 +++- .../passes/LightListExtractPass.java | 31 ++- ...enderPass.java => OutputGeometryPass.java} | 38 +-- .../passes/PostProcessingRenderPass.java | 116 --------- .../framegraph/passes/QueueMergePass.java | 45 +++- .../framegraph/passes/RenderPass.java | 128 ++++++---- .../framegraph/passes/SceneEnqueuePass.java | 88 +++++-- .../Common/MatDefs/ShadingCommon/Screen.vert | 4 +- .../com/jme3/post/framegraph/BloomPass.java | 66 ++++- .../jme3/post/framegraph/CartoonEdgePass.java | 44 +++- .../post/framegraph/DepthOfFieldPass.java | 44 +++- .../com/jme3/post/framegraph/FazePass.java | 74 ------ .../com/jme3/post/framegraph/FogPass.java | 180 ++++++++++++++ .../com/jme3/post/framegraph/HazePass.java | 173 +++++++++++++ .../resources/Common/MatDefs/Post/Haze.frag | 26 ++ .../resources/Common/MatDefs/Post/Haze.j3md | 17 ++ .../resources/Common/MatDefs/Post/SkyFog.frag | 34 +++ .../resources/Common/MatDefs/Post/SkyFog.j3md | 26 ++ .../framegraph/examples/DownsamplingPass.java | 44 +++- .../examples/HelloCustomFrameGraph.java | 4 +- .../framegraph/examples/effects/TestFog.java | 95 ++++++++ .../jme3test/framegraph/sandbox/Main.java | 12 +- 66 files changed, 2394 insertions(+), 862 deletions(-) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderModule.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{RenderResource.java => ResourceView.java} (95%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphValue.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/filters/SoftBloomPass.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/FilterPass.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/{BucketPass.java => GeometryPass.java} (84%) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LegacyFilterPass.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/{OutputRenderPass.java => OutputGeometryPass.java} (67%) delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingRenderPass.java delete mode 100644 jme3-effects/src/main/java/com/jme3/post/framegraph/FazePass.java create mode 100644 jme3-effects/src/main/java/com/jme3/post/framegraph/FogPass.java create mode 100644 jme3-effects/src/main/java/com/jme3/post/framegraph/HazePass.java create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Haze.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/Haze.j3md create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/SkyFog.frag create mode 100644 jme3-effects/src/main/resources/Common/MatDefs/Post/SkyFog.j3md create mode 100644 jme3-examples/src/main/java/jme3test/framegraph/examples/effects/TestFog.java diff --git a/jme3-core/src/main/java/com/jme3/export/InputCapsule.java b/jme3-core/src/main/java/com/jme3/export/InputCapsule.java index dbe7a58fcc..bde385f7ea 100644 --- a/jme3-core/src/main/java/com/jme3/export/InputCapsule.java +++ b/jme3-core/src/main/java/com/jme3/export/InputCapsule.java @@ -122,6 +122,9 @@ public default T readSavable(String name, Class type, T d return defVal; } } + public default SavableObject readSavableObject(String name, SavableObject defVal) throws IOException { + return readSavable(name, SavableObject.class, defVal); + } // ArrayLists diff --git a/jme3-core/src/main/java/com/jme3/export/SavableObject.java b/jme3-core/src/main/java/com/jme3/export/SavableObject.java index cd8b281294..f07f0f0143 100644 --- a/jme3-core/src/main/java/com/jme3/export/SavableObject.java +++ b/jme3-core/src/main/java/com/jme3/export/SavableObject.java @@ -15,13 +15,18 @@ import java.util.Map; /** - * + * Saves the internal object if it is savable. + * * @author codex */ public class SavableObject implements Savable { + public static final SavableObject NULL = new SavableObject(); + private static final String OBJECT = "object"; + private static final String TYPE = "type"; + private static final String NULL_TYPE = "Null"; + private Object object; - private final String name = "object"; public SavableObject() {} public SavableObject(Object object) { @@ -30,115 +35,116 @@ public SavableObject(Object object) { @Override public void write(JmeExporter ex) throws IOException { + if (object == null) return; OutputCapsule out = ex.getCapsule(this); if (object instanceof Savable) { - out.write((Savable)object, name, (Savable)object); - out.write("Savable", "type", ""); + out.write((Savable)object, OBJECT, null); + out.write("Savable", TYPE, NULL_TYPE); } else if (object instanceof Integer) { - out.write((int)object, name, (int)object); - out.write("Integer", "type", ""); + out.write((int)object, OBJECT, 0); + out.write("Integer", TYPE, NULL_TYPE); } else if (object instanceof Float) { - out.write((float)object, name, (float)object); - out.write("Float", "type", ""); + out.write((float)object, OBJECT, 0); + out.write("Float", TYPE, NULL_TYPE); } else if (object instanceof Double) { - out.write((double)object, name, (double)object); - out.write("Double", "type", ""); + out.write((double)object, OBJECT, 0); + out.write("Double", TYPE, NULL_TYPE); } else if (object instanceof Boolean) { - out.write((boolean)object, name, (boolean)object); - out.write("Boolean", "type", ""); + out.write((boolean)object, OBJECT, false); + out.write("Boolean", TYPE, NULL_TYPE); } else if (object instanceof Byte) { - out.write((byte)object, name, (byte)object); - out.write("Byte", "type", ""); + out.write((byte)object, OBJECT, (byte)0); + out.write("Byte", TYPE, NULL_TYPE); } else if (object instanceof String) { - out.write((String)object, name, (String)object); - out.write("String", "type", ""); + out.write((String)object, OBJECT, null); + out.write("String", TYPE, NULL_TYPE); } else if (object instanceof Long) { - out.write((Long)object, name, (Long)object); - out.write("Long", "type", ""); + out.write((Long)object, OBJECT, 0); + out.write("Long", TYPE, NULL_TYPE); } else if (object instanceof Short) { - out.write((short)object, name, (short)object); - out.write("Short", "type", ""); + out.write((short)object, OBJECT, (short)0); + out.write("Short", TYPE, NULL_TYPE); } else if (object instanceof BitSet) { - out.write((BitSet)object, name, (BitSet)object); - out.write("BitSet", "type", ""); + out.write((BitSet)object, OBJECT, null); + out.write("BitSet", TYPE, NULL_TYPE); } else if (object instanceof FloatBuffer) { - out.write((FloatBuffer)object, name, (FloatBuffer)object); - out.write("FloatBuffer", "type", ""); + out.write((FloatBuffer)object, OBJECT, null); + out.write("FloatBuffer", TYPE, NULL_TYPE); } else if (object instanceof IntBuffer) { - out.write((IntBuffer)object, name, (IntBuffer)object); - out.write("IntBuffer", "type", ""); + out.write((IntBuffer)object, OBJECT, null); + out.write("IntBuffer", TYPE, NULL_TYPE); } else if (object instanceof ByteBuffer) { - out.write((ByteBuffer)object, name, (ByteBuffer)object); - out.write("ByteBuffer", "type", ""); + out.write((ByteBuffer)object, OBJECT, null); + out.write("ByteBuffer", TYPE, NULL_TYPE); } else if (object instanceof ShortBuffer) { - out.write((ShortBuffer)object, name, (ShortBuffer)object); - out.write("ShortBuffer", "type", ""); + out.write((ShortBuffer)object, OBJECT, null); + out.write("ShortBuffer", TYPE, NULL_TYPE); } else if (object instanceof ArrayList) { - out.writeSavableArrayList((ArrayList)object, name, (ArrayList)object); - out.write("ArrayList", "type", ""); + out.writeSavableArrayList((ArrayList)object, OBJECT, null); + out.write("ArrayList", TYPE, NULL_TYPE); } else if (object instanceof Map) { - out.writeStringSavableMap((Map)object, name, (Map)object); - out.write("StringMap", "type", ""); + out.writeStringSavableMap((Map)object, OBJECT, null); + out.write("StringMap", TYPE, NULL_TYPE); } else if (object instanceof IntMap) { - out.writeIntSavableMap((IntMap)object, name, (IntMap)object); - out.write("IntMap", "type", ""); + out.writeIntSavableMap((IntMap)object, OBJECT, null); + out.write("IntMap", TYPE, NULL_TYPE); } } @Override public void read(JmeImporter im) throws IOException { InputCapsule in = im.getCapsule(this); - String type = in.readString("type", ""); + String type = in.readString(TYPE, NULL_TYPE); switch (type) { case "Savable": - object = in.readSavable(name, null); + object = in.readSavable(OBJECT, null); break; case "Integer": - object = in.readInt(name, 0); + object = in.readInt(OBJECT, 0); break; case "Float": - object = in.readFloat(name, 0); + object = in.readFloat(OBJECT, 0); break; case "Double": - object = in.readDouble(name, 0); + object = in.readDouble(OBJECT, 0); break; case "Boolean": - object = in.readBoolean(name, false); + object = in.readBoolean(OBJECT, false); break; case "Byte": - object = in.readByte(name, (byte)0); + object = in.readByte(OBJECT, (byte)0); break; case "String": - object = in.readString(name, null); + object = in.readString(OBJECT, null); break; case "Long": - object = in.readLong(name, 0); + object = in.readLong(OBJECT, 0); break; case "Short": - object = in.readShort(name, (short)0); + object = in.readShort(OBJECT, (short)0); break; case "BitSet": - object = in.readBitSet(name, null); + object = in.readBitSet(OBJECT, null); break; case "FloatBuffer": - object = in.readFloatBuffer(name, null); + object = in.readFloatBuffer(OBJECT, null); break; case "IntBuffer": - object = in.readIntBuffer(name, null); + object = in.readIntBuffer(OBJECT, null); break; case "ByteBuffer": - object = in.readByteBuffer(name, null); + object = in.readByteBuffer(OBJECT, null); break; case "ShortBuffer": - object = in.readShortBuffer(name, null); + object = in.readShortBuffer(OBJECT, null); break; case "ArrayList": - object = in.readSavableArrayList(name, null); + object = in.readSavableArrayList(OBJECT, null); break; case "StringMap": - object = in.readStringSavableMap(name, null); + object = in.readStringSavableMap(OBJECT, null); break; case "IntMap": - object = in.readIntSavableMap(name, null); + object = in.readIntSavableMap(OBJECT, null); break; } } 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 index 8536f509dc..ce9ec464cd 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java @@ -39,8 +39,7 @@ import java.io.IOException; /** - * Defines the range between 0 and 1 at values written to depth buffers - * are clamped to. + * Defines a range within 0 and 1 that render depth values are clamped to. * * @author codex */ 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 90d0bb3240..8a11990269 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 @@ -47,12 +47,25 @@ import com.jme3.texture.Texture2D; import java.util.function.Predicate; import com.jme3.renderer.GeometryRenderHandler; -import com.jme3.renderer.queue.GeometryList; /** - * Contains necessary context for framegraph rendering. + * Context for FrameGraph rendering. *

      - * Also manages renderer states, to ensure settings do no leak between passes. + * Provides RenderPasses with access to important objects such as the RenderManager, + * ViewPort, profiler, and fullscreen quad. Utility methods are provided for + * fullscreen quad rendering and camera management. + *

      + * Additionally, the following render settings are handled to ensure settings + * do not leak between renders. + *

        + *
      • Forced technique
      • + *
      • Forced material
      • + *
      • Geometry render handler
      • + *
      • Geometry filter
      • + *
      • Forced render state
      • + *
      + * After each pass execution on the main render thread, {@link #popRenderSettings()} is + * called to reset these settings to what they were before rendering began. * * @author codex */ 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 53663a2d62..bf56cc70f9 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 @@ -49,7 +49,6 @@ import java.util.HashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; -import java.util.function.Supplier; /** * Manages render passes, dependencies, and resources in a node-based parameter system. @@ -92,7 +91,7 @@ public class FrameGraph { /** - * Index for the main render thread pass queue. + * Index of the {@link PassThread} running on the main render thread. */ public static final int RENDER_THREAD = 0; @@ -148,6 +147,8 @@ public FrameGraph(AssetManager assetManager, String dataAsset) { /** * Configures the rendering context. + *

      + * Called automatically by the RenderManager before calling {@link #execute()}. * * @param rm * @param vp viewport to render (not null) @@ -169,7 +170,7 @@ public void configure(RenderManager rm, ViewPort vp, AppProfiler prof, float tpf *

    • Clean (reset).
    • * * - * @return true if this is the first execution this frame + * @return true if this is the first execution of this FrameGraph this frame */ public boolean execute() { // prepare @@ -226,7 +227,8 @@ public boolean execute() { else return (rendered = true); } /** - * Should be called only when all rendering for the frame is complete. + * Called automatically by the RenderManager after all rendering operations are + * complete and this FrameGraph executed at least once this frame. */ public void renderingComplete() { // notify passes @@ -252,7 +254,7 @@ private PassThread getQueue(int i) { } /** - * Adds the pass to end of the pass queue. + * Adds the pass to end of the {@link PassThread} running on the main render thread. * * @param * @param pass @@ -262,9 +264,12 @@ public T add(T pass) { return getQueue(RENDER_THREAD).add(pass); } /** - * Adds the pass at the index in the pass queue. + * Adds the pass at the index. + *

      + * If the thread index is >= the total number of {@link PassThreads}s, + * a new PassThread will be created for this to be added to. *

      - * If the index is >= the current queue size, the pass will + * If the queue index is >= the current queue size, the pass will * be added to the end of the queue. Passes above the added pass * will have their indexes shifted. * @@ -276,24 +281,16 @@ public T add(T pass) { public T add(T pass, PassIndex index) { return getQueue(index.getThreadIndex()).add(pass, index); } - /** - * Creates and adds an Attribute pass and links it to the given ticket. - *

      - * This is handy for quickly debugging various resources in the graph. - * - * @param - * @param ticket ticket to reference from - * @return created Attribute - */ - public Attribute addAttribute(ResourceTicket ticket) { - return getQueue(RENDER_THREAD).addAttribute(ticket); - } /** * Adds an array of passes connected in series to the framegraph. *

      * The named input ticket on each pass (except the first) is connected to - * the named output ticket on the previous pass. + * the named output ticket on the previous pass, creating a series of connected + * passes. The array length determines the number of passes that will be added + * and connected. + *

      + * Null elements of the array are replaced using the Function. * * @param * @param array array of passes (elements may be null) @@ -324,7 +321,7 @@ public T[] addLoop(T[] array, Function functi */ public T[] addLoop(T[] array, PassIndex index, Function function, String inTicket, String outTicket) { - return threads.get(index.queueIndex).addLoop(array, index, function, inTicket, outTicket); + return threads.get(index.getThreadIndex()).addLoop(array, index, function, inTicket, outTicket); } /** @@ -369,7 +366,7 @@ public T get(PassLocator by) { } /** - * Removes the pass at the index in the queue. + * Removes the pass at the index in the main {@link PassThread} (running on the main render thread). *

      * Passes above the removed pass will have their indexes shifted. * @@ -381,9 +378,10 @@ public RenderPass remove(int i) { return threads.get(RENDER_THREAD).remove(i); } /** - * Removes the given pass from the queue. + * Removes the given pass from this FrameGraph. *

      - * Passes above the removed pass will have their indexes shifted. + * Passes above the removed pass will have their indices shifted to + * accomodate. * * @param pass * @return true if the pass was removed from the queue @@ -397,7 +395,7 @@ public boolean remove(RenderPass pass) { return false; } /** - * Clears all passes from the pass queue. + * Clears all passes from this FrameGraph. */ public void clear() { for (PassThread queue : threads) { @@ -406,7 +404,10 @@ public void clear() { } /** - * Sets the setting under the name. + * Registers the object under the name in the settings map. + *

      + * Registered objects can be referenced by passes by name. Any existing + * object already registered under the name will be replaced. * * @param * @param name @@ -418,14 +419,15 @@ public T setSetting(String name, T object) { return object; } /** - * Sets the setting under the name and creates a GraphSetting - * of the same name. + * Registers the object under the name in the settings map, and creates + * a {@link GraphSetting} with the same name. * * @param * @param name * @param object - * @param create + * @param create true to create a GraphSetting, otherwise one will not be created and null returned * @return created graph setting + * @see #setSetting(java.lang.String, java.lang.Object) */ public GraphSetting setSetting(String name, T object, boolean create) { setSetting(name, object); @@ -436,7 +438,7 @@ public GraphSetting setSetting(String name, T object, boolean create) { } } /** - * Sets an integer setting based on a boolean value. + * Sets an integer in the settings map based on a boolean value. *

      * If the boolean is true, 0 is written, otherwise -1 is written. This is * used primarily for Junction sources: 0 points to the first input, and -1 @@ -445,16 +447,18 @@ public GraphSetting setSetting(String name, T object, boolean create) { * @param name * @param value * @return + * @see #setSetting(java.lang.String, java.lang.Object) */ public int setJunctionSetting(String name, boolean value) { return setSetting(name, value ? 0 : -1); } /** - * Gets the setting under the name, or null. + * Gets the object registered under the name in the settings map, + * or null if none is registered. * * @param * @param name - * @return + * @return registered object, or null */ public T getSetting(String name) { Object obj = settings.get(name); @@ -465,11 +469,11 @@ public T getSetting(String name) { } } /** - * Removes the setting under the name. + * Removes the object registered under the name in the settings map. * * @param * @param name - * @return removed setting, or null + * @return removed object, or null */ public T removeSetting(String name) { Object obj = settings.remove(name); @@ -491,7 +495,7 @@ public HashMap getSettingsMap() { } /** - * Sets the name of this framegraph. + * Sets the name of this FrameGraph. * * @param name */ @@ -499,7 +503,7 @@ public void setName(String name) { this.name = name; } /** - * Sets the OpenCL context for compute shading. + * Sets the OpenCL context used for compute shading. * * @param clContext */ @@ -518,7 +522,7 @@ public void setCLQueue(CommandQueue clQueue) { } /** - * Called internally to notify the framegraph that a queue has completed execution. + * Called automatically to notify the FrameGraph that a {@link PassThread} has completed execution. * * @param queue */ @@ -530,7 +534,7 @@ public void notifyComplete(PassThread queue) { } } /** - * Called internally when a rendering exception occurs. + * Called automatically when a rendering exception occurs. * * @param ex */ @@ -543,6 +547,7 @@ public void interruptRendering(Exception ex) { } /** + * Gets the {@link AssetManager} assigned to this FrameGraph. * * @return */ @@ -550,7 +555,7 @@ public AssetManager getAssetManager() { return assetManager; } /** - * Gets the ResourceList that manages resources for this framegraph. + * Gets the {@link ResourceList} that manages resources for this FrameGraph. * * @return */ @@ -558,7 +563,7 @@ public ResourceList getResources() { return resources; } /** - * Gets the framegraph rendering context. + * Gets the rendering context. * * @return */ @@ -566,6 +571,7 @@ public FGRenderContext getContext() { return context; } /** + * Gets the RenderManager. * * @return */ @@ -573,7 +579,7 @@ public RenderManager getRenderManager() { return context.getRenderManager(); } /** - * Gets the OpenCL context for compute shading. + * Gets the OpenCL context used for compute shading, or null if not set. * * @return */ @@ -589,7 +595,7 @@ public String getName() { return name; } /** - * Returns true if this framegraph is running asynchronous passes. + * Returns true if this framegraph is running asynchronous {@link PassThread}s. * * @return */ @@ -598,7 +604,7 @@ public boolean isAsync() { } /** - * Applies the framegraph data to this framegraph. + * Applies the {@link FrameGraphData} to this FrameGraph. * * @param data * @return this instance @@ -608,7 +614,7 @@ public final FrameGraph applyData(FrameGraphData data) { return this; } /** - * Applies the framegraph data to this framegraph. + * Applies the {@link FrameGraphData} to this FrameGraph. * * @param data * @return this instance @@ -627,7 +633,7 @@ public FrameGraph applyData(Object data) { } } /** - * Loads and applies framegraph data from the key. + * Loads and applies {@link FrameGraphData} from the key. * * @param key * @return @@ -636,7 +642,7 @@ public FrameGraph loadData(FrameGraphKey key) { return applyData(assetManager.loadFrameGraph(key)); } /** - * Loads and applies framegraph data at the specified asset path. + * Loads and applies {@link FrameGraphData} at the specified asset path. * * @param assetPath * @return @@ -645,7 +651,7 @@ public FrameGraph loadData(String assetPath) { return applyData(assetManager.loadFrameGraph(assetPath)); } /** - * Creates exportable framegraph data. + * Creates exportable snapshot of this FrameGraph as {@link FrameGraphData}. * * @return */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java index 0015611a29..ec40fe3f9e 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java @@ -45,9 +45,7 @@ import java.util.Map; /** - * Holds framegraph data ready for import or export. - *

      - * Each individual data instance should only be affiliated with one framegraph. + * Holds FrameGraph snapshot data ready for import or export. * * @author codex */ @@ -144,7 +142,7 @@ public void read(JmeImporter im) throws IOException { } /** - * Applies internal data to the framegraph. + * Applies internal data to the FrameGraph. *

      * This operation consumes the data. * @@ -191,7 +189,10 @@ public boolean isExportOnly() { } /** - * Returns true if this data has been consumed. + * Returns true if this data has been consumed by completing an import + * or export. + *

      + * Attempting to import or export consumed data will result in an exception. * * @return */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index 211861dbf9..f051e7bc1f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -39,19 +39,20 @@ import com.jme3.renderer.framegraph.passes.GBufferPass; import com.jme3.renderer.framegraph.passes.Junction; import com.jme3.renderer.framegraph.passes.LightImagePass; -import com.jme3.renderer.framegraph.passes.OutputRenderPass; +import com.jme3.renderer.framegraph.passes.OutputGeometryPass; import com.jme3.renderer.framegraph.passes.OutputPass; +import com.jme3.renderer.framegraph.passes.QueueMergePass; import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; /** - * Utility class for constructing common framegraphs. + * Utility class for constructing common {@link FrameGraph}s in code. * * @author codex */ public class FrameGraphFactory { /** - * Constructs a standard forward framegraph, with no controllable features. + * Constructs a standard forward FrameGraph, with no controllable settings. * * @param assetManager * @return forward framegraph @@ -62,24 +63,23 @@ public static FrameGraph forward(AssetManager assetManager) { fg.setName("Forward"); SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass(true, true)); - OutputRenderPass opaque = fg.add(new OutputRenderPass()); - OutputRenderPass sky = fg.add(new OutputRenderPass(DepthRange.REAR)); - OutputRenderPass transparent = fg.add(new OutputRenderPass()); - OutputRenderPass gui = fg.add(new OutputRenderPass(DepthRange.FRONT, false)); - OutputRenderPass translucent = fg.add(new OutputRenderPass()); - - opaque.makeInput(enqueue, "Opaque", "Geometry"); - sky.makeInput(enqueue, "Sky", "Geometry"); - transparent.makeInput(enqueue, "Transparent", "Geometry"); - gui.makeInput(enqueue, "Gui", "Geometry"); - translucent.makeInput(enqueue, "Translucent", "Geometry"); + QueueMergePass merge = fg.add(new QueueMergePass(5)); + OutputGeometryPass out = fg.add(new OutputGeometryPass()); + + merge.makeInput(enqueue, "Opaque", "Queues[0]"); + merge.makeInput(enqueue, "Sky", "Queues[1]"); + merge.makeInput(enqueue, "Transparent", "Queues[2]"); + merge.makeInput(enqueue, "Gui", "Queues[3]"); + merge.makeInput(enqueue, "Translucent", "Queues[4]"); + + out.makeInput(merge, "Result", "Geometry"); return fg; } /** - * Constructs a deferred or tiled deferred framegraph. + * Constructs a deferred FrameGraph. * * @param assetManager * @param tiled true to enable tiled lighting @@ -90,7 +90,7 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled) { } /** - * Constructs a deferred framegraph. + * Constructs a deferred FrameGraph. * * @param assetManager * @param tiled true to enable tiled lighting @@ -102,20 +102,19 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled, bool FrameGraph fg = new FrameGraph(assetManager); fg.setName(tiled ? "TiledDeferred" : "Deferred"); + int asyncThread = async ? 1 : FrameGraph.RENDER_THREAD; + SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass(true, true)); Attribute tileInfoAttr = fg.add(new Attribute()); Junction tileJunct1 = fg.add(new Junction(1, 1)); GBufferPass gbuf = fg.add(new GBufferPass()); - LightImagePass lightImg = fg.add(new LightImagePass(), - new PassIndex().setThreadIndex(async ? 1 : FrameGraph.RENDER_THREAD)); + LightImagePass lightImg = fg.add(new LightImagePass(), new PassIndex(asyncThread, -1)); Junction lightJunct = fg.add(new Junction(1, 6)); Junction tileJunct2 = fg.add(new Junction(1, 2)); DeferredPass deferred = fg.add(new DeferredPass()); OutputPass defOut = fg.add(new OutputPass(0f)); - OutputRenderPass sky = fg.add(new OutputRenderPass(DepthRange.REAR)); - OutputRenderPass transparent = fg.add(new OutputRenderPass()); - OutputRenderPass gui = fg.add(new OutputRenderPass(DepthRange.FRONT, false)); - OutputRenderPass translucent = fg.add(new OutputRenderPass()); + QueueMergePass merge = fg.add(new QueueMergePass(4), new PassIndex(asyncThread, -1)); + OutputGeometryPass geometry = fg.add(new OutputGeometryPass()); gbuf.makeInput(enqueue, "Opaque", "Geometry"); @@ -152,10 +151,12 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled, bool defOut.makeInput(deferred, "Color", "Color"); defOut.makeInput(gbuf, "GBufferData[4]", "Depth"); - sky.makeInput(enqueue, "Sky", "Geometry"); - transparent.makeInput(enqueue, "Transparent", "Geometry"); - gui.makeInput(enqueue, "Gui", "Geometry"); - translucent.makeInput(enqueue, "Translucent", "Geometry"); + merge.makeInput(enqueue, "Sky", "Queues[0]"); + merge.makeInput(enqueue, "Transparent", "Queues[1]"); + merge.makeInput(enqueue, "Gui", "Queues[2]"); + merge.makeInput(enqueue, "Translucent", "Queues[3]"); + + geometry.makeInput(merge, "Result", "Geometry"); return fg; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java index c791bf8a37..648ceac898 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FullScreenQuad.java @@ -34,7 +34,6 @@ import com.jme3.asset.AssetManager; import com.jme3.light.LightList; import com.jme3.material.Material; -import com.jme3.math.Vector2f; import com.jme3.renderer.RenderManager; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; @@ -43,7 +42,9 @@ import com.jme3.util.BufferUtils; /** - * A quad specifically for rendering fullscreen. + * Renders materials and textures on a static fullscreen quad geometry. + *

      + * Compatible with Filter shaders. * * @author codex */ @@ -120,14 +121,17 @@ public void render(RenderManager rm, Texture2D color, Texture2D depth) { transferMat.getAdditionalRenderState().setDepthTest(writeDepth); transferMat.getAdditionalRenderState().setDepthWrite(writeDepth); render(rm, transferMat); - setQuadScale(Vector2f.UNIT_XY); setAlphaDiscard(null); } } - public void setQuadScale(Vector2f scale) { - transferMat.setVector2("Scale", scale); - } + /** + * Sets the alpha discard threshold for next texture render. + *

      + * Fragments with alpha values below or equal to the threshold will be discarded. + * + * @param alphaDiscard + */ public void setAlphaDiscard(Float alphaDiscard) { if (alphaDiscard == null) { transferMat.clearParam("AlphaDiscard"); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java index 9eb127995c..c0c5145bd1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.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) 2024 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; @@ -14,7 +41,11 @@ import java.util.ArrayList; /** - * Holds a queue of geometries and an internal list of geometry queues. + * Queue of ordered geometries for rendering. + *

      + * Similar to {@link GeometryList}, but designed for use in FrameGraphs. Specifically, + * this can store other GeometryQueues internally, essentially making queues able + * to merge very quickly and still maintain geometry order. * * @author codex */ @@ -24,17 +55,25 @@ public class GeometryQueue { private Geometry[] geometries; private GeometryComparator comparator; + private Camera cam; private final ListSort listSort; private final ArrayList internalQueues = new ArrayList<>(); private final DepthRange depth = new DepthRange(); private boolean updateFlag = true; - private Camera cam; - private int size; private boolean perspective = true; - + private int size; + + /** + * Geometry queue with default settings and a {@link NullComparator}. + */ public GeometryQueue() { this(new NullComparator()); } + /** + * Geometry queue with default settings and the given comparator. + * + * @param comparator + */ public GeometryQueue(GeometryComparator comparator) { size = 0; geometries = new Geometry[DEFAULT_SIZE]; @@ -76,7 +115,7 @@ public void render(RenderManager renderManager, GeometryRenderHandler handler) { renderManager.setCamera(cam, true); } for (Geometry g : geometries) { - assert g != null; + if (g == null) continue; h.renderGeometry(renderManager, g); g.queueDistance = Float.NEGATIVE_INFINITY; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java index 1524838346..7e23f077e2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java @@ -1,13 +1,43 @@ /* - * 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) 2024 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; /** - * Holds indices to a render pass within a framegraph. + * Holds indices pointing to a render pass held within a framegraph. *

      - * Negative indices denote using defaults. + * The FrameGraph system uses indices to schedule resources, particularly + * with reservations. + *

      + * Negative indices denote using defaults assigned by the FrameGraph. * * @author codex */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java index d6c730a02c..0ee4bec444 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java @@ -1,6 +1,33 @@ /* - * 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 + * Copyright (c) 2024 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/PassThread.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.java index e760b428f2..d47b79cc83 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.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) 2024 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; @@ -20,7 +47,10 @@ import java.util.function.Function; /** - * + * A queue of RenderPasses executing on a particular thread. + *

      + * The primary PassThread runs on the main JME render thread. + * * @author codex */ public class PassThread implements Runnable, Iterable, Savable { @@ -37,9 +67,17 @@ public class PassThread implements Runnable, Iterable, Savable { private boolean async = false; private boolean interrupted = false; + /** + * Serialization only. + */ public PassThread() { frameGraph = null; } + /** + * + * @param frameGraph + * @param index + */ public PassThread(FrameGraph frameGraph, int index) { this.frameGraph = frameGraph; this.index = index; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderModule.java deleted file mode 100644 index 8ab9d35ab8..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderModule.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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 codex - */ -public class RenderModule { - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java index 2cfcbc9e90..a1b5ec8e8b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObject.java @@ -33,12 +33,11 @@ import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.util.NativeObject; -import java.util.Iterator; import java.util.LinkedList; import java.util.function.Consumer; /** - * Stores an object used for rendering. + * Handles a raw object used for rendering processes within a FrameGraph. * * @author codex * @param @@ -86,19 +85,54 @@ else if (object instanceof NativeObject) { } } + /** + * Starts an inspection of this object. + *

      + * This blocks other threads from inspecting this object at the same time. + * Often, other threads will save this object for later, and continue inspecting + * other objects in the meantime. + *

      + * Note that this is not a threadsafe operation, meaning some threads may "escape" + * this check. A synchronized block should be used to catch these exceptions. + * + * @see #endInspect() + */ public void startInspect() { inspect = true; } + /** + * Ends an inspection of this object. + * + * @see #startInspect() + */ public void endInspect() { inspect = false; } + /** + * Returns true if this object is currently being inspected. + * + * @return + */ public boolean isInspect() { return inspect; } + /** + * Marks this RenderObject as priorized, but not officially claimed, by a thread. + *

      + * This will block threads from attempting to reallocate this as an indirect + * resource. + * + * @param prioritized + */ public void setPrioritized(boolean prioritized) { this.prioritized = prioritized; } + /** + * Returns true if this RenderObject is prioritized. + * + * @return + */ public boolean isPrioritized() { return prioritized; } @@ -140,10 +174,10 @@ public void dispose() { } /** - * Returns true if + * Claims the reservation pertaining to the index. * * @param index - * @return + * @return true if a reservation was claimed. */ public boolean claimReservation(PassIndex index) { for (Reservation r : reservations) { @@ -152,10 +186,11 @@ public boolean claimReservation(PassIndex index) { return false; } /** - * Returns true if this render object is reserved within the time frame. + * Determine if reallocating this object with the context would + * result in a violation of a reservation. * * @param frame - * @return + * @return true if this object is reserved within the timeframe */ public boolean isReservedWithin(TimeFrame frame) { for (Reservation r : reservations) { @@ -171,16 +206,19 @@ public void clearReservations() { } /** - * Ticks down the timer tracking frames since last use. + * Decrements the integer tracking frames until the object is deemed + * abandoned. + *

      + * Abandoned objects are removed and disposed. * - * @return true if the timer has not expired + * @return true if the object is not considered abandoned */ public boolean tickTimeout() { return timeout-- > 0; } /** - * Sets this render object as constant, so that this cannot be reallocated. + * Sets this as constant, which blocks reallocations until the rendering ends. * * @param constant */ @@ -222,7 +260,7 @@ public boolean isConstant() { } /** - * Gets the next id. + * Gets the next unique id of RenderObjects. * * @return */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 078afac085..491708c6c9 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -34,7 +34,6 @@ import com.jme3.renderer.RenderManager; import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.definitions.ResourceDef; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; @@ -61,6 +60,11 @@ public class RenderObjectMap { private int totalObjects = 0; private int flushedObjects = 0; + /** + * + * @param renderManager + * @param async + */ public RenderObjectMap(RenderManager renderManager, boolean async) { this.renderManager = renderManager; objectMap = new ConcurrentHashMap<>(); @@ -79,20 +83,19 @@ private boolean isAvailable(RenderObject object) { } /** - * Allocates a render object to the resource. + * Allocates a render object to the ResourceView. *

      - * First, if this resource holds an object id, the corresponding render object, + * First, if this resource holds an object id, then corresponding render object, * if it still exists, will be tried for reallocation. If that fails, each render object * will be tried for reallocation. Finally, if that fails, a new render object * will be created and allocated to the resource. - *

      - * If this RenderObjectMap is asynchronous, this method is threadsafe. * * @param * @param resource - * @param async true to execute asynchronous methods + * @param async true to execute asynchronous methods, otherwise synchronous methods will + * be used in the interest of efficiency */ - public void allocate(RenderResource resource, boolean async) { + public void allocate(ResourceView resource, boolean async) { if (async) { allocateAsync(resource); } else { @@ -100,7 +103,7 @@ public void allocate(RenderResource resource, boolean async) { } } - private void allocateSync(RenderResource resource) { + private void allocateSync(ResourceView resource) { if (resource.isUndefined()) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); } @@ -150,7 +153,7 @@ private void allocateSync(RenderResource resource) { resource.getIndex(), resource.getResource().getClass().getSimpleName()); objectsCreated++; } - private boolean allocateSpecificSync(RenderResource resource) { + private boolean allocateSpecificSync(ResourceView resource) { GraphEventCapture cap = renderManager.getGraphCapture(); ResourceDef def = resource.getDefinition(); long id = resource.getTicket().getObjectId(); @@ -179,7 +182,7 @@ private boolean allocateSpecificSync(RenderResource resource) { failedReservations++; return false; } - private void allocateAsync(RenderResource resource) { + private void allocateAsync(ResourceView resource) { if (resource.isUndefined()) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); } @@ -271,7 +274,7 @@ private void allocateAsync(RenderResource resource) { resource.getIndex(), resource.getResource().getClass().getSimpleName()); objectsCreated++; } - private boolean allocateSpecificAsync(RenderResource resource) { + private boolean allocateSpecificAsync(ResourceView resource) { GraphEventCapture cap = renderManager.getGraphCapture(); ResourceDef def = resource.getDefinition(); long id = resource.getTicket().getObjectId(); @@ -308,12 +311,15 @@ private boolean allocateSpecificAsync(RenderResource resource) { /** * Makes a reservation of render object holding the specified id at the render - * pass index so that no other resource may (without a reservation) use that - * render object at that time. + * pass index. + *

      + * A reservation blocks other reallocation requests for the remainder of the frame. + * It is not strictly guaranteed to block all other requests, so it is not considered + * good practice to rely on a reservation blocking all such requests. * - * @param objectId - * @param index - * @return + * @param objectId id of the object to reserve + * @param index index to reserve the object at + * @return true if the referenced object exists */ public boolean reserve(long objectId, PassIndex index) { RenderObject obj = objectMap.get(objectId); @@ -328,11 +334,11 @@ public boolean reserve(long objectId, PassIndex index) { return false; } /** - * Disposes the render object pointed to by the resource. + * Disposes the render object pointed to by the ResourceView's internal ticket. * * @param resource */ - public void dispose(RenderResource resource) { + public void dispose(ResourceView resource) { long id = resource.getTicket().getObjectId(); if (id >= 0) { RenderObject obj = objectMap.remove(id); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index 44869fd43c..ca6f7f7865 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -41,36 +41,44 @@ import java.util.concurrent.TimeoutException; /** - * Manages render resource declarations, references, and releases for a framegraph. + * Manages {@link ResourceView} declarations, references, and + * releases for a single framegraph. * * @author codex */ public class ResourceList { - + + /** + * Initial size of the resource ArrayList. + */ private static final int INITIAL_SIZE = 20; private final FrameGraph frameGraph; private RenderManager renderManager; private RenderObjectMap map; private GraphEventCapture cap; - private ArrayList resources = new ArrayList<>(INITIAL_SIZE); + private ArrayList resources = new ArrayList<>(INITIAL_SIZE); private final LinkedList futureRefs = new LinkedList<>(); private int nextSlot = 0; private int textureBinds = 0; - + + /** + * + * @param frameGraph + */ public ResourceList(FrameGraph frameGraph) { this.frameGraph = frameGraph; } - private RenderResource create(ResourceProducer producer, ResourceDef def) { - RenderResource res = new RenderResource<>(producer, def, new ResourceTicket<>()); + private ResourceView create(ResourceProducer producer, ResourceDef def) { + ResourceView res = new ResourceView<>(producer, def, new ResourceTicket<>()); res.getTicket().setLocalIndex(add(res)); return res; } - private RenderResource locate(ResourceTicket ticket) { + private ResourceView locate(ResourceTicket ticket) { return locate(ticket, true); } - private RenderResource locate(ResourceTicket ticket, boolean failOnMiss) { + private ResourceView locate(ResourceTicket ticket, boolean failOnMiss) { if (ticket == null) { if (failOnMiss) { throw new NullPointerException("Ticket cannot be null."); @@ -85,7 +93,7 @@ private RenderResource locate(ResourceTicket ticket, boolean failOnMis return null; } if (i < resources.size()) { - RenderResource res = resources.get(i); + ResourceView res = resources.get(i); if (res != null) { return res; } @@ -98,10 +106,10 @@ private RenderResource locate(ResourceTicket ticket, boolean failOnMis } return null; } - private RenderResource fastLocate(ResourceTicket ticket) { + private ResourceView fastLocate(ResourceTicket ticket) { return resources.get(ticket.getWorldIndex()); } - private int add(RenderResource res) { + private int add(ResourceView res) { assert res != null; if (nextSlot >= resources.size()) { // addUserEvent resource to end of list @@ -121,8 +129,8 @@ private int add(RenderResource res) { return i; } } - private RenderResource remove(int index) { - RenderResource prev = resources.set(index, null); + private ResourceView remove(int index) { + ResourceView prev = resources.set(index, null); if (prev != null && prev.isReferenced()) { throw new IllegalStateException("Cannot remove "+prev+" because it is referenced."); } @@ -152,7 +160,7 @@ public boolean validate(ResourceTicket ticket) { * @return */ public ResourceTicket declare(ResourceProducer producer, ResourceDef def, ResourceTicket store) { - RenderResource resource = create(producer, def); + ResourceView resource = create(producer, def); if (cap != null) cap.declareResource(resource.getIndex(), (store != null ? store.getName() : "")); return resource.getTicket().copyIndexTo(store); } @@ -175,10 +183,11 @@ public void reserve(PassIndex passIndex, ResourceTicket ticket) { } /** - * Makes reservations for each given ticket. + * Makes reservations at the index for each {@link RenderObject} referenced by the tickets. * * @param passIndex * @param tickets + * @see RenderObjectMap#reserve(long, com.jme3.renderer.framegraph.PassIndex) */ public void reserve(PassIndex passIndex, ResourceTicket... tickets) { for (ResourceTicket t : tickets) { @@ -187,7 +196,7 @@ public void reserve(PassIndex passIndex, ResourceTicket... tickets) { } private void reference(PassIndex passIndex, ResourceTicket ticket, boolean optional) { - RenderResource resource = locate(ticket, false); + ResourceView resource = locate(ticket, false); if (resource != null) { resource.reference(passIndex); if (cap != null) cap.referenceResource(resource.getIndex(), ticket.getName()); @@ -273,7 +282,7 @@ public > R getDefinition(Class type, ResourceTick * @param ticket */ public void setUndefined(ResourceTicket ticket) { - RenderResource resource = locate(ticket); + ResourceView resource = locate(ticket); resource.setUndefined(); if (cap != null) cap.setResourceUndefined(resource.getIndex(), ticket.getName()); } @@ -355,7 +364,7 @@ public void wait(ResourceTicket ticket, int thread, long timeoutMillis, int atte } // wait for resource to become available to this context long start = System.currentTimeMillis(); - RenderResource res; + ResourceView res; // TODO: determine why not locating the resource on each try results in timeouts. while (!(res = fastLocate(ticket)).isReadAvailable()) { if (System.currentTimeMillis()-start >= timeoutMillis) { @@ -397,7 +406,7 @@ public boolean isAsync(ResourceTicket ticket) { * @param ticket * @return */ - protected T acquire(RenderResource resource, ResourceTicket ticket) { + protected T acquire(ResourceView resource, ResourceTicket ticket) { if (!resource.isUsed()) { throw new IllegalStateException(resource+" was unexpectedly acquired."); } @@ -420,7 +429,7 @@ protected T acquire(RenderResource resource, ResourceTicket ticket) { * @return */ public T acquire(ResourceTicket ticket) { - RenderResource resource = locate(ticket); + ResourceView resource = locate(ticket); if (resource.isUndefined()) { throw new NullPointerException("Cannot acquire undefined resource."); } @@ -435,12 +444,12 @@ public T acquire(ResourceTicket ticket) { * * @param * @param ticket - * @param value default value + * @param value default value (may be null) * @return */ public T acquireOrElse(ResourceTicket ticket, T value) { if (validate(ticket)) { - RenderResource resource = locate(ticket); + ResourceView resource = locate(ticket); if (!resource.isUndefined()) { return acquire(resource, ticket); } @@ -589,7 +598,7 @@ public void setPrimitive(ResourceTicket ticket, T value) { * @param ticket */ public void release(ResourceTicket ticket) { - RenderResource resource = locate(ticket); + ResourceView resource = locate(ticket); if (cap != null) cap.releaseResource(resource.getIndex(), ticket.getName()); if (!resource.release()) { if (cap != null && resource.getObject() != null) { @@ -675,13 +684,13 @@ public void applyFutureReferences() { * references, and prior to execution. */ public void cullUnreferenced() { - LinkedList cull = new LinkedList<>(); - for (RenderResource r : resources) { + LinkedList cull = new LinkedList<>(); + for (ResourceView r : resources) { if (r != null && !r.isReferenced() && !r.isSurvivesRefCull()) { cull.add(r); } } - RenderResource resource; + ResourceView resource; while ((resource = cull.pollFirst()) != null) { // dereference producer of resource ResourceProducer producer = resource.getProducer(); @@ -695,7 +704,7 @@ public void cullUnreferenced() { if (!validate(t)) { continue; } - RenderResource r = locate(t); + ResourceView r = locate(t); r.release(); if (!r.isReferenced()) { cull.addLast(r); @@ -745,9 +754,7 @@ public void setRenderManager(RenderManager renderManager) { } /** - * Represents a reference that is made in the future. - *

      - * Used primarily with asynchronous framegraphs. + * Represents a reference to a resource that will exist in the future. */ private static class FutureReference { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java index 7637a849c0..a955ce3e33 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java @@ -53,6 +53,7 @@ public interface ResourceProducer { * @return */ public boolean dereference(); + /** * Returns true if this producer is used. * @@ -66,6 +67,7 @@ public interface ResourceProducer { * @return */ public Collection getInputTickets(); + /** * Gets a collection of all output tickets. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index 6dda9badd6..c7f01e64ba 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -34,11 +34,10 @@ /** * References a {@link RenderResource} by index. *

      - * A ticket can be set as another tickets source, in which case the former inherits - * the resource index of the latter. - *

      - * Tickets can also vaguely point to the last known render object, which is used - * to prioritize that render object, especially for reservations. + * Can reference another ticket as a source, which makes this point to the same + * resource as the source ticket. This mechanism allows RenderPasses to share + * resources. Also vaguely tracks the last seen render object, which is used to + * prioritize that render object, especially for reservations. * * @author codex * @param diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceView.java similarity index 95% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceView.java index fe09ddf8ca..bdb7aa8301 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderResource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceView.java @@ -37,11 +37,15 @@ /** * Represents an existing or future resource used for rendering. + *

      + * Unlike {@link RenderObject}, this is only loosely connected to a raw + * rendering resource. In fact, the creation of a ResourceView does not + * necessarily predict the creation of a raw resource, due to culling. * * @author codex * @param */ -public class RenderResource { +public class ResourceView { private final ResourceProducer producer; private final ResourceDef def; @@ -59,9 +63,8 @@ public class RenderResource { * @param producer * @param def * @param ticket - * @param async */ - public RenderResource(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { + public ResourceView(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { this.producer = producer; this.def = def; this.ticket = ticket; @@ -133,7 +136,7 @@ public void setObject(RenderObject object, T resource) { ticket.setObjectId(this.object.getId()); } /** - * Directly sets the concrete resource held by this render resource. + * Directly sets the raw resource held by this render resource. * * @param resource */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java index 6ea12fb753..454dbd8a66 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java @@ -39,7 +39,7 @@ import java.io.IOException; /** - * Represents an abstract connection between render passes that can be saved. + * Represents a connection of tickets between render passes. * * @author codex */ @@ -49,7 +49,7 @@ public class SavablePassConnection implements Savable { private String inputTicket, outputTicket; /** - * + * Serialization only. */ public SavablePassConnection() {} /** @@ -67,6 +67,7 @@ public SavablePassConnection(int inputId, int outputId, String inputTicket, Stri } /** + * Shifts the input and output pass ids. * * @param shift */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java index 8238cc293b..a50fe49fff 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TimeFrame.java @@ -35,7 +35,11 @@ * Represents a period of time starting at the start of the indexed pass, and * lasting for the duration of a number of following passes. *

      - * An asynchronous timeframe indicates that the end is unpredictable. + * Used primarily to track the lifetime of ResourceViews, which is then used + * to determine if a ResourceView violates any reservations. + *

      + * This would rather overestimate that underestimate, so asynchronous resources + * are tracked as surviving from first inception to frame end. * * @author codex */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java index 9511696270..9fab8efc9c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.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) 2024 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.client; @@ -14,7 +41,8 @@ import java.io.IOException; /** - * + * Shares settings from the FrameGraph settings map with the FrameGraph. + * * @author codex * @param */ @@ -23,23 +51,31 @@ public class GraphSetting implements GraphSource, GraphTarget, Savable private String name; private ViewPortFilter filter; + /** + * Serialization only. + */ public GraphSetting() { this(""); } + /** + * Graph setting that interacts with the named setting. + * + * @param name + */ public GraphSetting(String name) { this.name = name; } @Override public T getGraphValue(FrameGraph frameGraph, ViewPort viewPort) { - if (filter == null || filter.confirm(viewPort)) { + if (filter == null || filter.accept(viewPort)) { return frameGraph.getSetting(name); } return null; } @Override public boolean setGraphValue(FrameGraph frameGraph, ViewPort viewPort, T value) { - if (filter == null || filter.confirm(viewPort)) { + if (filter == null || filter.accept(viewPort)) { frameGraph.setSetting(name, value); return true; } @@ -60,13 +96,32 @@ public void read(JmeImporter im) throws IOException { filter = (ViewPortFilter)in.readSavable("filter", new DefaultSavableFilter()); } + /** + * Sets the viewport filter. + *

      + * Rejected viewports are not able to change or read from the settings map via + * this object. + * + * @param filter + */ public void setFilter(ViewPortFilter filter) { this.filter = filter; } + /** + * Gets the name of the setting this interacts with. + * + * @return + */ public String getName() { return name; } + + /** + * Gets the viewport filter. + * + * @return + */ public ViewPortFilter getFilter() { return filter; } @@ -74,7 +129,7 @@ public ViewPortFilter getFilter() { public static class DefaultSavableFilter implements ViewPortFilter, Savable { @Override - public boolean confirm(ViewPort vp) { + public boolean accept(ViewPort vp) { return true; } @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java index 25dd46dffe..7ea188d1d6 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSource.java @@ -35,7 +35,7 @@ import com.jme3.renderer.framegraph.FrameGraph; /** - * Provides values to a framegraph from game logic. + * Provides values to a FrameGraph from game logic. * * @author codex * @param @@ -51,4 +51,34 @@ public interface GraphSource { */ public T getGraphValue(FrameGraph frameGraph, ViewPort viewPort); + /** + * Returns the value from provided by the GraphSource. + *

      + * If the source is null, the default value will be returned instead. + * + * @param + * @param source graph source + * @param defValue default value (used if graph source is null) + * @param frameGraph framegraph + * @param viewPort viewport + * @return value from source (or default value if source is null) + */ + public static T get(GraphSource source, T defValue, FrameGraph frameGraph, ViewPort viewPort) { + if (source != null) { + return source.getGraphValue(frameGraph, viewPort); + } + return defValue; + } + + /** + * Returns a source that returns the given value. + * + * @param + * @param value + * @return + */ + public static GraphValue value(T value) { + return new GraphValue<>(value); + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java index 67285ae13d..2d4089b4bf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphTarget.java @@ -43,12 +43,13 @@ public interface GraphTarget { /** - * Sets the value recieved from the framegraph. + * Recieves a value from the FrameGraph. * - * @param frameGraph framegraph currently rendering + * @param frameGraph FrameGraph currently rendering * @param viewPort viewport currently being rendered * @param value value from framegraph - * @return true if value is used + * @return true if value is used, which may affect how resources are + * handled by the FrameGraph internally */ public boolean setGraphValue(FrameGraph frameGraph, ViewPort viewPort, T value); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphValue.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphValue.java new file mode 100644 index 0000000000..5688e852b6 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphValue.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 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.client; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.export.SavableObject; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FrameGraph; +import java.io.IOException; + +/** + * Implementation of GraphSource and GraphTarget that manages a value. + * + * @author codex + * @param + */ +public class GraphValue implements GraphSource, GraphTarget, Savable { + + private T value; + + public GraphValue() {} + public GraphValue(T value) { + this.value = value; + } + + @Override + public T getGraphValue(FrameGraph frameGraph, ViewPort viewPort) { + return value; + } + @Override + public boolean setGraphValue(FrameGraph frameGraph, ViewPort viewPort, T value) { + this.value = value; + return true; + } + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(new SavableObject(value), "value", SavableObject.NULL); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + value = (T)in.readSavableObject("value", SavableObject.NULL).getObject(); + } + + /** + * Sets the held value. + *

      + * Subject to change if values are being recieved from the FrameGraph. + * + * @param value + */ + public void setValue(T value) { + this.value = value; + } + + /** + * Gets the held value. + * + * @return + */ + public T getValue() { + return value; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java index 10b89167f6..3986dc2d58 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/MatParamTargetControl.java @@ -42,7 +42,10 @@ import com.jme3.shader.VarType; /** - * Controls a material parameter based on values provided by a framegraph. + * Applies values from a FrameGraph to a material parameter. + *

      + * The target material is the first located material in the controlled spatial's + * hierarchy, however, this is mainly intended to control geometries. * * @author codex * @param @@ -103,13 +106,36 @@ private boolean containsViewPort(ViewPort vp) { return false; } + /** + * Registers the ViewPorts that are able to affect the internal value. + *

      + * ViewPorts not included in the array cannot affect the internal value. + * + * @param viewPorts + */ public void setViewPorts(ViewPort... viewPorts) { this.viewPorts = viewPorts; } + /** + * Sets the ViewPort filter to allow ViewPorts to affect the internal value. + */ + public void includeAllViewPorts() { + viewPorts = null; + } + /** + * Gets the internal value. + * + * @return + */ public T getValue() { return value; } + /** + * Gets the array of ViewPorts that are able to affect the internal value. + * + * @return array of ViewPorts, or null if all ViewPorts are accepted + */ public ViewPort[] getViewPorts() { return viewPorts; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/ViewPortFilter.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/ViewPortFilter.java index 8598484925..8184897b6b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/ViewPortFilter.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/ViewPortFilter.java @@ -1,17 +1,59 @@ /* - * 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) 2024 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.client; import com.jme3.renderer.ViewPort; /** - * + * Filter that accepts or denies ViewPorts. + *

      + * Used primarily by {@link GraphSource} and {@link GraphTarget} implementation + * that only function for certain registered ViewPorts. + * * @author codex */ public interface ViewPortFilter { - public boolean confirm(ViewPort vp); + /** + * Filter that accepts all viewports. + */ + public static final ViewPortFilter ANY = vp -> true; + + /** + * Returns true if the viewport is accepted by this filter. + * + * @param vp + * @return + */ + public boolean accept(ViewPort vp); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java index b9ba7527b0..47b32bdc4a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java @@ -1,14 +1,39 @@ /* - * 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) 2024 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.debug; import com.jme3.renderer.Camera; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.PassIndex; -import com.jme3.renderer.framegraph.RenderObject; -import com.jme3.renderer.framegraph.RenderResource; import com.jme3.texture.FrameBuffer; import java.io.File; import java.io.FileWriter; @@ -17,7 +42,11 @@ import java.util.function.Supplier; /** - * + * Logs a list of FrameGraph events that occures over a number of frames. + *

      + * Event logs can be written to a file, so that it can be analyzed by external + * programs. + * * @author codex */ public class GraphEventCapture { @@ -27,7 +56,12 @@ public class GraphEventCapture { private int frame = 0; private boolean includeNanos = true; private long userNanos = 0; - + + /** + * Graph event capture that exports the the file. + * + * @param target + */ public GraphEventCapture(File target) { this.target = target; } @@ -35,101 +69,256 @@ public GraphEventCapture(File target) { private void add(Event c) { events.addLast(c); } + /** + * Adds an event triggered by the user. + * + * @param operation + * @param arguments + */ public void addUserEvent(String operation, Object... arguments) { add(new Event("USEREVENT", operation, arguments)); } + /** + * Logs the object. + *

      + * Changes to object afterward affect this. + * + * @param name + * @param value + */ public void value(String name, Object value) { add(new Value(name, value)); } + /** + * Logs a render frame start event. + */ public void startRenderFrame() { add(new Event("SUPEREVENT", "StartRenderFrame", frame)); } + /** + * Logs a render frame end event. + */ public void endRenderFrame() { add(new Event("SUPEREVENT", "EndRenderFrame", frame++)); } + /** + * Logs a viewport render event. + * + * @param vp + */ public void renderViewPort(ViewPort vp) { Camera cam = vp.getCamera(); add(new Event("SUPEREVENT", "StartViewPort", vp.getName(), cam.getWidth(), cam.getHeight())); } + /** + * Logs a RenderPass preperation event. + * + * @param index + * @param name + */ public void prepareRenderPass(PassIndex index, String name) { - events.add(new Event("PrepareRenderPass", index, name)); - } + events.add(new Event("PrepareRenderPass", index.clone(), name)); + } + /** + * Logs a RenderPass execution event. + * + * @param index + * @param name + */ public void executeRenderPass(PassIndex index, String name) { - add(new Event("ExecuteRenderPass", index, name)); + add(new Event("ExecuteRenderPass", index.clone(), name)); } + /** + * Logs a FrameBuffer creation event. + * + * @param fb + */ public void createFrameBuffer(FrameBuffer fb) { add(new Event("CreateFrameBuffer", fb.getWidth(), fb.getHeight(), fb.getSamples())); } + /** + * Logs a ResourceView declaration event. + * + * @param index + * @param ticket + */ public void declareResource(int index, String ticket) { add(new Event("DeclareResource", index, ticket)); } + /** + * Logs a ResourceView reference event. + * + * @param index + * @param ticket + */ public void referenceResource(int index, String ticket) { add(new Event("ReferenceResource", index, ticket)); } + /** + * Logs a resource acquire event. + * + * @param index + * @param ticket + */ public void acquireResource(int index, String ticket) { add(new Event("AcquireResource", index, ticket)); } + /** + * Logs an event in which a ResourceView is marked as undefined. + * + * @param index + * @param ticket + */ public void setResourceUndefined(int index, String ticket) { add(new Event("SetResourceUndefined", index, ticket)); } + /** + * Logs a ResourceView release event. + * + * @param index + * @param ticket + */ public void releaseResource(int index, String ticket) { add(new Event("ReleaseResource", index, ticket)); } + /** + * Logs a ResourceView clearing event. + * + * @param size number of resources cleared + */ public void clearResources(int size) { add(new Event("ClearResources", size)); } + /** + * Logs a texture bind event. + * + * @param index + * @param ticket + */ public void bindTexture(int index, String ticket) { add(new Event("BindTexture", index, ticket)); } + /** + * Logs a RenderObject reservation event. + * + * @param id + * @param index + */ public void reserveObject(long id, PassIndex index) { - add(new Event("ReserveObject", id, index)); - } + add(new Event("ReserveObject", id, index.clone())); + } + /** + * Logs a ResourceObject creation event. + * + * @param id + * @param index + * @param type + */ public void createObject(long id, int index, String type) { add(new Event("CreateObject", id, index, type)); } - public void setObjectDirect(long id, int index, String type) { - add(new Event("SetObjectDirect", id, index, type)); - } + /** + * Logs a RenderObject reallocation event. + * + * @param id + * @param index + * @param type + */ public void reallocateObject(long id, int index, String type) { add(new Event("ReallocateObject", id, index, type)); } + /** + * Logs an attempt at reallocating a specific RenderObject. + * + * @param id + * @param index + */ public void attemptReallocation(long id, int index) { add(new Event("AttemptSpecificReallocation", id, index)); } + /** + * Logs an event in which a RenderObject is marked as constant. + * + * @param id + */ public void setObjectConstant(long id) { add(new Event("SetObjectConstant", id)); } + /** + * Logs a RenderObject release event. + * + * @param id + */ public void releaseObject(long id) { add(new Event("ReleaseObject", id)); } + /** + * Logs a RenderObject dispose event. + * + * @param id + */ public void disposeObject(long id) { add(new Event("DisposeObject", id)); } + /** + * Logs an event in which RenderObjectMap is flushed. + * + * @param size number of RenderObjects in the map. + */ public void flushObjects(int size) { add(new Event("FlushObjects", size)); } + /** + * Begins a nanos count. + * + * @param subject + */ public void startNanos(String subject) { userNanos = System.nanoTime(); add(new Event("PROFILE", "StartNanos", subject)); } + /** + * Marks the beginning and end of a nanos "lap". + * + * @param subject + * @return + */ public long lapNanos(String subject) { return breakNanos(subject, subject); } + /** + * Ends the current nanos count and begins a new nanos count. + * + * @param endSubject + * @param startSubject + * @return + */ public long breakNanos(String endSubject, String startSubject) { long duration = endNanos(endSubject); startNanos(startSubject); return duration; } + /** + * Ends the current nanos count. + * + * @param subject + * @return + */ public long endNanos(String subject) { long duration = Math.abs(System.nanoTime()-userNanos); add(new Event("PROFILE", "EndNanos", subject, duration+"ns", (duration/1000000)+"ms")); return duration; } + /** + * Exports the current event log to this capture's target file. + * + * @throws IOException + */ public void export() throws IOException { if (target.exists()) { target.delete(); @@ -144,9 +333,19 @@ public void export() throws IOException { writer.close(); } + /** + * Set the export file to include nanos with each event. + * + * @param includeNanos + */ public void setIncludeNanos(boolean includeNanos) { this.includeNanos = includeNanos; } + + /** + * + * @return + */ public boolean isIncludeNanos() { return includeNanos; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java index 29bebb8969..2dbc372d02 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/AbstractResourceDef.java @@ -34,7 +34,8 @@ import java.util.function.Consumer; /** - * + * Abstract implementation of ResourceDef. + * * @author codex * @param */ @@ -72,7 +73,7 @@ public boolean isReadConcurrent() { } /** - * Sets the consumer responsible for disposing the resource. + * Sets the Consumer responsible for disposing the resource. *

      * default=null * @@ -86,7 +87,9 @@ public void setDisposalMethod(Consumer disposalMethod) { * Sets the number of frames the resource can be static before being * disposed. *

      - * If less than zero, the default value will be used instead. + * If less than zero, the default value provided by + * {@link com.jme3.renderer.framegraph.RenderObjectMap RenderObjectMap} will + * be used instead. * * @param staticTimout */ @@ -95,7 +98,7 @@ public void setStaticTimeout(int staticTimout) { } /** - * Sets this definition to allow for use of reallocated objects. + * Allows for reallocation of existing resources. *

      * default=true * @@ -106,7 +109,7 @@ public void setUseExisting(boolean useExisting) { } /** - * Sets the resource to be disposed when it is unused. + * Sets the resource to be disposed when it is first unused. *

      * default=false * @@ -118,6 +121,8 @@ public void setDisposeOnRelease(boolean disposeOnRelease) { /** * Sets the resource as able to be read concurrently. + *

      + * default=true * * @param readConcurrent */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java index 2f91e6dcf7..2df32d21b7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/ResourceDef.java @@ -32,10 +32,11 @@ package com.jme3.renderer.framegraph.definitions; import java.util.function.Consumer; +import com.jme3.renderer.framegraph.ResourceView; /** - * Creates and reallocates objects for a resource and defines how that resource - * will behaves. + * Manages the behavior of a {@link ResourceView}, especially for creation, + * reallocation, and disposal of related raw resources. * * @author codex * @param @@ -50,20 +51,24 @@ public interface ResourceDef { public T createResource(); /** - * Repurposes the given resource only if the resource is of - * a certain type. + * Checks if the resource can be directly allocated to this definition's + * {@link ResourceView} as is. *

      - * For reallocation, direct resources are preferred over indirect - * resources. Usually because direct resources require fewer changes - * to be usable. + * For reallocation, direct "as is" resources are preferred over indirect + * resources. Usually because direct resources are specifically designed + * for whatever task. * * @param resource - * @return + * @return the resource if approved, otherwise null */ public T applyDirectResource(Object resource); /** - * Repurposes the given resource. + * Repurposes the given resource for allocation to this definition's + * {@link ResourceView}. + *

      + * An indirect resource usually does not exactly match the type of this + * definition, but does contain the necessary components. * * @param resource * @return repurposed resource, or null if the given resource is not usable. diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java index 5dde5bd00c..82ee5eafe5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/definitions/TextureDef.java @@ -35,7 +35,6 @@ import com.jme3.texture.Texture; import com.jme3.texture.Texture2D; import com.jme3.texture.Texture3D; -import com.jme3.texture.TextureArray; import com.jme3.texture.image.ColorSpace; import java.util.ArrayList; import java.util.Objects; @@ -45,8 +44,8 @@ /** * General resource definition for textures. *

      - * Other textures and objects only apply for reallocation if a contained - * image meets the parameters of this definition. + * Able to indirectly reallocate any object that contains a locatable {@link Image} that + * matches the properties given in this definition. * * @author codex * @param @@ -200,7 +199,7 @@ public void setTextureBuilder(Function textureBuilder) { this.textureBuilder = textureBuilder; } /** - * Sets the function that extracts an Image from and object. + * Sets the function that extracts an Image from an object. * * @param imageExtractor */ @@ -327,8 +326,8 @@ public void setFormat(Image.Format format) { this.format = format; } /** - * Sets reallocation so that the target image does not need the exact - * format of the definition. + * Sets reallocation so that the target image only needs to have the same + * format type (color versus depth) as this definition. *

      * default=false * @@ -362,8 +361,8 @@ public void setMinFilter(Texture.MinFilter minFilter) { this.minFilter = minFilter; } /** - * Sets reallocation so that the target image does not need the exact - * format of the definition. + * Sets reallocation so that the target image does not need the same + * color space as this definition. * * @param colorSpaceFlexible */ @@ -508,9 +507,19 @@ public Texture.WrapMode getWrap(Texture.WrapAxis axis) { } } + /** + * Creates a general-purpose definition for {@link Texture2D}s. + * + * @return + */ public static TextureDef texture2D() { return new TextureDef<>(Texture2D.class, TEXTURE_2D); } + /** + * Creates a general-purpose definition for {@link Texture3D}s. + * + * @return + */ public static TextureDef texture3D() { return new TextureDef<>(Texture3D.class, TEXTURE_3D); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/filters/SoftBloomPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/filters/SoftBloomPass.java deleted file mode 100644 index c73b9dff3e..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/filters/SoftBloomPass.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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.filters; - -/** - * - * @author codex - */ -public class SoftBloomPass { - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java index 3cbc2c1ece..11ecac19c2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightFrustum.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) 2024 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.light; @@ -17,7 +44,8 @@ import java.util.LinkedList; /** - * + * A screenspace rectangle that contains a light's influence. + * * @author codex */ public class LightFrustum { @@ -42,6 +70,12 @@ public class LightFrustum { private final Vector4f lightCenter = new Vector4f(); private boolean fullscreen = false; + /** + * Calculates important values from the camera. + * + * @param cam + * @return + */ public LightFrustum calculateCamera(Camera cam) { viewPortWidth = cam.getWidth() * 0.5f; viewPortHeight = cam.getHeight() * 0.5f; @@ -57,6 +91,12 @@ public LightFrustum calculateCamera(Camera cam) { return this; } + /** + * Calculates the frustum from the light. + * + * @param l + * @return + */ public LightFrustum fromLight(Light l) { switch (l.getType()) { case Directional: @@ -71,9 +111,21 @@ public LightFrustum fromLight(Light l) { throw new UnsupportedOperationException("Light type "+l.getType()+" is not supported."); } } + /** + * Calculates the frustum from the DirectionalLight. + * + * @param dl + * @return + */ public LightFrustum fromDirectional(DirectionalLight dl) { return fullscreen(); } + /** + * Calculates the frustum from the point light. + * + * @param pl + * @return + */ public LightFrustum fromPoint(PointLight pl) { //return fullscreen(); @@ -140,12 +192,29 @@ public LightFrustum fromPoint(PointLight pl) { return this; } + /** + * Calculates the frustum from the SpotLight. + * + * @param sl + * @return + */ public LightFrustum fromSpot(SpotLight sl) { return fullscreen(); } + /** + * Calculates the frustum from the AmbientLight. + * + * @param al + * @return + */ public LightFrustum fromAmbient(AmbientLight al) { return fullscreen(); } + /** + * Calculates a fullscreen frustum. + * + * @return + */ public LightFrustum fullscreen() { fullscreen = true; left = bottom = 0; @@ -154,6 +223,13 @@ public LightFrustum fullscreen() { return this; } + /** + * Writes the calculated frustum of the indexed light to a set of screenspace tiles. + * + * @param tileIndices 2D lists containing light indices for each tile + * @param tileInfo information about tile demensions + * @param lightIndex index of light + */ public void write(ArrayList> tileIndices, TiledRenderGrid tileInfo, int lightIndex) { if (!fullscreen) { int width = tileInfo.getGridWidth(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java index b784744e3b..ed3fb82cd8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/LightImagePacker.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) 2024 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.light; @@ -21,7 +48,8 @@ import java.util.List; /** - * + * Rasters light info to a set of textures. + * * @author codex */ public class LightImagePacker { @@ -35,6 +63,15 @@ public class LightImagePacker { public LightImagePacker() {} + /** + * Sets the textures to raster light information to. + * + * @param tex1 texture to contain light color and type + * @param tex2 texture to contain light position/direction and coefficients + * @param tex3 texture to contain spot coefficients + * @param tiles texture to contain start indices for each tile (or null to not calculate tiles) + * @param indices texture to contain light indices referenced by tiles (or null to not calculate tiles) + */ public void setTextures(Texture2D tex1, Texture2D tex2, Texture2D tex3, Texture2D tiles, Texture2D indices) { validateSize(tex1, tex2); validateSize(tex1, tex3); @@ -44,13 +81,34 @@ public void setTextures(Texture2D tex1, Texture2D tex2, Texture2D tex3, Texture2 updateTexture(3, tiles); updateTexture(4, indices); } + /** + * Gets the array of textures to raster to. + * + * @return + */ public Texture2D[] getTextures() { return textures; } + /** + * Gets the texture at the index. + * + * @param i + * @return + */ public Texture2D getTexture(int i) { return textures[i]; } + /** + * Rasters the lights in the LightList into the current textures. + * + * @param lights lights to pack + * @param ambient stores the accumulated ambient light + * @param probes stores all LightProbes + * @param cam camera for tile calculations + * @param tileInfo tile demensions for tile calculations + * @return number of directional, point, and spot lights + */ public int packLights(LightList lights, ColorRGBA ambient, List probes, Camera cam, TiledRenderGrid tileInfo) { ambient.set(0, 0, 0, 0); @@ -143,7 +201,6 @@ private void packLightIndices() { int tileX = 0, tileY = 0; final int indexWidth = textures[4].getImage().getWidth(); final int tileWidth = textures[3].getImage().getWidth(); - final int tileHeight = textures[3].getImage().getHeight(); final ColorRGBA tileInfoColor = new ColorRGBA(); tempColor.set(0, 0, 0, 0); for (LinkedList l : tileIndices) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java index 29a2e48fbd..5916f47ebe 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/light/TiledRenderGrid.java @@ -40,8 +40,10 @@ import java.io.IOException; /** - * - * @author codex + * Calculates screenspace tile demensions for rendering + * techniques such as tiled deferred. + * + * @author johnkkk, codex */ public class TiledRenderGrid implements Savable { @@ -50,7 +52,7 @@ public class TiledRenderGrid implements Savable { private int tileSize = 0; private int gridWidth = 0; private int gridHeight = 0; - + public TiledRenderGrid() {} public TiledRenderGrid(int divisions) { this.divisions = divisions; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java index 160883689b..9158d226e2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Attribute.java @@ -53,6 +53,15 @@ *

      * Objects handled by this pass are automatically marked as constant, so that future changes * do not taint the game logic's resource view. + *

      + * Inputs: + *

        + *
      • {@link #INPUT} ({@link Object}): the value to share with game logic via registered GraphTargets (optional).
      • + *
      + * Outputs: + *
        + *
      • {@link #OUTPUT} ({@link Object}): the value to share with the FrameGraph from game logic using the registered GraphSource
      • + *
      * * @author codex * @param @@ -68,6 +77,7 @@ public class Attribute extends RenderPass { @Override protected void initialize(FrameGraph frameGraph) { + this. in = addInput(INPUT); out = addOutput(OUTPUT); } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BlitPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BlitPass.java index 8e0c843e1b..b1f4f7738d 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BlitPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BlitPass.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) 2024 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.passes; @@ -14,7 +41,7 @@ import com.jme3.texture.Texture2D; /** - * + * * @author codex */ public class BlitPass extends RenderPass { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java index 7e29c37283..496538d3c7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/DeferredPass.java @@ -64,11 +64,35 @@ import com.jme3.texture.Texture2D; import java.io.IOException; import java.util.EnumSet; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; /** - * Renders GBuffer information using deferred lighting to a color texture. + * Renders GBuffer information using the deferred lighting technique to a color texture. + *

      + * Inputs: + *

        + *
      • GBufferData[5] ({@link Texture2D}): Textures containing the necessary geometry information.
      • + *
      • Lights ({@link LightList}): List of lights in the scene (optional).
      • + *
      • LightTextures[3] ({@link Texture2D}): Textures containing light data (optional).
      • + *
      • TileTextures[2] ({@link Texture2D}): Textures sorting lights by screenspace tile (optional).
      • + *
      • NumLights (int): Number of lights stored in LightTextures (optional).
      • + *
      • Ambient ({@link ColorRGBA}): Accumulated color of ambient lights (optional).
      • + *
      • Probes (List<{@link LightProbe}>): List of light probes in the scene (optional)
      • + *
      + * Outputs: + *
        + *
      • Color ({@link Texture2D}): Result of deferred rendering.
      • + *
      + * There are three different ways to inject lighting information: + *
        + *
      1. Provide raw light list ("Lights"). Requires "LightTextures" and "Ambient" be undefined.
      2. + *
      3. Provide preprocessed light list ("Lights"), with "Ambient" and "Probes" defined, and "LightTextures" undefined.
      4. + *
      5. Provide lights packed into "LightTextures", with "NumLights", "Ambient", and "Probes" defined.
      6. + *
      + * With light textures, "TileTextures" can also be defined to use tiled lighting techniques, + * which generally makes the process more efficient, especially with a large number of lights. * * @author codex */ @@ -78,12 +102,13 @@ public class DeferredPass extends RenderPass implements TechniqueDefLogic { * Indicates the maximum number of directional, point, and spot lights * that can be handled using buffers. *

      - * Excess lights will be discarded. + * Excess lights will be discarded if using buffers (instead of textures). *

      * Development Note: if more uniforms are added to the * shader, this value may need to be decreased. */ public static final int MAX_BUFFER_LIGHTS = 320; + /** * Indicates the maximum number of light probes that can be handled. *

      @@ -91,7 +116,6 @@ public class DeferredPass extends RenderPass implements TechniqueDefLogic { */ public static final int MAX_PROBES = 3; - private static Defines defs; private static final List localProbeList = new LinkedList<>(); private boolean tiled = false; @@ -107,7 +131,6 @@ public class DeferredPass extends RenderPass implements TechniqueDefLogic { private final Texture2D[] tileTextures = new Texture2D[2]; private final ColorRGBA ambientColor = new ColorRGBA(); private List probeList; - private TechniqueDef active; public DeferredPass() {} public DeferredPass(boolean tiled) { @@ -116,11 +139,6 @@ public DeferredPass(boolean tiled) { @Override protected void initialize(FrameGraph frameGraph) { - // Lighting Arguments: - // IF LightTextures = undefined - // EITHER provide raw light list - // OR provide processed light list (without ambient or probes), ambient color, and probe list. - // ELSE provide 3 light textures, number of lights, ambient color, and probe list. addInputGroup("GBufferData", 5); lights = addInput("Lights"); addInputGroup("LightTextures", 3); @@ -133,11 +151,8 @@ protected void initialize(FrameGraph frameGraph) { colorDef.setFormatFlexible(true); assetManager = frameGraph.getAssetManager(); material = new Material(assetManager, "Common/MatDefs/ShadingCommon/DeferredShading.j3md"); - if (defs == null) { - defs = new Defines(); -// for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { -// defs.config(t); -// } + for (TechniqueDef t : material.getMaterialDef().getTechniqueDefs("DeferredPass")) { + Defines.config(t); } } @Override @@ -153,21 +168,27 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { + + // setup framebuffer FrameBuffer fb = getFrameBuffer(context, 1); resources.acquireColorTargets(fb, outColor); context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); + + // apply gbuffer textures ResourceTicket[] gbuffers = getGroupArray("GBufferData"); for (int i = 0; i < gbuffers.length; i++) { material.setTexture("GBuffer"+i, resources.acquire(gbuffers[i])); } + + // setup technique material.selectTechnique("DeferredPass", context.getRenderManager()); - material.getActiveTechnique().getDef().setLogic(this); - active = material.getActiveTechnique().getDef(); - if (active.getDefineNames().length == 0) { - defs.config(active); - } + TechniqueDef active = material.getActiveTechnique().getDef(); + active.setLogic(this); + Defines.config(active); + + // render acquireArrayOrElse("LightTextures", lightTextures, null); if (lightTextures[0] == null) { context.getScreen().render(context.getRenderManager(), material, resources.acquire(lights)); @@ -181,7 +202,7 @@ protected void execute(FGRenderContext context) { material.setTexture("LightIndex", tileTextures[1]); context.renderFullscreen(material); } - material.getActiveTechnique().getDef().setLogic(null); + active.setLogic(null); } @Override protected void reset(FGRenderContext context) {} @@ -190,7 +211,8 @@ protected void cleanup(FrameGraph frameGraph) {} @Override public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager, EnumSet rendererCaps, LightList lights, DefineList defines) { - // if the technique def somehow wasn't configured, configure it + TechniqueDef active = material.getActiveTechnique().getDef(); + Defines defs = Defines.get(active); if (lightTextures[0] == null) { ColorRGBA amb = resources.acquireOrElse(ambient, null); if (amb == null) { @@ -217,7 +239,7 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager // this may need to be changed to only be enabled when there is an ambient light present defines.set(defs.useAmbientLight, true); defines.set(defs.numProbes, getNumReadyProbes(probeList)); - return material.getActiveTechnique().getDef().getShader(assetManager, rendererCaps, defines); + return active.getShader(assetManager, rendererCaps, defines); } @Override public void render(RenderManager rm, Shader shader, Geometry geometry, @@ -225,10 +247,8 @@ public void render(RenderManager rm, Shader shader, Geometry geometry, Renderer renderer = rm.getRenderer(); injectShaderGlobals(rm, shader, lastBindUnits.textureUnit); if (lightTextures[0] == null) { - // pass light data by uniforms injectLightBuffers(shader, lights); } else { - // pass light data by textures injectLightTextures(shader); } renderer.setShader(shader); @@ -250,10 +270,7 @@ public void read(JmeImporter im) throws IOException { private int getNumReadyProbes(List probes) { int n = 0; - if (probes == null) { - return n; - } - for (LightProbe p : probes) { + if (probes != null) for (LightProbe p : probes) { if (p.isEnabled() && p.isReady() && ++n == MAX_PROBES) { break; } @@ -348,11 +365,10 @@ private static class Defines { private static final String DEFINE_USE_AMBIENT_LIGHT = "USE_AMBIENT_LIGHT"; private static final String DEFINE_TILED_LIGHTS = "TILED_LIGHTS"; - public int numLights, useTextures, numProbes, useAmbientLight, useTiles; + private static final HashMap defMap = new HashMap<>(); + public final int numLights, useTextures, numProbes, useAmbientLight, useTiles; - public Defines() {} - - public void config(TechniqueDef def) { + public Defines(TechniqueDef def) { numLights = def.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int); numProbes = def.addShaderUnmappedDefine(DEFINE_NB_PROBES, VarType.Int); useTextures = def.addShaderUnmappedDefine(DEFINE_USE_LIGHT_TEXTURES, VarType.Boolean); @@ -360,6 +376,23 @@ public void config(TechniqueDef def) { useTiles = def.addShaderUnmappedDefine(DEFINE_TILED_LIGHTS, VarType.Boolean); } + public static Defines config(TechniqueDef technique) { + Defines defs = defMap.get(technique); + if (defs == null) { + defs = new Defines(technique); + defMap.put(technique, defs); + } + return defs; + } + + public static Defines get(TechniqueDef technique) { + Defines defs = defMap.get(technique); + if (defs == null) { + throw new NullPointerException("Attempted to use unconfigured TechniqueDef."); + } + return defs; + } + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/FilterPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/FilterPass.java deleted file mode 100644 index 164cbe2fe5..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/FilterPass.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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.passes; - -/** - * - * @author codex - */ -public abstract class FilterPass extends RenderPass { - - - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java index d06b8cc1f0..da23efb9d7 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GBufferPass.java @@ -45,13 +45,20 @@ import java.util.function.Function; import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.framegraph.GeometryQueue; -import com.jme3.renderer.queue.GeometryList; /** - * Renders diffuse, specular, emissive, normal, and depth information to a set of - * textures. + * Renders information about a queue of geometries to a set of textures. *

      - * Lights from rendered geometries are accumulated and exported. + * Inputs: + *

        + *
      • Geometry ({@link GeometryQueue}: queue of geometries to extract information from.
      • + *
      + * Outputs: + *
        + *
      • GBufferData[5] ({@link Texture2D}): textures containing geometry information.
      • + *
      • NumRenders (int): number of geometries rendered, since not all geometries are guaranteed to be rendered.
      • + *
      + * Geometries that do not have a material with a "GBuffer" technique are not rendered. * * @author codex */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GeometryPass.java similarity index 84% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GeometryPass.java index 2b63ae4e98..8412fe1742 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/BucketPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GeometryPass.java @@ -49,10 +49,22 @@ /** * Renders a queue bucket to a set of color and depth textures. + *

      + * Inputs: + *

        + *
      • Geometry ({@link GeometryQueue}): queue of geometries to render.
      • + *
      • Color ({@link Texture2D}): Color texture to combine (by depth comparison) with the result of this render (optional).
      • + *
      • Depth ({@link Texture2D}): Depth texture to combine (by depth comparison) with the result of this render (optional).
      • + *
      + * Outputs: + *
        + *
      • Color ({@link Texture2D}): Resulting color texture.
      • + *
      • Depth ({@link Texture2D}): Resulting depth texture.
      • + *
      * * @author codex */ -public class BucketPass extends RenderPass { +public class GeometryPass extends RenderPass { private final DepthRange depth = new DepthRange(); private ResourceTicket inColor, inDepth, outColor, outDepth; @@ -60,13 +72,13 @@ public class BucketPass extends RenderPass { private TextureDef colorDef, depthDef; private boolean perspective; - public BucketPass() { + public GeometryPass() { this(DepthRange.IDENTITY, true); } - public BucketPass(DepthRange depth) { + public GeometryPass(DepthRange depth) { this(depth, true); } - public BucketPass(DepthRange depth, boolean perspective) { + public GeometryPass(DepthRange depth, boolean perspective) { this.depth.set(depth); this.perspective = perspective; } @@ -104,14 +116,14 @@ protected void execute(FGRenderContext context) { context.getRenderer().clearBuffers(true, true, true); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); context.renderTextures(resources.acquireOrElse(inColor, null), resources.acquireOrElse(inDepth, null)); - context.getRenderer().setDepthRange(depth); - if (!perspective) { - context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); - } + //context.getRenderer().setDepthRange(depth); + //if (!perspective) { + // context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); + //} context.renderGeometry(resources.acquire(geometry), null, null); - if (!perspective) { - context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); - } + //if (!perspective) { + // context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); + //} } @Override protected void reset(FGRenderContext context) {} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java index d47f672fd5..565e540e80 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GroupAttribute.java @@ -1,15 +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 + * Copyright (c) 2024 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.passes; import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; -import com.jme3.export.NullSavable; import com.jme3.export.OutputCapsule; -import com.jme3.export.Savable; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; @@ -20,7 +45,21 @@ import java.util.ArrayList; /** - * + * Accepts and produces and group of inputs and outputs to/from game logic. + *

      + * The size of each group is determine by the specified group size. Each given + * {@link GraphSource} and {@link GraphTarget} map index-to-index to an individual + * output or input. Surplus sources and targets are not used. + *

      + * Inputs: + *

        + *
      • {@link #INPUT}[n] ({@link Object}): input group of a specified size (optional). + *
      + * Outputs: + *
        + *
      • {@link #OUTPUT}[n] ({@link Object)}: output group of a specified size. + *
      + * * @author codex */ public class GroupAttribute extends RenderPass { @@ -96,19 +135,39 @@ public void read(JmeImporter im) throws IOException { in.readToCollection("sources", sources); in.readToCollection("targets", targets); } - + + /** + * Sets the size of the input and output groups. + * + * @param groupSize + * @throws IllegalStateException if called while pass is assigned to a framegraph + */ public void setGroupSize(int groupSize) { if (isAssigned()) { throw new IllegalStateException("Cannot alter group size while assigned to a framegraph."); } this.groupSize = groupSize; } + /** + * Sets the source that provides values for the output at the index + * within the output group. + * + * @param i + * @param source + */ public void setSource(int i, GraphSource source) { while (sources.size() <= i) { sources.add(null); } sources.set(i, source); } + /** + * Sets the target that recieves values from the input at the index + * within the input group. + * + * @param i + * @param target + */ public void setTarget(int i, GraphTarget target) { while (targets.size() <= i) { targets.add(null); @@ -116,9 +175,19 @@ public void setTarget(int i, GraphTarget target) { targets.set(i, target); } + /** + * + * @return + */ public int getGroupSize() { return groupSize; } + /** + * Gets the source at the index. + * + * @param i + * @return source at the index, or null if no source is assigned at the index + */ public GraphSource getSource(int i) { if (i < sources.size()) { return sources.get(i); @@ -126,6 +195,12 @@ public GraphSource getSource(int i) { return null; } } + /** + * Gets the target at the index. + * + * @param i + * @return target at the index, or null if no target is assigned at the index. + */ public GraphTarget getTarget(int i) { if (i < targets.size()) { return targets.get(i); @@ -134,9 +209,21 @@ public GraphTarget getTarget(int i) { } } + /** + * Gets the name of the input at the index. + * + * @param i + * @return + */ public static String getInput(int i) { return INPUT+'['+i+']'; } + /** + * Gets the name of the output at the index. + * + * @param i + * @return + */ public static String getOutput(int i) { return OUTPUT+'['+i+']'; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 96a6c82dcf..2e3330ffe5 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -47,7 +47,10 @@ * Merges several inputs into one output by choosing one input to connect to * the output using a controllable index. *

      - * This pass does no rendering and cannot be culled. + * Junction can either function as a set of individual inputs (group size is 1), or as a set of + * group inputs (group size is greater than 1). + *

      + * Static methods should be used to correctly reference inputs and outputs. * * @author codex * @param @@ -208,15 +211,43 @@ public int getDefaultIndex() { return defaultIndex; } + /** + * Returns a string referencing an individual input (groupSize = 1) or + * an input group (groupSize > 1). + * + * @param i index of input or input group + * @return + */ public static String getInput(int i) { return "Input["+i+"]"; } + /** + * Returns a string referencing an individual input that is part of + * a group (groupSize > 1 only). + * + * @param i index of group + * @param j index of input in group + * @return + */ public static String getInput(int i, int j) { return "Input["+i+"]["+j+"]"; } + /** + * Returns a string referencing the individual output (groupSize = 1) + * or the output group (groupSize > 1). + * + * @return + */ public static String getOutput() { return "Value"; } + /** + * Returns a string referencing an individual output in the output group + * (groupSize > 1 only). + * + * @param i index of output in group + * @return + */ public static String getOutput(int i) { return "Value["+i+"]"; } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LegacyFilterPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LegacyFilterPass.java deleted file mode 100644 index 8ea7feb5fd..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LegacyFilterPass.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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.passes; - -import com.jme3.export.JmeExporter; -import com.jme3.export.OutputCapsule; -import com.jme3.material.Material; -import com.jme3.post.Filter; -import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.FGRenderContext; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.ResourceTicket; -import com.jme3.renderer.framegraph.client.GraphSource; -import com.jme3.renderer.framegraph.definitions.TextureDef; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture2D; -import java.io.IOException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -/** - * FrameGraph adapter for traditional filters. - * - * @author codex - */ -public class LegacyFilterPass extends RenderPass { - - private ResourceTicket inColor, inDepth, outColor; - private TextureDef texDef = TextureDef.texture2D(); - private final HashMap filters = new HashMap<>(); - private GraphSource source; - - @Override - protected void initialize(FrameGraph frameGraph) { - inColor = addInput("Color"); - inDepth = addInput("Depth"); - } - @Override - protected void prepare(FGRenderContext context) { - declare(texDef, outColor); - reference(inColor, inDepth); - } - @Override - protected void execute(FGRenderContext context) { - PassFilter f = filters.get(context.getViewPort()); - if (f == null) { - f = new PassFilter(source.getGraphValue(frameGraph, context.getViewPort())); - f.filter.init(frameGraph.getAssetManager(), context.getRenderManager(), context.getViewPort(), 0, 0); - filters.put(context.getViewPort(), f); - } - f.used = true; - Texture2D colorTex = resources.acquire(inColor); - Texture2D depthTex = resources.acquire(inDepth); - FrameBuffer fb = getFrameBuffer(context, 1); - resources.acquireColorTarget(fb, outColor); - if (f.filter.isEnabled()) { - f.filter.filterPreFrame(context.getTpf()); - List passes = f.filter.getPostRenderPasses(); - if (passes != null) for (Filter.Pass p : passes) { - p.beforeRender(); - Material mat = p.getPassMaterial(); - if (p.requiresSceneAsTexture()) { - applyTexture(mat, colorTex, "Texture", "NumSamples"); - } - if (p.requiresDepthAsTexture()) { - applyTexture(mat, depthTex, "DepthTexture", "NumSamplesDepth"); - } - context.getRenderer().setFrameBuffer(p.getRenderFrameBuffer()); - context.getRenderer().clearBuffers(true, true, true); - context.renderFullscreen(p.getPassMaterial()); - } - Material mat = f.filter.getPassMaterial(); - if (f.filter.isReqSceneTex()) { - applyTexture(mat, colorTex, "Texture", "NumSamples"); - } - if (f.filter.isReqDepthTex()) { - applyTexture(mat, depthTex, "DepthTexture", "NumSamplesDepth"); - } - context.getRenderer().setFrameBuffer(fb); - context.getRenderer().clearBuffers(true, true, true); - context.renderFullscreen(mat); - f.filter.filterPostRender(context.getRenderer(), fb); - } - } - @Override - protected void reset(FGRenderContext context) {} - @Override - protected void cleanup(FrameGraph frameGraph) {} - @Override - public void renderingComplete() { - super.renderingComplete(); - for (Iterator it = filters.values().iterator(); it.hasNext();) { - PassFilter f = it.next(); - if (!f.used) { - f.filter.cleanup(frameGraph.getRenderManager().getRenderer()); - it.remove(); - } else { - f.used = false; - } - } - } - @Override - public void write(JmeExporter ex) throws IOException { - super.write(ex); - } - - private void applyTexture(Material mat, Texture tex, String texParam, String msParam) { - mat.setTexture(texParam, tex); - if (tex.getImage().getMultiSamples() > 1) { - mat.setInt(msParam, tex.getImage().getMultiSamples()); - } else { - mat.clearParam(msParam); - } - } - - public Filter getFilter(ViewPort vp) { - PassFilter f = filters.get(vp); - if (f != null) { - return f.filter; - } else { - return null; - } - } - - private static class PassFilter { - - public final Filter filter; - public int width = -1; - public int height = -1; - public boolean used = true; - - public PassFilter(Filter filter) { - this.filter = filter; - } - - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java index e5bc5acb06..a47bccd7cc 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightImagePass.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) 2024 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.passes; @@ -28,7 +55,24 @@ import java.util.List; /** - * + * Packs light data into a set of textures. + *

      + * Inputs: + *

        + *
      • Lights ({@link LightList}): list of lights to pack.
      • + *
      • TileInfo ({@link TileInfo}): settings for packing tile information (optional).
      • + *
      + * Outputs: + *
        + *
      • Textures[3] ({@link Texture2D}): textures containing packed light information.
      • + *
      • TileTextures[2] ({@link Texture2D}): textures containing tile and index information.
      • + *
      • NumLights (int): number of lights that are not AmbientLights or LightProbes.
      • + *
      • Ambient ({@link ColorRGBA}): accumulated color of all AmbientLights.
      • + *
      • Probes (LinkedList<{@link LightProbe}>): list of all LightProbes.
      • + *
      + * If "TileInfo" is defined, tile textures will additionally be generated, which can be used + * in algorithms such as tiled deferred. Otherwise, "TileTextures" will be undefined. + * * @author codex */ public class LightImagePass extends RenderPass { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightListExtractPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightListExtractPass.java index 9f8fe0128d..90f74dbb94 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightListExtractPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/LightListExtractPass.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) 2024 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.passes; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputGeometryPass.java similarity index 67% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputGeometryPass.java index 7ad66e5e51..7fa82a256a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputRenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputGeometryPass.java @@ -47,23 +47,9 @@ * * @author codex */ -public class OutputRenderPass extends RenderPass { +public class OutputGeometryPass extends RenderPass { private ResourceTicket geometry; - private DepthRange depth; - private boolean perspective = true; - - public OutputRenderPass() { - this(DepthRange.IDENTITY, true); - } - public OutputRenderPass(DepthRange range) { - this(range, true); - } - public OutputRenderPass(DepthRange depth, boolean perspective) { - this.depth = depth; - this.perspective = perspective; - } - @Override protected void initialize(FrameGraph frameGraph) { @@ -76,15 +62,7 @@ protected void prepare(FGRenderContext context) { @Override protected void execute(FGRenderContext context) { context.popFrameBuffer(); - if (!perspective) { - context.getRenderManager().setCamera(context.getViewPort().getCamera(), true); - } - context.getRenderer().setDepthRange(depth); - //context.renderViewPortQueue(bucket, true); context.renderGeometry(resources.acquire(geometry), null, null); - if (!perspective) { - context.getRenderManager().setCamera(context.getViewPort().getCamera(), false); - } } @Override protected void reset(FGRenderContext context) {} @@ -94,19 +72,5 @@ protected void cleanup(FrameGraph frameGraph) {} public boolean isUsed() { return geometry.hasSource(); } - @Override - public void write(JmeExporter ex) throws IOException { - super.write(ex); - OutputCapsule out = ex.getCapsule(this); - out.write(depth, "depth", DepthRange.IDENTITY); - out.write(perspective, "perspective", true); - } - @Override - public void read(JmeImporter im) throws IOException { - super.read(im); - InputCapsule in = im.getCapsule(this); - depth = in.readSavable("depth", DepthRange.class, DepthRange.IDENTITY); - perspective = in.readBoolean("perspective", true); - } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingRenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingRenderPass.java deleted file mode 100644 index 1a432daa35..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/PostProcessingRenderPass.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2024 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.passes; - -import com.jme3.post.SceneProcessor; -import com.jme3.profile.AppProfiler; -import com.jme3.profile.SpStep; -import com.jme3.profile.VpStep; -import com.jme3.renderer.framegraph.FGRenderContext; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.util.SafeArrayList; - -/** - * Runs viewport post-processors. - *

      - * FilterPostProcessor is rendered to the viewport's output framebuffer. - * - * @author codex - */ -public class PostProcessingRenderPass extends RenderPass { - - - - @Override - protected void initialize(FrameGraph frameGraph) {} - @Override - protected void prepare(FGRenderContext context) {} - @Override - protected void execute(FGRenderContext context) { - SafeArrayList processors = context.getViewPort().getProcessors(); - if (!processors.isEmpty()) { - context.popFrameBuffer(); - AppProfiler prof = context.getProfiler(); - if (prof != null) { - prof.vpStep(VpStep.PostFrame, context.getViewPort(), null); - } - for (SceneProcessor proc : processors.getArray()) { - if (prof != null) { - prof.spStep(SpStep.ProcPostFrame, proc.getClass().getSimpleName()); - } - proc.postFrame(context.getViewPort().getOutputFrameBuffer()); - } - if (prof != null) { - prof.vpStep(VpStep.ProcEndRender, context.getViewPort(), null); - } - } - } - @Override - protected void reset(FGRenderContext context) {} - @Override - protected void cleanup(FrameGraph frameGraph) {} - @Override - public boolean isUsed() { - return true; - } - @Override - public void preFrame(FGRenderContext context) { - SafeArrayList processors = context.getViewPort().getProcessors(); - if (!processors.isEmpty()) { - AppProfiler prof = context.getProfiler(); - for (SceneProcessor p : processors.getArray()) { - if (!p.isInitialized()) { - p.initialize(context.getRenderManager(), context.getViewPort()); - } - p.setProfiler(prof); - if (prof != null) { - prof.spStep(SpStep.ProcPreFrame, p.getClass().getSimpleName()); - } - p.preFrame(context.getTpf()); - } - } - } - @Override - public void postQueue(FGRenderContext context) { - SafeArrayList processors = context.getViewPort().getProcessors(); - if (!processors.isEmpty()) { - AppProfiler prof = context.getProfiler(); - for (SceneProcessor p : processors.getArray()) { - if (prof != null) { - prof.spStep(SpStep.ProcPostQueue, p.getClass().getSimpleName()); - } - p.postQueue(context.getViewPort().getQueue()); - } - } - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java index d96b544c31..f3e5bdf4fe 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.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) 2024 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.passes; @@ -12,11 +39,20 @@ import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.GeometryQueue; import com.jme3.renderer.framegraph.ResourceTicket; -import com.jme3.renderer.queue.GeometryList; import java.io.IOException; /** - * + * Merges a specified number of {@link GeometryQueue}s into one output queue. + *

      + * Inputs: + *

        + *
      • Queues[n] ({@link GeometryQueue}: queues to merge into one.
      • + *
      + * Outputs: + *
        + *
      • Result ({@link GeometryQueue}): resulting geometry queue.
      • + *
      + * * @author codex */ public class QueueMergePass extends RenderPass { @@ -42,6 +78,7 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { + System.out.println("acquire queues to merge"); GeometryQueue[] queues = acquireArray("Queues", n -> new GeometryQueue[n]); for (GeometryQueue q : queues) { target.add(q); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index d7d1b7bbdf..33f555748b 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -55,7 +55,7 @@ import java.util.function.Function; /** - * Performs rendering operations for a framegraph. + * Modular rendering process for a {@link FrameGraph}. * * @author codex */ @@ -197,24 +197,12 @@ public void renderingComplete() { } } } - /** - * Called on the pre-rendering step. - * - * @param context - */ - public void preFrame(FGRenderContext context) {} - /** - * Called after render queues have been assembled. - * - * @param context - */ - public void postQueue(FGRenderContext context) {} /** * Declares a new resource. * * @param - * @param def + * @param def definition for new resource * @param ticket ticket to store resulting index * @return given ticket */ @@ -222,20 +210,7 @@ protected ResourceTicket declare(ResourceDef def, ResourceTicket ti return resources.declare(this, def, ticket); } /** - * Declares a new resource that is locally used only. - * - * @param - * @param def - * @param ticket - * @return - */ - protected ResourceTicket declareLocal(ResourceDef def, ResourceTicket ticket) { - ticket = resources.declare(this, def, ticket); - resources.setSurvivesReferenceCull(ticket); - return ticket; - } - /** - * Reserves the resource associated with the ticket. + * Reserves the {@link com.jme3.renderer.framegraph.RenderObject RenderObject} associated with the ticket. * * @param ticket */ @@ -243,7 +218,7 @@ protected void reserve(ResourceTicket ticket) { resources.reserve(index, ticket); } /** - * Reserves each resource associated with the tickets. + * Reserves each RenderObject associated with the tickets. * * @param tickets */ @@ -288,6 +263,9 @@ protected void referenceOptional(ResourceTicket... tickets) { /** * Forces this thread to wait until all inputs are available for this pass. + *

      + * An incoming resource is deemed ready when {@link com.jme3.renderer.framegraph.ResourceView#claimReadPermissions() read + * permissions are claimed}. * * @param timeout maximum wait time for each ticket before a timeout exception is thrown * @param attempts maximum attempts for each ticket before a timeout exception is thrown @@ -300,8 +278,7 @@ public void waitForInputs(long timeout, int attempts) throws TimeoutException { } /** - * Acquires a set of resources from a ticket group and stores them in - * the array. + * Acquires a set of resources from a ticket group and stores them in the array. * * @param * @param name @@ -437,7 +414,7 @@ private ResourceTicket addOutput(ResourceTicket output) { * Creates and registers a new ticket as input. * * @param - * @param name + * @param name name assigned to the new ticket * @return created ticket */ protected ResourceTicket addInput(String name) { @@ -448,7 +425,7 @@ protected ResourceTicket addInput(String name) { * Creates and registers a new ticket as output. * * @param - * @param name + * @param name name assigned to the new ticket * @return created ticket */ protected ResourceTicket addOutput(String name) { @@ -458,7 +435,9 @@ protected ResourceTicket addOutput(String name) { /** * Creates and adds a ticket array as a group input of the specified length under the given name. *

      - * Each ticket's name is formatted as the {@code groupName+"["+index+"]"}. + * A group bundles several tickets together so that they can easily be used together. + * Each individual ticket is handled just like any other, it is just registered with the group as well. + * Names are formatted as {@code groupName+"["+index+"]"}. * * @param * @param name @@ -477,7 +456,9 @@ protected ResourceTicket[] addInputGroup(String name, int length) { /** * Creates and adds a ticket array as a group output of the specified length under the given name. *

      - * Each ticket's name is formatted as the {@code groupName+"["+index+"]"}. + * A group bundles several tickets together so that they can easily be used together. + * Each individual ticket is handled just like any other, it is just registered with the group as well. + * Names are formatted as {@code groupName+"["+index+"]"}. * * @param * @param name @@ -494,7 +475,14 @@ protected ResourceTicket[] addOutputGroup(String name, int length) { return group.array; } /** - * Creates an input group of indefinite size. + * Creates an input ticket list. + *

      + * A ticket list is an extension of a ticket group where the size is indefinite, meaning connections + * can be added or removed at will. The order of connections is not guaranteed, especially + * when a ticket list is loaded from a save file. + *

      + * Each addition or removal from a ticket list requires an array resize, so it a ticket + * list should remain static where possible. * * @param name */ @@ -700,17 +688,20 @@ public void disconnectInputsFrom(RenderPass pass) { } /** - * Gets an existing framebuffer that matches the given properties. + * Gets an existing {@link FrameBuffer} that matches the given properties. *

      - * If no existing framebuffer matches, a new framebuffer will be created - * and returned. + * If no existing FrameBuffer matches, a new framebuffer will be created + * and returned. FrameBuffers that are not used during pass execution + * are disposed. + *

      + * If the event capturer is not null, an event will be logged for debugging. * - * @param cap graph event capturer, for debugging, may be null. - * @param tag - * @param width - * @param height - * @param samples - * @return + * @param cap graph event capturer for debugging (may be null) + * @param tag tag (name) requirement for returned FrameBuffer (may be null) + * @param width width requirement for returned FrameBuffer + * @param height height requirement for returned FrameBuffer + * @param samples samples requirement for returned FrameBuffer + * @return FrameBuffer matching given width, height, and samples */ protected FrameBuffer getFrameBuffer(GraphEventCapture cap, String tag, int width, int height, int samples) { if (tag == null) { @@ -733,6 +724,7 @@ protected FrameBuffer getFrameBuffer(GraphEventCapture cap, String tag, int widt * @param height * @param samples * @return + * @see #getFrameBuffer(com.jme3.renderer.framegraph.debug.GraphEventCapture, java.lang.String, int, int, int) */ protected FrameBuffer getFrameBuffer(GraphEventCapture cap, int width, int height, int samples) { return getFrameBuffer(cap, null, width, height, samples); @@ -743,6 +735,7 @@ protected FrameBuffer getFrameBuffer(GraphEventCapture cap, int width, int heigh * @param height * @param samples * @return + * @see #getFrameBuffer(com.jme3.renderer.framegraph.debug.GraphEventCapture, java.lang.String, int, int, int) */ protected FrameBuffer getFrameBuffer(int width, int height, int samples) { return getFrameBuffer(null, null, width, height, samples); @@ -754,25 +747,30 @@ protected FrameBuffer getFrameBuffer(int width, int height, int samples) { * @param height * @param samples * @return + * @see #getFrameBuffer(com.jme3.renderer.framegraph.debug.GraphEventCapture, java.lang.String, int, int, int) */ protected FrameBuffer getFrameBuffer(String tag, int width, int height, int samples) { return getFrameBuffer(null, tag, width, height, samples); } /** + * Creates a FrameBuffer matching the width and height presented by the {@link FGRenderContext}. * * @param context * @param samples * @return + * @see #getFrameBuffer(com.jme3.renderer.framegraph.debug.GraphEventCapture, java.lang.String, int, int, int) */ protected FrameBuffer getFrameBuffer(FGRenderContext context, int samples) { return getFrameBuffer(context.getGraphCapture(), context.getWidth(), context.getHeight(), samples); } /** + * Creates a FrameBuffer matching the width and height presented by the {@link FGRenderContext}. * * @param context * @param tag * @param samples * @return + * @see #getFrameBuffer(com.jme3.renderer.framegraph.debug.GraphEventCapture, java.lang.String, int, int, int) */ protected FrameBuffer getFrameBuffer(FGRenderContext context, String tag, int samples) { return getFrameBuffer(context.getGraphCapture(), tag, context.getWidth(), context.getHeight(), samples); @@ -781,15 +779,20 @@ protected FrameBuffer getFrameBuffer(FGRenderContext context, String tag, int sa /** * Counts the number of potential references to this pass. *

      + * Used for determining if this pass should be culled. + *

      * Called automatically. Do not use. */ - public void countReferences() { + public final void countReferences() { refs = outputs.size(); } /** * Shifts the execution index if this pass's index is greater than the * specified threshold. *

      + * Used to alter the index if another pass was inserted below this in the same + * {@link com.jme3.renderer.framegraph.PassThread PassThread}. + *

      * Called automatically. Do not use. * * @param threshold @@ -801,6 +804,8 @@ public void shiftExecutionIndex(int threshold, boolean positive) { /** * Shifts the id of this pass. *

      + * Used to ensure that all RenderPass ids are unique after loading from a save file. + *

      * Called automatically. Do not use. * * @param shift @@ -817,7 +822,7 @@ public void setName(String name) { this.name = name; } /** - * Sets the id of this pass. + * Sets the unique id of this pass. *

      * Called automatically. Do not use. * @@ -829,6 +834,10 @@ public void setId(int id) { /** * Sets the id used when exporting. *

      + * Export id counted from zero for each pass in the FrameGraph, which will not + * necessarily be globally unique or match the normal id. Only in use during + * export operations. + *

      * Called automatically. Do not use. * * @param id @@ -838,6 +847,7 @@ public void setExportId(int id) { } /** + * Gets the name assigned to this RenderPass. * * @return */ @@ -845,7 +855,7 @@ public String getName() { return name; } /** - * Gets the name used for profiling. + * Gets the name given to a profiler, which may be more compact or informative. * * @return */ @@ -853,6 +863,7 @@ public String getProfilerName() { return getName(); } /** + * Gets the unique id of this pass. * * @return */ @@ -860,6 +871,7 @@ public int getId() { return id; } /** + * Gets the export id of this pass used only during export operations. * * @return */ @@ -867,6 +879,7 @@ public int getExportId() { return exportId; } /** + * Gets the index of this pass. * * @return */ @@ -882,7 +895,7 @@ public boolean isAssigned() { return index != null; } /** - * Gets the number of ticket groups. + * Gets the number of active ticket groups in this pass. * * @return */ @@ -920,14 +933,31 @@ public void write(JmeExporter ex) throws IOException { OutputCapsule out = ex.getCapsule(this); out.write((exportId >= 0 ? exportId : id), "id", -1); out.write(name, "name", "RenderPass"); + write(out); } @Override public void read(JmeImporter im) throws IOException { InputCapsule in = im.getCapsule(this); id = in.readInt("id", -1); name = in.readString("name", "RenderPass"); + read(in); } + /** + * Convenience method for writing pass properties to the output capsule. + * + * @param out + * @throws IOException + */ + protected void write(OutputCapsule out) throws IOException {} + /** + * Convenience method for reading pass properties from the input capsule. + * + * @param in + * @throws IOException + */ + protected void read(InputCapsule in) throws IOException {} + /** * Gets the next generated id. * diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java index e51f64c9f9..25a92302f8 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.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) 2024 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.passes; @@ -19,7 +46,6 @@ import com.jme3.renderer.framegraph.GeometryQueue; import com.jme3.renderer.framegraph.ResourceTicket; import com.jme3.renderer.queue.GeometryComparator; -import com.jme3.renderer.queue.GeometryList; import com.jme3.renderer.queue.GuiComparator; import com.jme3.renderer.queue.NullComparator; import com.jme3.renderer.queue.OpaqueComparator; @@ -34,18 +60,30 @@ import java.util.List; /** - * + * Enqueues geometries into different {@link GeometryQueue}s based on world + * render bucket value. + *

      + * Outputs vary based on what GeometryQueues are added. If default queues are + * added (via {@link #SceneEnqueuePass(boolean, boolean)}), then the outputs + * include: "Opaque", "Sky", "Transparent", "Gui", and "Translucent". All outputs + * are GeometryQueues. + *

      + * A geometry is placed in queues according to the userdata found at + * {@link #QUEUE} (expected as String) according to ancestor inheritance, or the + * value returned by {@link Geometry#getQueueBucket()} (converted to String). + * Userdata value (if found) trumps queue bucket value. + * * @author codex */ public class SceneEnqueuePass extends RenderPass { /** - * Userdata key for denoting the bucket the spatial should be sorted into. + * Userdata key for denoting the queue the spatial should be sorted into. */ - public static final String BUCKET = "RenderQueue.Bucket"; + public static final String QUEUE = "SceneEnqueuePass.RenderQueue"; /** - * Userdata value for inheriting the bucket of the spatial's parent. + * Userdata value for inheriting the queue of the spatial's parent. */ public static final String INHERIT = RenderQueue.Bucket.Inherit.name(); @@ -60,14 +98,24 @@ public class SceneEnqueuePass extends RenderPass { private final HashMap buckets = new HashMap<>(); private String defaultBucket = OPAQUE; + /** + * Initialize an instance with default settings. + *

      + * Default queues are not added. + */ public SceneEnqueuePass() {} + /** + * + * @param runControlRender true to have this pass run {@link com.jme3.scene.control.Control} renders + * @param useDefaultBuckets true to have default queues registered + */ public SceneEnqueuePass(boolean runControlRender, boolean useDefaultBuckets) { this.runControlRender = runControlRender; if (useDefaultBuckets) { add(OPAQUE, new OpaqueComparator()); - add(SKY, null); + add(SKY, null, DepthRange.REAR, true); add(TRANSPARENT, new TransparentComparator()); - add(GUI, new GuiComparator()); + add(GUI, new GuiComparator(), DepthRange.FRONT, false); add(TRANSLUCENT, new TransparentComparator()); } } @@ -94,6 +142,7 @@ protected void execute(FGRenderContext context) { vp.getCamera().setPlaneState(0); queueSubScene(context, scenes.get(i), null); } + System.out.println("set queue resources"); for (Queue b : buckets.values()) { resources.setPrimitive(b.geometry, b.queue); resources.setPrimitive(b.lights, b.lightList); @@ -165,7 +214,7 @@ private void queueSubScene(FGRenderContext context, Spatial spatial, String pare } } private String getSpatialBucket(Spatial spatial, String parentValue) { - String value = spatial.getUserData(BUCKET); + String value = spatial.getUserData(QUEUE); if (value == null) { value = spatial.getLocalQueueBucket().name(); } @@ -182,26 +231,27 @@ private String getSpatialBucket(Spatial spatial, String parentValue) { } /** - * Adds a bucket with the name and comparator. + * Adds a queue with the name and comparator. *

      * If a bucket already exists under the name, it will be replaced. * - * @param name - * @param comparator - * @return + * @param name name of the queue corresponding to the output name + * @param comparator sorts geometries within the queue + * @return this instance * @throws IllegalStateException if called while assigned to a framegraph */ - public SceneEnqueuePass add(String name, GeometryComparator comparator) { + public final SceneEnqueuePass add(String name, GeometryComparator comparator) { return add(name, comparator, DepthRange.IDENTITY, true); } /** - * Adds a bucket with the name and comparator. + * Adds a queue with the name, comparator, depth range, and perspective mode. * - * @param name - * @param comparator + * @param name name of the queue corresponding to the output name. + * @param comparator sorts geometries within the queue * @param depth range in which geometries in the bucket will be rendered within * @param perspective true to render geometries in the bucket in perspective mode (versus orthogonal) - * @return this + * @return this instance + * @throws IllegalStateException if called while assigned to a framegraph */ public final SceneEnqueuePass add(String name, GeometryComparator comparator, DepthRange depth, boolean perspective) { if (isAssigned()) { diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert index e0c179c139..0187b54681 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert @@ -3,12 +3,10 @@ attribute vec3 inPosition; varying vec2 texCoord; -uniform vec2 m_Scale; void main() { texCoord = inPosition.xy; - vec2 pos = inPosition.xy * vec2(2.0) * m_Scale; - pos -= vec2(1.0); + vec2 pos = inPosition.xy * vec2(2.0) - vec2(1.0); gl_Position = vec4(pos, 0.0, 1.0); } diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java index 1748b3ecdb..d71f1e6989 100644 --- a/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.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) 2024 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.post.framegraph; @@ -22,7 +49,20 @@ import java.io.IOException; /** - * + * Port of {@link com.jme3.post.filters.BloomFilter} as a RenderPass. + *

      + * Inputs: + *

        + *
      • Color ({@link Texture2D}): color texture to apply bloom effect to (optional).
      • + *
      • Objects ({@link GeometryQueue}): specific geometries to apply bloom effect to (optional).
      • + *
      + * Outputs: + *
        + *
      • Color ({@link Texture2D}): resulting color texture.
      • + *
      + * If "Objects" is undefined, the texture from "Color" (input) will be used. Otherwise, the + * queue from "Objects" will be rendered with the Glow technique and the result used. + * * @author codex */ public class BloomPass extends RenderPass { @@ -53,24 +93,27 @@ protected void initialize(FrameGraph frameGraph) { @Override protected void prepare(FGRenderContext context) { declare(texDef, result); - reserve(result); + declare(texDef, midTex); + reserve(result, midTex); referenceOptional(inColor, objects); } @Override protected void execute(FGRenderContext context) { + // configure definitions int w = (int)Math.max(1f, context.getWidth()/downSamplingFactor); int h = (int)Math.max(1f, context.getHeight()/downSamplingFactor); texDef.setSize(w, h); - // get resources + + // get framebuffers and resources FrameBuffer outFb = getFrameBuffer(w, h, 1); Texture2D outTarget = resources.acquireColorTarget(outFb, result); FrameBuffer midFb = getFrameBuffer("mid", w, h, 1); - declare(texDef, midTex); Texture2D midTarget = resources.acquireColorTarget(midFb, midTex); GeometryQueue geometry = resources.acquireOrElse(objects, null); Texture2D scene = resources.acquireOrElse(inColor, null); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); + // geometry render if (geometry != null) { context.getRenderer().setFrameBuffer(outFb); @@ -82,6 +125,7 @@ protected void execute(FGRenderContext context) { } else { extractMat.clearParam("GlowMap"); } + // extraction extractMat.setFloat("ExposurePow", exposurePower); extractMat.setFloat("ExposureCutoff", exposureCutOff); @@ -92,21 +136,27 @@ protected void execute(FGRenderContext context) { extractMat.clearParam("Texture"); } render(context, midFb, extractMat); + // horizontal blur hBlurMat.setTexture("Texture", midTarget); - hBlurMat.setFloat("Size", context.getWidth()); + hBlurMat.setFloat("Size", w); hBlurMat.setFloat("Scale", blurScale); render(context, outFb, hBlurMat); + // vertical blur vBlurMat.setTexture("Texture", outTarget); - vBlurMat.setFloat("Size", context.getHeight()); + vBlurMat.setFloat("Size", h); vBlurMat.setFloat("Scale", blurScale); render(context, midFb, vBlurMat); + // final output outMat.setTexture("Texture", scene); outMat.setTexture("BloomTex", midTarget); render(context, outFb, outMat); + + // manual release required for unregistered tickets resources.release(midTex); + } @Override protected void reset(FGRenderContext context) {} diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java index e25a942965..eced0c1f1b 100644 --- a/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.java +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/CartoonEdgePass.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) 2024 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.post.framegraph; @@ -20,7 +47,18 @@ import java.io.IOException; /** - * Adds cartoon edges to the scene. + * Port of {@link com.jme3.post.filters.CartoonEdgeFilter} to a RenderPass. + *

      + * Inputs: + *

        + *
      • Color ({@link Texture2D}): scene color texture.
      • + *
      • Depth ({@link Texture2D}): scene depth texture.
      • + *
      • Normals ({@link Texture2D}): scene normals texture.
      • + *
      + * Outputs: + *
        + *
      • Color ({@link Texture2D}): resulting color texture.
      • + *
      * * @author codex */ diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java index 67a710c394..933c4af043 100644 --- a/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.java +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/DepthOfFieldPass.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) 2024 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.post.framegraph; @@ -19,7 +46,18 @@ import java.io.IOException; /** - * + * Port of {@link com.jme3.post.filters.DepthOfFieldFilter} to a RenderPass. + *

      + * Inputs: + *

        + *
      • Color ({@link Texture2D}): scene color texture.
      • + *
      • Depth ({@link Texture2D}): scene depth texture.
      • + *
      + * Outputs: + *
        + *
      • Color ({@link Texture2D}): resulting color texture.
      • + *
      + * * @author codex */ public class DepthOfFieldPass extends RenderPass { diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/FazePass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/FazePass.java deleted file mode 100644 index 86dda1f78e..0000000000 --- a/jme3-effects/src/main/java/com/jme3/post/framegraph/FazePass.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.post.framegraph; - -import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; -import com.jme3.renderer.framegraph.FGRenderContext; -import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.ResourceTicket; -import com.jme3.renderer.framegraph.definitions.TextureDef; -import com.jme3.renderer.framegraph.passes.RenderPass; -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.texture.FrameBuffer; -import com.jme3.texture.Texture; -import com.jme3.texture.Texture2D; - -/** - * Similar to fog, but does not affect sky visibility. - * - * @author codex - */ -public class FazePass extends RenderPass { - - private ResourceTicket inColor, inDepth, result; - private final TextureDef texDef = TextureDef.texture2D(); - private Material material; - private ColorRGBA color; - - @Override - protected void initialize(FrameGraph frameGraph) { - inColor = addInput("Color"); - inDepth = addInput("Depth"); - result = addOutput("Result"); - texDef.setMagFilter(Texture.MagFilter.Bilinear); - texDef.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); - material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/Post/Faze.j3md"); - material.setColor("FazeColor", color); - } - @Override - protected void prepare(FGRenderContext context) { - declare(texDef, result); - reserve(result); - reference(inColor, inDepth); - } - @Override - protected void execute(FGRenderContext context) { - - Texture2D colorTex = resources.acquire(inColor); - Texture2D depthTex = resources.acquire(inDepth); - material.setTexture("ColorMap", colorTex); - material.setTexture("DepthMap", depthTex); - - int w = colorTex.getImage().getWidth(); - int h = colorTex.getImage().getHeight(); - texDef.setSize(w, h); - texDef.setFormat(colorTex.getImage().getFormat()); - - FrameBuffer fb = getFrameBuffer(w, h, 1); - resources.acquireColorTarget(fb, result); - context.getRenderer().setFrameBuffer(fb); - context.getRenderer().clearBuffers(true, true, true); - context.resizeCamera(w, h, false, false, false); - - context.getScreen().render(context.getRenderManager(), material); - - } - @Override - protected void reset(FGRenderContext context) {} - @Override - protected void cleanup(FrameGraph frameGraph) {} - -} diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/FogPass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/FogPass.java new file mode 100644 index 0000000000..8fd8625b7d --- /dev/null +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/FogPass.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2024 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.post.framegraph; + +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.renderer.ViewPort; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.client.GraphSource; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.renderer.framegraph.passes.RenderPass; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; + +/** + * Port of {@link com.jme3.post.filters.FogFilter} to a RenderPass. + *

      + * Inputs: + *

        + *
      • Color ({@link Texture2D}): scene color texture.
      • + *
      • Depth ({@link Texture2D}): scene depth texture.
      • + *
      • Fog ({@link Texture2D}): screenspace fog texture to fade into (optional).
      • + *
      + * Outputs: + *
        + *
      • Result ({@link Texture2D}): resulting color texture.
      • + *
      + * If "Fog" is defined, the fog texture will be used to determine the fog color in screenspace. + * Otherwise, a solid color from a {@link GraphSource} will be used. + * + * @author codex + */ +public class FogPass extends RenderPass { + + private ResourceTicket colorMap, depthMap, fogMap, result; + private final TextureDef texDef = TextureDef.texture2D(); + private Material material; + private GraphSource color; + private GraphSource density, distance; + + @Override + protected void initialize(FrameGraph frameGraph) { + colorMap = addInput("Color"); + depthMap = addInput("Depth"); + fogMap = addInput("Fog"); + result = addOutput("Result"); + texDef.setMagFilter(Texture.MagFilter.Bilinear); + texDef.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/Post/SkyFog.j3md"); + } + @Override + protected void prepare(FGRenderContext context) { + declare(texDef, result); + reserve(result); + reference(colorMap, depthMap); + referenceOptional(fogMap); + } + @Override + protected void execute(FGRenderContext context) { + + ViewPort vp = context.getViewPort(); + + Texture2D colorTex = resources.acquire(colorMap); + Texture2D fogTex = resources.acquireOrElse(fogMap, null); + material.setTexture("ColorMap", colorTex); + material.setTexture("DepthMap", resources.acquire(depthMap)); + if (fogTex != null) { + material.setTexture("FogMap", fogTex); + } else { + material.clearParam("FogMap"); + material.setColor("FogColor", GraphSource.get(color, ColorRGBA.White, frameGraph, vp)); + } + material.setFloat("Density", GraphSource.get(density, .7f, frameGraph, vp)); + material.setFloat("Distance", GraphSource.get(distance, 1000f, frameGraph, vp)); + + int w = colorTex.getImage().getWidth(); + int h = colorTex.getImage().getHeight(); + texDef.setSize(w, h); + texDef.setFormat(colorTex.getImage().getFormat()); + + FrameBuffer fb = getFrameBuffer(w, h, 1); + resources.acquireColorTarget(fb, result); + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + context.resizeCamera(w, h, false, false, false); + + context.getScreen().render(context.getRenderManager(), material); + + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + + /** + * Sets the fog color used if no fog map is specified. + *

      + * default={@link ColorRGBA#White} + * + * @param color + */ + public void setColor(GraphSource color) { + this.color = color; + } + /** + * Sets the fog density. + *

      + * default={@code 0.7f} + * + * @param density + */ + public void setDensity(GraphSource density) { + this.density = density; + } + /** + * Sets the distance the fog begins at. + *

      + * default={@code 1000f} + * + * @param distance + */ + public void setDistance(GraphSource distance) { + this.distance = distance; + } + + /** + * + * @return + */ + public GraphSource getColor() { + return color; + } + /** + * + * @return + */ + public GraphSource getDensity() { + return density; + } + /** + * + * @return + */ + public GraphSource getDistance() { + return distance; + } + +} diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/HazePass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/HazePass.java new file mode 100644 index 0000000000..c4f0979145 --- /dev/null +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/HazePass.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2024 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.post.framegraph; + +import com.jme3.export.InputCapsule; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Vector2f; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.client.GraphSource; +import com.jme3.renderer.framegraph.definitions.TextureDef; +import com.jme3.renderer.framegraph.passes.RenderPass; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture2D; +import java.io.IOException; + +/** + * Fog that only affects objects within a specified depth range. + *

      + * Inputs: + *

        + *
      • Color ({@link Texture2D}): scene color texture.
      • + *
      • Depth ({@link Texture2D}): scene depth texture.
      • + *
      + * Outputs: + *
        + *
      • Result ({@link Texture2D}): resulting color texture.
      • + *
      + * + * @author codex + */ +public class HazePass extends RenderPass { + + private static final Vector2f DEF_RANGE = new Vector2f(0.5f, 1.0f); + + private ResourceTicket inColor, inDepth, result; + private final TextureDef texDef = TextureDef.texture2D(); + private Material material; + private GraphSource color; + private GraphSource range; + + @Override + protected void initialize(FrameGraph frameGraph) { + inColor = addInput("Color"); + inDepth = addInput("Depth"); + result = addOutput("Result"); + texDef.setMagFilter(Texture.MagFilter.Bilinear); + texDef.setMinFilter(Texture.MinFilter.BilinearNoMipMaps); + material = new Material(frameGraph.getAssetManager(), "Common/MatDefs/Post/Haze.j3md"); + } + @Override + protected void prepare(FGRenderContext context) { + declare(texDef, result); + reserve(result); + reference(inColor, inDepth); + } + @Override + protected void execute(FGRenderContext context) { + + Texture2D colorTex = resources.acquire(inColor); + Texture2D depthTex = resources.acquire(inDepth); + material.setTexture("ColorMap", colorTex); + material.setTexture("DepthMap", depthTex); + material.setColor("HazeColor", GraphSource.get(color, ColorRGBA.White, frameGraph, context.getViewPort())); + material.setVector2("Range", GraphSource.get(range, DEF_RANGE, frameGraph, context.getViewPort())); + + int w = colorTex.getImage().getWidth(); + int h = colorTex.getImage().getHeight(); + texDef.setSize(w, h); + texDef.setFormat(colorTex.getImage().getFormat()); + + FrameBuffer fb = getFrameBuffer(w, h, 1); + resources.acquireColorTarget(fb, result); + context.getRenderer().setFrameBuffer(fb); + context.getRenderer().clearBuffers(true, true, true); + context.resizeCamera(w, h, false, false, false); + + context.getScreen().render(context.getRenderManager(), material); + + } + @Override + protected void reset(FGRenderContext context) {} + @Override + protected void cleanup(FrameGraph frameGraph) {} + @Override + protected void write(OutputCapsule out) throws IOException { + if (color != null && color instanceof Savable) { + out.write((Savable)color, "color", null); + } + } + @Override + protected void read(InputCapsule in) throws IOException { + color = (GraphSource)in.readSavable("color", null); + } + + /** + * Sets the color of the haze. + *

      + * The alpha value determines the strength of the haze effect. One being + * total haze at the maximum range, and zero being no haze at the maximum range. + *

      + * default={@link ColorRGBA#White} + * + * @param color color source (or null to use default) + */ + public void setColor(GraphSource color) { + this.color = color; + } + /** + * Sets the depth range in which haze is increasing (exclusive). + *

      + * The x value determines the range's lower boundary, and the y value + * determines the range's upper boundary. Pixels outside the range + * are not affected by haze. + *

      + * default={@code (0.5, 1.0)} + * + * @param range range source (or null to use default) + */ + public void setRange(GraphSource range) { + this.range = range; + } + + /** + * + * @return + */ + public GraphSource getColor() { + return color; + } + /** + * + * @return + */ + public GraphSource getRange() { + return range; + } + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Haze.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/Haze.frag new file mode 100644 index 0000000000..d64dee7daf --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/Haze.frag @@ -0,0 +1,26 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" + +uniform sampler2D m_ColorMap; +uniform sampler2D m_DepthMap; +uniform vec4 m_HazeColor; +uniform vec2 m_Range; + +varying vec2 texCoord; + +float mapRange(in float value, in vec2 range) { + if (value > range.x && value < range.y) { + return (range.y - value) / (range.y - range.x); + } else { + return 0.0; + } +} + +void main() { + + vec4 color = texture2D(m_ColorMap, texCoord); + float depth = texture2D(m_DepthMap, texCoord).r; + gl_FragColor.rgb = mix(color.rgb, m_HazeColor.rgb, mapRange(depth, m_Range) * m_HazeColor.a); + //gl_FragColor = mix(color, m_HazeColor, depth); + //gl_FragColor = color; + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/Haze.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/Haze.j3md new file mode 100644 index 0000000000..41a44a5839 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/Haze.j3md @@ -0,0 +1,17 @@ +MaterialDef Haze { + + MaterialParameters { + Texture2D ColorMap + Texture2D DepthMap + Color HazeColor + Vector2 Range : 0.5 1.0 + } + + Technique { + + VertexShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/ShadingCommon/Screen.vert + FragmentShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Post/Haze.frag + + } + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/SkyFog.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/SkyFog.frag new file mode 100644 index 0000000000..e969d0b3ec --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/SkyFog.frag @@ -0,0 +1,34 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" + +uniform sampler2D m_ColorMap; +uniform sampler2D m_DepthMap; +uniform float m_Density; +uniform float m_Distance; +#ifdef FOG_MAP + uniform sampler2D m_FogMap; +#else + uniform vec4 m_FogColor; +#endif + +varying vec2 texCoord; + +const float LOG2 = 1.442695; + +void main() { + + vec2 frustum = vec2(1.0, m_Distance); + vec4 color = texture2D(m_ColorMap, texCoord); + float depth = texture2D(m_DepthMap, texCoord).r; + depth = (2.0 * frustum.x) / (frustum.y + frustum.x - depth * (frustum.y - frustum.x)); + + #ifdef FOG_MAP + vec4 fogClr = texture2D(m_FogMap, texCoord); + #else + vec4 fogClr = m_FogColor; + #endif + + float fogFactor = exp2(-m_Density * m_Density * depth * depth * LOG2); + fogFactor = clamp(fogFactor, 0.0, 1.0); + gl_FragColor = mix(fogClr, color, fogFactor); + +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/SkyFog.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/SkyFog.j3md new file mode 100644 index 0000000000..42bd88ec36 --- /dev/null +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/SkyFog.j3md @@ -0,0 +1,26 @@ +MaterialDef SkyFog { + + MaterialParameters { + Texture2D ColorMap + Texture2D DepthMap + Texture2D FogMap + Color FogColor + Float Density : 0.7 + Float Distance : 1000 + } + + Technique { + + VertexShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/ShadingCommon/Screen.vert + FragmentShader GLSL300 GLSL150 GLSL100 : Common/MatDefs/Post/SkyFog.frag + + WorldParameters { + } + + Defines { + FOG_MAP : FogMap + } + + } + +} diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java index 9329b6517b..d4cdb3a436 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/DownsamplingPass.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) 2024 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.framegraph.examples; @@ -15,7 +42,18 @@ import com.jme3.texture.Texture2D; /** - * + * Downsamples from the input texture to an output texture 1/4 the size. + *

      + * Inputs: + *

        + *
      • Input: the input color texture.
      • + *
      + * Outputs: + *
        + *
      • Output: the texture downsampled to. Is 1/4 the size of the input texture, + * and matches the format of the input texture.
      • + *
      + * * @author codex */ public class DownsamplingPass extends RenderPass { diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java index d0e5fd7291..f55ccef32f 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/HelloCustomFrameGraph.java @@ -11,7 +11,7 @@ import com.jme3.math.Vector3f; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.passes.QueueMergePass; -import com.jme3.renderer.framegraph.passes.BucketPass; +import com.jme3.renderer.framegraph.passes.GeometryPass; import com.jme3.renderer.framegraph.passes.OutputPass; import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; import com.jme3.scene.Geometry; @@ -41,7 +41,7 @@ public void simpleInitApp() { SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass(true, true)); QueueMergePass merge = fg.add(new QueueMergePass(5)); - BucketPass bucket = fg.add(new BucketPass()); + GeometryPass bucket = fg.add(new GeometryPass()); DownsamplingPass[] downsamples = fg.addLoop(new DownsamplingPass[4], (i) -> new DownsamplingPass(), "Input", "Output"); OutputPass out = fg.add(new OutputPass()); diff --git a/jme3-examples/src/main/java/jme3test/framegraph/examples/effects/TestFog.java b/jme3-examples/src/main/java/jme3test/framegraph/examples/effects/TestFog.java new file mode 100644 index 0000000000..4ea7d4d819 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/framegraph/examples/effects/TestFog.java @@ -0,0 +1,95 @@ +/* + * 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.framegraph.examples.effects; + +import com.jme3.app.SimpleApplication; +import com.jme3.material.Material; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.post.framegraph.HazePass; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.PassIndex; +import com.jme3.renderer.framegraph.passes.GeometryPass; +import com.jme3.renderer.framegraph.passes.OutputPass; +import com.jme3.renderer.framegraph.passes.QueueMergePass; +import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; +import com.jme3.scene.Geometry; +import com.jme3.scene.Spatial; +import com.jme3.scene.shape.Box; +import com.jme3.system.AppSettings; +import com.jme3.util.SkyFactory; + +/** + * + * @author codex + */ +public class TestFog extends SimpleApplication { + + public static void main(String[] args) { + TestFog app = new TestFog(); + AppSettings settings = new AppSettings(true); + settings.setWidth(700); + settings.setHeight(700); + app.setSettings(settings); + app.start(); + } + + @Override + public void simpleInitApp() { + + FrameGraph fg = new FrameGraph(assetManager); + viewPort.setFrameGraph(fg); + //viewPort.setFrameGraph(FrameGraphFactory.forward(assetManager)); + + SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass(true, true)); + QueueMergePass merge = fg.add(new QueueMergePass(5)); + GeometryPass geom = fg.add(new GeometryPass()); + HazePass haze = fg.add(new HazePass()); + OutputPass out = fg.add(new OutputPass()); + OutputPass out2 = fg.add(new OutputPass()); + + merge.makeInput(enqueue, "Opaque", "Queues[0]"); + merge.makeInput(enqueue, "Sky", "Queues[1]"); + merge.makeInput(enqueue, "Transparent", "Queues[2]"); + merge.makeInput(enqueue, "Gui", "Queues[3]"); + merge.makeInput(enqueue, "Translucent", "Queues[4]"); + + geom.makeInput(merge, "Result", "Geometry"); + + haze.makeInput(geom, "Color", "Color"); + haze.makeInput(geom, "Depth", "Depth"); + + out.makeInput(haze, "Result", "Color"); + out.makeInput(geom, "Depth", "Depth"); + + //out2.makeInput(sky, "Color", "Color"); + //out2.makeInput(sky, "Depth", "Depth"); + + flyCam.setMoveSpeed(100); + flyCam.setDragToRotate(true); + + for (int i = 0; i < 1000; i++) { + Geometry g = new Geometry("cube", new Box(1, 1, 1)); + g.setLocalTranslation( + FastMath.nextRandomFloat(-100, 100), + FastMath.nextRandomFloat(-100, 100), + FastMath.nextRandomFloat(-100, 100)); + g.setLocalRotation(new Quaternion().fromAngles( + FastMath.nextRandomFloat(0, FastMath.TWO_PI), + FastMath.nextRandomFloat(0, FastMath.TWO_PI), + FastMath.nextRandomFloat(0, FastMath.TWO_PI))); + Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + mat.setColor("Color", ColorRGBA.randomColor()); + g.setMaterial(mat); + rootNode.attachChild(g); + } + + Spatial skyBox = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap); + rootNode.attachChild(skyBox); + + } + +} diff --git a/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java b/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java index 1620392948..12ba25c00f 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java @@ -13,7 +13,7 @@ import com.jme3.post.framegraph.CartoonEdgePass; import com.jme3.renderer.framegraph.DepthRange; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.passes.BucketPass; +import com.jme3.renderer.framegraph.passes.GeometryPass; import com.jme3.renderer.framegraph.passes.OutputPass; import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; import com.jme3.scene.Geometry; @@ -41,11 +41,11 @@ public void simpleInitApp() { FrameGraph frameGraph = new FrameGraph(assetManager); SceneEnqueuePass enqueue = frameGraph.add(new SceneEnqueuePass()); - BucketPass opaque = frameGraph.add(new BucketPass()); - BucketPass sky = frameGraph.add(new BucketPass(DepthRange.REAR)); - BucketPass transparent = frameGraph.add(new BucketPass()); - BucketPass gui = frameGraph.add(new BucketPass(DepthRange.FRONT, false)); - BucketPass translucent = frameGraph.add(new BucketPass()); + GeometryPass opaque = frameGraph.add(new GeometryPass()); + GeometryPass sky = frameGraph.add(new GeometryPass(DepthRange.REAR)); + GeometryPass transparent = frameGraph.add(new GeometryPass()); + GeometryPass gui = frameGraph.add(new GeometryPass(DepthRange.FRONT, false)); + GeometryPass translucent = frameGraph.add(new GeometryPass()); OutputPass output = frameGraph.add(new OutputPass()); opaque.makeInput(enqueue, "Opaque", "Geometry"); From a27e6a84a3daa4f279a4a0f80ec55bf5c657face Mon Sep 17 00:00:00 2001 From: codex <103840984+codex128@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:55:42 -0400 Subject: [PATCH 111/111] added pipeline interface and added render modules --- .../java/com/jme3/asset/AssetManager.java | 3 +- .../com/jme3/asset/DesktopAssetManager.java | 3 +- .../java/com/jme3/asset/FrameGraphKey.java | 2 +- .../java/com/jme3/asset/ModuleGraphKey.java | 28 + .../java/com/jme3/export/InputCapsule.java | 1 - .../java/com/jme3/export/SavableObject.java | 197 +++++- .../renderer/AbstractPipelineContext.java | 45 ++ .../jme3/renderer/DefaultPipelineContext.java | 18 + .../renderer/{framegraph => }/DepthRange.java | 2 +- .../com/jme3/renderer/ForwardPipeline.java | 125 ++++ .../com/jme3/renderer/PipelineContext.java | 18 + .../java/com/jme3/renderer/RenderManager.java | 263 +++---- .../com/jme3/renderer/RenderPipeline.java | 58 ++ .../main/java/com/jme3/renderer/Renderer.java | 1 - .../main/java/com/jme3/renderer/ViewPort.java | 24 - .../jme3/renderer/framegraph/Connectable.java | 75 ++ .../framegraph/FGPipelineContext.java | 64 ++ .../renderer/framegraph/FGRenderContext.java | 34 +- .../jme3/renderer/framegraph/FrameGraph.java | 388 +++++------ .../renderer/framegraph/FrameGraphData.java | 203 ------ .../framegraph/FrameGraphFactory.java | 18 +- .../renderer/framegraph/GeometryQueue.java | 1 + .../framegraph/GraphRenderException.java | 18 + .../jme3/renderer/framegraph/PassIndex.java | 17 +- .../jme3/renderer/framegraph/PassThread.java | 428 ------------ .../renderer/framegraph/RenderObjectMap.java | 32 +- .../renderer/framegraph/ResourceList.java | 106 +-- .../renderer/framegraph/ResourceProducer.java | 78 --- .../renderer/framegraph/ResourceTicket.java | 96 +-- .../renderer/framegraph/ResourceUser.java | 28 + .../renderer/framegraph/ResourceView.java | 28 +- .../jme3/renderer/framegraph/TicketGroup.java | 118 ++++ .../framegraph/client/GraphSetting.java | 53 +- .../framegraph/debug/GraphEventCapture.java | 48 +- .../framegraph/export/FrameGraphData.java | 64 ++ .../framegraph/export/ModuleGraphData.java | 159 +++++ .../SavableConnection.java} | 94 ++- .../ModuleLocator.java} | 16 +- .../framegraph/modules/RenderContainer.java | 204 ++++++ .../framegraph/modules/RenderModule.java | 324 +++++++++ .../framegraph/modules/RenderThread.java | 61 ++ .../framegraph/modules/ThreadLauncher.java | 75 ++ .../framegraph/passes/GeometryPass.java | 2 +- .../renderer/framegraph/passes/Junction.java | 38 +- .../framegraph/passes/OutputGeometryPass.java | 2 +- .../framegraph/passes/QueueMergePass.java | 1 - .../framegraph/passes/RenderPass.java | 658 ++---------------- .../framegraph/passes/SceneEnqueuePass.java | 29 +- .../Common/MatDefs/ShadingCommon/Screen.vert | 4 +- .../com/jme3/post/framegraph/BloomPass.java | 12 +- .../framegraph/TestDeferredShading.java | 6 +- .../TestFrameGraphImportExport.java | 4 +- .../framegraph/TestPBRTerrainRenderPath.java | 4 +- .../TestSimpleDeferredLighting.java | 4 +- .../jme3test/framegraph/sandbox/Main.java | 2 +- 55 files changed, 2363 insertions(+), 2021 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/asset/ModuleGraphKey.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/AbstractPipelineContext.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/DefaultPipelineContext.java rename jme3-core/src/main/java/com/jme3/renderer/{framegraph => }/DepthRange.java (99%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/ForwardPipeline.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/PipelineContext.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/RenderPipeline.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/Connectable.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPipelineContext.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphRenderException.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.java delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceUser.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/TicketGroup.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/export/FrameGraphData.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/export/ModuleGraphData.java rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{SavablePassConnection.java => export/SavableConnection.java} (57%) rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{PassLocator.java => modules/ModuleLocator.java} (83%) create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderContainer.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderModule.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderThread.java create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/ThreadLauncher.java diff --git a/jme3-core/src/main/java/com/jme3/asset/AssetManager.java b/jme3-core/src/main/java/com/jme3/asset/AssetManager.java index 58e488e132..16cf9c8d01 100644 --- a/jme3-core/src/main/java/com/jme3/asset/AssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/AssetManager.java @@ -39,7 +39,8 @@ import com.jme3.material.Material; import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.Caps; -import com.jme3.renderer.framegraph.FrameGraphData; +import com.jme3.renderer.framegraph.export.FrameGraphData; +import com.jme3.renderer.framegraph.export.ModuleGraphData; import com.jme3.scene.Spatial; import com.jme3.scene.plugins.OBJLoader; import com.jme3.shader.ShaderGenerator; diff --git a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java index fa508daffe..218105369b 100644 --- a/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java +++ b/jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java @@ -38,7 +38,8 @@ import com.jme3.material.Material; import com.jme3.post.FilterPostProcessor; import com.jme3.renderer.Caps; -import com.jme3.renderer.framegraph.FrameGraphData; +import com.jme3.renderer.framegraph.export.FrameGraphData; +import com.jme3.renderer.framegraph.export.ModuleGraphData; import com.jme3.scene.Spatial; import com.jme3.shader.Glsl100ShaderGenerator; import com.jme3.shader.Glsl150ShaderGenerator; diff --git a/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java b/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java index a2e06b73f8..92b3d80668 100644 --- a/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java +++ b/jme3-core/src/main/java/com/jme3/asset/FrameGraphKey.java @@ -32,7 +32,7 @@ package com.jme3.asset; import com.jme3.asset.cache.AssetCache; -import com.jme3.renderer.framegraph.FrameGraphData; +import com.jme3.renderer.framegraph.export.FrameGraphData; /** * diff --git a/jme3-core/src/main/java/com/jme3/asset/ModuleGraphKey.java b/jme3-core/src/main/java/com/jme3/asset/ModuleGraphKey.java new file mode 100644 index 0000000000..04b27e95e3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/asset/ModuleGraphKey.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.asset; + +import com.jme3.asset.cache.AssetCache; +import com.jme3.renderer.framegraph.export.ModuleGraphData; + +/** + * + * @author codex + */ +public class ModuleGraphKey extends AssetKey { + + public ModuleGraphKey(String name) { + super(name); + } + public ModuleGraphKey() { + super(); + } + + @Override + public Class getCacheType() { + return null; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/export/InputCapsule.java b/jme3-core/src/main/java/com/jme3/export/InputCapsule.java index bde385f7ea..55b5ea0a66 100644 --- a/jme3-core/src/main/java/com/jme3/export/InputCapsule.java +++ b/jme3-core/src/main/java/com/jme3/export/InputCapsule.java @@ -125,7 +125,6 @@ public default T readSavable(String name, Class type, T d public default SavableObject readSavableObject(String name, SavableObject defVal) throws IOException { return readSavable(name, SavableObject.class, defVal); } - // ArrayLists diff --git a/jme3-core/src/main/java/com/jme3/export/SavableObject.java b/jme3-core/src/main/java/com/jme3/export/SavableObject.java index f07f0f0143..4cdf4ac425 100644 --- a/jme3-core/src/main/java/com/jme3/export/SavableObject.java +++ b/jme3-core/src/main/java/com/jme3/export/SavableObject.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) 2024 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.export; @@ -13,57 +40,129 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; /** - * Saves the internal object if it is savable. + * Saves the internal object if it is a supported savable type. + *

      + * All types supported by Input/Output capsules are supported here, + * except all arrays. * * @author codex */ public class SavableObject implements Savable { public static final SavableObject NULL = new SavableObject(); + private static final String NAME = "name"; private static final String OBJECT = "object"; private static final String TYPE = "type"; private static final String NULL_TYPE = "Null"; + private static final Logger LOG = Logger.getLogger(SavableObject.class.getName()); + private String name; private Object object; public SavableObject() {} + public SavableObject(String name) { + this(name, null); + } public SavableObject(Object object) { + this(null, object); + } + public SavableObject(String name, Object object) { + this.name = name; this.object = object; } @Override public void write(JmeExporter ex) throws IOException { - if (object == null) return; + if (object == null) { + return; + } OutputCapsule out = ex.getCapsule(this); + out.write(name, NAME, null); if (object instanceof Savable) { out.write((Savable)object, OBJECT, null); out.write("Savable", TYPE, NULL_TYPE); + } else if (object instanceof Savable[]) { + out.write((Savable[])object, OBJECT, new Savable[0]); + out.write("Savable[]", TYPE, NULL_TYPE); + } else if (object instanceof Savable[][]) { + out.write((Savable[][])object, OBJECT, new Savable[0][0]); + out.write("Savable[][]", TYPE, NULL_TYPE); } else if (object instanceof Integer) { out.write((int)object, OBJECT, 0); out.write("Integer", TYPE, NULL_TYPE); + } else if (object instanceof Integer[]) { + out.write((int[])object, OBJECT, new int[0]); + out.write("Integer[]", TYPE, NULL_TYPE); + } else if (object instanceof Integer[][]) { + out.write((int[][])object, OBJECT, new int[0][0]); + out.write("Integer[][]", TYPE, NULL_TYPE); } else if (object instanceof Float) { out.write((float)object, OBJECT, 0); out.write("Float", TYPE, NULL_TYPE); + } else if (object instanceof Float[]) { + out.write((float[])object, OBJECT, new float[0]); + out.write("Float[]", TYPE, NULL_TYPE); + } else if (object instanceof Float[][]) { + out.write((float[][])object, OBJECT, new float[0][0]); + out.write("Float[][]", TYPE, NULL_TYPE); } else if (object instanceof Double) { out.write((double)object, OBJECT, 0); out.write("Double", TYPE, NULL_TYPE); + } else if (object instanceof Double[]) { + out.write((double[])object, OBJECT, new double[0]); + out.write("Double[]", TYPE, NULL_TYPE); + } else if (object instanceof Double[][]) { + out.write((double[][])object, OBJECT, new double[0][0]); + out.write("Double[][]", TYPE, NULL_TYPE); } else if (object instanceof Boolean) { out.write((boolean)object, OBJECT, false); out.write("Boolean", TYPE, NULL_TYPE); + } else if (object instanceof Boolean[]) { + out.write((boolean[])object, OBJECT, new boolean[0]); + out.write("Boolean[]", TYPE, NULL_TYPE); + } else if (object instanceof Boolean[][]) { + out.write((boolean[][])object, OBJECT, new boolean[0][0]); + out.write("Boolean[][]", TYPE, NULL_TYPE); } else if (object instanceof Byte) { out.write((byte)object, OBJECT, (byte)0); out.write("Byte", TYPE, NULL_TYPE); + } else if (object instanceof Byte[]) { + out.write((byte[])object, OBJECT, new byte[0]); + out.write("Byte[]", TYPE, NULL_TYPE); + } else if (object instanceof Byte[][]) { + out.write((byte[][])object, OBJECT, new byte[0][0]); + out.write("Byte[][]", TYPE, NULL_TYPE); } else if (object instanceof String) { out.write((String)object, OBJECT, null); out.write("String", TYPE, NULL_TYPE); + } else if (object instanceof String[]) { + out.write((String[])object, OBJECT, new String[0]); + out.write("String[]", TYPE, NULL_TYPE); + } else if (object instanceof String[][]) { + out.write((String[][])object, OBJECT, new String[0][0]); + out.write("String[][]", TYPE, NULL_TYPE); } else if (object instanceof Long) { out.write((Long)object, OBJECT, 0); out.write("Long", TYPE, NULL_TYPE); + } else if (object instanceof Long[]) { + out.write((long[])object, OBJECT, new long[0]); + out.write("Long[]", TYPE, NULL_TYPE); + } else if (object instanceof Long[][]) { + out.write((long[][])object, OBJECT, new long[0][0]); + out.write("Long[][]", TYPE, NULL_TYPE); } else if (object instanceof Short) { out.write((short)object, OBJECT, (short)0); out.write("Short", TYPE, NULL_TYPE); + } else if (object instanceof Short[]) { + out.write((short[])object, OBJECT, new short[0]); + out.write("Short[]", TYPE, NULL_TYPE); + } else if (object instanceof Short[][]) { + out.write((short[][])object, OBJECT, new short[0][0]); + out.write("Short[][]", TYPE, NULL_TYPE); } else if (object instanceof BitSet) { out.write((BitSet)object, OBJECT, null); out.write("BitSet", TYPE, NULL_TYPE); @@ -82,46 +181,111 @@ public void write(JmeExporter ex) throws IOException { } else if (object instanceof ArrayList) { out.writeSavableArrayList((ArrayList)object, OBJECT, null); out.write("ArrayList", TYPE, NULL_TYPE); + } else if (object instanceof ArrayList[]) { + out.writeSavableArrayListArray((ArrayList[])object, OBJECT, new ArrayList[0]); + out.write("ArrayList[]", TYPE, NULL_TYPE); + } else if (object instanceof ArrayList[][]) { + out.writeSavableArrayListArray2D((ArrayList[][])object, OBJECT, new ArrayList[0][0]); + out.write("ArrayList[][]", TYPE, NULL_TYPE); } else if (object instanceof Map) { out.writeStringSavableMap((Map)object, OBJECT, null); - out.write("StringMap", TYPE, NULL_TYPE); + out.write("StringSavableMap", TYPE, NULL_TYPE); } else if (object instanceof IntMap) { out.writeIntSavableMap((IntMap)object, OBJECT, null); out.write("IntMap", TYPE, NULL_TYPE); + } else { + String type = object.getClass().getName(); + LOG.log(Level.WARNING, "Attempted to save unsupported type {0}", type); + out.write(type, TYPE, NULL_TYPE); } } @Override public void read(JmeImporter im) throws IOException { InputCapsule in = im.getCapsule(this); + name = in.readString(NAME, null); String type = in.readString(TYPE, NULL_TYPE); switch (type) { case "Savable": object = in.readSavable(OBJECT, null); break; + case "Savable[]": + object = in.readSavableArray(OBJECT, new Savable[0]); + break; + case "Savable[][]": + object = in.readSavableArray2D(OBJECT, new Savable[0][0]); + break; case "Integer": object = in.readInt(OBJECT, 0); break; + case "Integer[]": + object = in.readIntArray(OBJECT, new int[0]); + break; + case "Integer[][]": + object = in.readIntArray2D(OBJECT, new int[0][0]); + break; case "Float": object = in.readFloat(OBJECT, 0); break; + case "Float[]": + object = in.readFloatArray(OBJECT, new float[0]); + break; + case "Float[][]": + object = in.readFloatArray2D(OBJECT, new float[0][0]); + break; case "Double": object = in.readDouble(OBJECT, 0); break; + case "Double[]": + object = in.readDoubleArray(OBJECT, new double[0]); + break; + case "Double[][]": + object = in.readDoubleArray2D(OBJECT, new double[0][0]); + break; case "Boolean": object = in.readBoolean(OBJECT, false); break; + case "Boolean[]": + object = in.readBooleanArray(OBJECT, new boolean[0]); + break; + case "Boolean[][]": + object = in.readBooleanArray2D(OBJECT, new boolean[0][0]); + break; case "Byte": object = in.readByte(OBJECT, (byte)0); break; + case "Byte[]": + object = in.readByteArray(OBJECT, new byte[0]); + break; + case "Byte[][]": + object = in.readByteArray2D(OBJECT, new byte[0][0]); + break; case "String": object = in.readString(OBJECT, null); break; + case "String[]": + object = in.readStringArray(OBJECT, new String[0]); + break; + case "String[][]": + object = in.readStringArray2D(OBJECT, new String[0][0]); + break; case "Long": object = in.readLong(OBJECT, 0); break; + case "Long[]": + object = in.readLongArray(OBJECT, new long[0]); + break; + case "Long[][]": + object = in.readLongArray2D(OBJECT, new long[0][0]); + break; case "Short": object = in.readShort(OBJECT, (short)0); break; + case "Short[]": + object = in.readShortArray(OBJECT, new short[0]); + break; + case "Short[][]": + object = in.readShortArray2D(OBJECT, new short[0][0]); + break; case "BitSet": object = in.readBitSet(OBJECT, null); break; @@ -140,21 +304,42 @@ public void read(JmeImporter im) throws IOException { case "ArrayList": object = in.readSavableArrayList(OBJECT, null); break; - case "StringMap": + case "ArrayList[]": + object = in.readSavableArrayListArray(OBJECT, new ArrayList[0]); + break; + case "ArrayList[][]": + object = in.readSavableArrayListArray2D(OBJECT, new ArrayList[0][0]); + break; + case "StringSavableMap": object = in.readStringSavableMap(OBJECT, null); break; case "IntMap": object = in.readIntSavableMap(OBJECT, null); break; + case NULL_TYPE: + object = null; + break; + default: + LOG.log(Level.WARNING, "Attempted to load unsupported type {0}", type); + break; } } + public void setName(String name) { + this.name = name; + } public void setObject(Object object) { this.object = object; } + public String getName() { + return name; + } public Object getObject() { return object; } + public T getObject(Class type) { + return (T)object; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/AbstractPipelineContext.java b/jme3-core/src/main/java/com/jme3/renderer/AbstractPipelineContext.java new file mode 100644 index 0000000000..47773fa363 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/AbstractPipelineContext.java @@ -0,0 +1,45 @@ +/* + * 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; + +import java.util.LinkedList; + +/** + * + * @author codex + */ +public abstract class AbstractPipelineContext implements PipelineContext { + + private final LinkedList usedPipelines = new LinkedList<>(); + + @Override + public boolean addPipeline(RenderManager rm, RenderPipeline pipeline) { + boolean firstCall = false; + if (!pipeline.hasRenderedThisFrame()) { + if (firstCall = usedPipelines.isEmpty()) { + beginRenderFrame(rm); + } + pipeline.beginRenderFrame(rm); + usedPipelines.add(pipeline); + } else if (usedPipelines.isEmpty()) { + throw new IllegalStateException( + "Pipeline cannot have rendered at this point, but claims it did."); + } + return firstCall; + } + @Override + public void flushPipelineStack(RenderManager rm) { + for (RenderPipeline p : usedPipelines) { + p.endRenderFrame(rm); + } + usedPipelines.clear(); + endRenderFrame(rm); + } + + protected abstract void beginRenderFrame(RenderManager rm); + + protected abstract void endRenderFrame(RenderManager rm); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/DefaultPipelineContext.java b/jme3-core/src/main/java/com/jme3/renderer/DefaultPipelineContext.java new file mode 100644 index 0000000000..2ca510f2d3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/DefaultPipelineContext.java @@ -0,0 +1,18 @@ +/* + * 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; + +/** + * + * @author codex + */ +public class DefaultPipelineContext extends AbstractPipelineContext { + + @Override + protected void beginRenderFrame(RenderManager rm) {} + @Override + protected void endRenderFrame(RenderManager rm) {} + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java b/jme3-core/src/main/java/com/jme3/renderer/DepthRange.java similarity index 99% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java rename to jme3-core/src/main/java/com/jme3/renderer/DepthRange.java index ce9ec464cd..c9ad3c705c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java +++ b/jme3-core/src/main/java/com/jme3/renderer/DepthRange.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.framegraph; +package com.jme3.renderer; import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; diff --git a/jme3-core/src/main/java/com/jme3/renderer/ForwardPipeline.java b/jme3-core/src/main/java/com/jme3/renderer/ForwardPipeline.java new file mode 100644 index 0000000000..85be771c1c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/ForwardPipeline.java @@ -0,0 +1,125 @@ +/* + * 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; + +import com.jme3.post.SceneProcessor; +import com.jme3.profile.AppProfiler; +import com.jme3.profile.SpStep; +import com.jme3.profile.VpStep; +import com.jme3.scene.Spatial; +import com.jme3.util.SafeArrayList; +import java.util.List; + +/** + * + * @author codex + */ +public class ForwardPipeline implements RenderPipeline { + + private boolean rendered = false; + + @Override + public PipelineContext fetchPipelineContext(RenderManager rm) { + return rm.getDefaultContext(); + } + @Override + public boolean hasRenderedThisFrame() { + return rendered; + } + @Override + public void beginRenderFrame(RenderManager rm) {} + @Override + public void pipelineRender(RenderManager rm, PipelineContext context, ViewPort vp, float tpf) { + + AppProfiler prof = rm.getProfiler(); + + SafeArrayList processors = vp.getProcessors(); + if (processors.isEmpty()) { + processors = null; + } + + if (processors != null) { + if (prof != null) { + prof.vpStep(VpStep.PreFrame, vp, null); + } + for (SceneProcessor p : processors.getArray()) { + if (!p.isInitialized()) { + p.initialize(rm, vp); + } + p.setProfiler(prof); + if (prof != null) { + prof.spStep(SpStep.ProcPreFrame, p.getClass().getSimpleName()); + } + p.preFrame(tpf); + } + } + + rm.applyViewPort(vp); + + if (prof != null) { + prof.vpStep(VpStep.RenderScene, vp, null); + } + // flatten scenes into render queue + List scenes = vp.getScenes(); + for (int i = scenes.size() - 1; i >= 0; i--) { + rm.renderScene(scenes.get(i), vp); + } + if (processors != null) { + 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()); + } + } + + if (prof != null) { + prof.vpStep(VpStep.FlushQueue, vp, null); + } + rm.flushQueue(vp); + + 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); + } + } + + // render the translucent objects queue after processors have been rendered + rm.renderTranslucentQueue(vp); + + // clear any remaining spatials that were not rendered. + rm.clearQueue(vp); + + rendered = true; + + /* + * the call to setCamera will indirectly cause a clipRect to be set, must be cleared to avoid surprising results + * if renderer#copyFrameBuffer is used later + */ + rm.getRenderer().clearClipRect(); + + if (prof != null) { + prof.vpStep(VpStep.EndRender, vp, null); + } + + } + @Override + public void endRenderFrame(RenderManager rm) { + rendered = false; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/PipelineContext.java b/jme3-core/src/main/java/com/jme3/renderer/PipelineContext.java new file mode 100644 index 0000000000..27007c3499 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/PipelineContext.java @@ -0,0 +1,18 @@ +/* + * 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; + +/** + * Handles objects globally for a single type of RenderPipeline. + * + * @author codex + */ +public interface PipelineContext { + + public boolean addPipeline(RenderManager rm, RenderPipeline pipeline); + + public void flushPipelineStack(RenderManager rm); + +} 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 1023798171..9aeeb8c8c3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -69,9 +69,11 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -92,10 +94,9 @@ public class RenderManager { private final ArrayList preViewPorts = new ArrayList<>(); private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); - private final RenderObjectMap renderObjects; - private final LinkedList executedFrameGraphs = new LinkedList<>(); - private FrameGraph frameGraph; - private GraphEventCapture graphCapture; + private final HashMap contexts = new HashMap<>(); + private final LinkedList usedContexts = new LinkedList<>(); + private RenderPipeline defaultPipeline = new ForwardPipeline(); private Camera prevCam = null; private Material forcedMaterial = null; private String forcedTechnique = null; @@ -116,7 +117,6 @@ public class RenderManager { private int singlePassLightBatchSize = 1; private MatParamOverride boundDrawBufferId = new MatParamOverride(VarType.Int, "BoundDrawBuffer", 0); private Predicate renderFilter; - private int captureLifetime = 0; /** * Creates a high-level rendering interface over the @@ -127,62 +127,88 @@ public class RenderManager { public RenderManager(Renderer renderer) { this.renderer = renderer; this.forcedOverrides.add(boundDrawBufferId); - this.renderObjects = new RenderObjectMap(this, true); + contexts.put(PipelineContext.class, new DefaultPipelineContext()); } /** - * Gets the default FrameGraph used when a ViewPort does not have a - * FrameGraph already assigned to it. + * Gets the default pipeline used when a ViewPort does not have a + * pipeline already assigned to it. * * @return */ - public FrameGraph getFrameGraph() { - return frameGraph; + public RenderPipeline getPipeline() { + return defaultPipeline; } /** - * Sets the default FrameGraph used when a ViewPort does not have a - * FrameGraph already assigned to it. + * Sets the default pipeline used when a ViewPort does not have a + * pipeline already assigned to it. *

      - * If null, ViewPorts without FrameGraphs will be rendered using the standard - * forward renderer. + * default={@link ForwardPipeline} * - * @param frameGraph default FrameGraph, or null + * @param pipeline default pipeline (not null) */ - public void setFrameGraph(FrameGraph frameGraph) { - this.frameGraph = frameGraph; + public void setPipeline(RenderPipeline pipeline) { + this.defaultPipeline = pipeline; } /** - * Gets the map that stores and manages rendering objects used by FrameGraphs. + * Gets the default pipeline context registered under + * {@link PipelineContext#getClass()}. * * @return */ - public RenderObjectMap getRenderObjectMap() { - return renderObjects; + public PipelineContext getDefaultContext() { + return getContext(PipelineContext.class); } /** - * Sets the frame capture that captures relevant framegraph rendering events. + * Gets the pipeline context registered under the class. * - * @param frameCapture - * @param frames - */ - public void setGraphCapture(GraphEventCapture frameCapture, int frames) { - this.graphCapture = frameCapture; - this.captureLifetime = frames; - if (this.captureLifetime <= 0) { - this.graphCapture = null; + * @param + * @param type + * @return + */ + public T getContext(Class type) { + return (T)contexts.get(type); + } + + /** + * Gets the pipeline context registered under the class or creates + * and registers a new context supplied by the supplier. + * + * @param + * @param type + * @param supplier + * @return + */ + public T getOrCreateContext(Class type, Supplier supplier) { + T c = getContext(type); + if (c == null) { + c = supplier.get(); + contexts.put(type, c); } + return c; + } + + /** + * Registers the pipeline context under the class. + * + * @param + * @param type + * @param context + */ + public void registerContext(Class type, T context) { + contexts.put(type, context); } /** - * Gets the frame capture that captures relevant framegraph rendering events. + * Gets the application profiler. * * @return */ - public GraphEventCapture getGraphCapture() { - return graphCapture; + public AppProfiler getProfiler() { + return prof; } /** @@ -1233,6 +1259,23 @@ public void renderViewPortRaw(ViewPort vp) { flushQueue(vp); } + /** + * Applies the ViewPort's Camera and FrameBuffer in preparation + * for rendering. + * + * @param vp + */ + public void applyViewPort(ViewPort 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()); + } + } + /** * Renders the {@link ViewPort}. * @@ -1279,123 +1322,16 @@ public void renderViewPortRaw(ViewPort vp) { public void renderViewPort(ViewPort vp, float tpf) { if (!vp.isEnabled()) { return; + } + RenderPipeline pipeline = vp.getFrameGraph(); + if (pipeline == null) { + pipeline = defaultPipeline; } - - if (prof != null) { - prof.vpStep(VpStep.BeginRender, vp, null); - } - - SafeArrayList processors = vp.getProcessors(); - if (processors.isEmpty()) { - processors = null; - } - - FrameGraph fg = null; - if (vp.isUseFrameGraphs()) { - fg = vp.getFrameGraph(); - if (fg == null) { - fg = frameGraph; - } + PipelineContext context = pipeline.fetchPipelineContext(this); + if (context.addPipeline(this, pipeline)) { + usedContexts.add(context); } - - if (prof != null && (fg != null || processors != null)) { - prof.vpStep(VpStep.PreFrame, vp, null); - } - if (fg != null) { - fg.configure(this, vp, prof, tpf); - //fg.preFrame(); - } else if (processors != null) { - for (SceneProcessor p : processors.getArray()) { - if (!p.isInitialized()) { - p.initialize(this, vp); - } - p.setProfiler(this.prof); - if (prof != null) { - prof.spStep(SpStep.ProcPreFrame, p.getClass().getSimpleName()); - } - p.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()); - } - - if (fg != null) { - // returns true on first execution this frame - if (fg.execute()) { - executedFrameGraphs.add(fg); - } - } else { - - if (prof != null) { - prof.vpStep(VpStep.RenderScene, vp, null); - } - // flatten scenes into render queue - 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 p : processors.getArray()) { - if (prof != null) { - prof.spStep(SpStep.ProcPostQueue, p.getClass().getSimpleName()); - } - p.postQueue(vp.getQueue()); - } - } - - if (prof != null) { - prof.vpStep(VpStep.FlushQueue, vp, null); - } - flushQueue(vp); - - 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); - } - } - - // render the translucent objects queue after processors have been rendered - renderTranslucentQueue(vp); - - // clear any remaining spatials that were not rendered. - clearQueue(vp); - - } - - // clear all reservations made - if (fg != null) { - renderObjects.clearReservations(); - } - - /* - * the call to setCamera will indirectly cause a clipRect to be set, must be cleared to avoid surprising results - * if renderer#copyFrameBuffer is used later - */ - renderer.clearClipRect(); - - if (prof != null) { - prof.vpStep(VpStep.EndRender, vp, null); - } - + pipeline.pipelineRender(this, context, vp, tpf); } /** @@ -1418,12 +1354,7 @@ public void render(float tpf, boolean mainFrameBufferActive) { return; } - if (graphCapture != null) { - graphCapture.startRenderFrame(); - } - uniformBindingManager.newFrame(); - renderObjects.newFrame(); if (prof != null) { prof.appStep(AppStep.RenderPreviewViewPorts); @@ -1455,28 +1386,13 @@ public void render(float tpf, boolean mainFrameBufferActive) { } } - if (graphCapture != null) { - graphCapture.endRenderFrame(); - } - - // cleanup for executed framegraphs only - for (FrameGraph fg : executedFrameGraphs) { - fg.renderingComplete(); - } - executedFrameGraphs.clear(); - - // flush object map - renderObjects.flushMap(); - - // tick frame capture - if (graphCapture != null && --captureLifetime <= 0) { - try { - graphCapture.export(); - } catch (IOException ex) { - Logger.getLogger(RenderManager.class.getName()).log(Level.SEVERE, null, ex); - } - graphCapture = null; + // cleanup for used pipeline contexts only + System.out.println("flush pipelines"); + for (PipelineContext c : usedContexts) { + System.out.println("flush pipeline stack for "+c); + c.flushPipelineStack(this); } + usedContexts.clear(); } @@ -1506,6 +1422,7 @@ public void setPassDrawBufferTargetIdToShaders(boolean v) { this.forcedOverrides.remove(boundDrawBufferId); } } + /** * Set a render filter. Every geometry will be tested against this filter * before rendering and will only be rendered if the filter returns true. diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderPipeline.java b/jme3-core/src/main/java/com/jme3/renderer/RenderPipeline.java new file mode 100644 index 0000000000..3aa658016a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderPipeline.java @@ -0,0 +1,58 @@ +/* + * 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; + +/** + * Renders a ViewPort. + * + * @author codex + * @param + */ +public interface RenderPipeline { + + /** + * Fetches the PipelineContext this pipeline requires for rendering + * from the RenderManager. + * + * @param rm + * @return pipeline context (not null) + */ + public T fetchPipelineContext(RenderManager rm); + + /** + * Returns true if this pipeline has rendered a viewport this render frame. + * + * @return + */ + public boolean hasRenderedThisFrame(); + + /** + * Called before this pipeline is rendered for the first time this frame. + *

      + * Only called if the pipeline will actually be rendered. + * + * @param rm + */ + public void beginRenderFrame(RenderManager rm); + + /** + * Renders the pipeline. + * + * @param rm + * @param context + * @param vp + * @param tpf + */ + public void pipelineRender(RenderManager rm, T context, ViewPort vp, float tpf); + + /** + * Called after all rendering is complete in a rendering frame this + * pipeline participated in. + * + * @param rm + */ + public void endRenderFrame(RenderManager rm); + +} 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 530fb87f68..f553980a8f 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java +++ b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java @@ -33,7 +33,6 @@ 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; 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 dbb2bb6bb2..3756dfb588 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java +++ b/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java @@ -111,7 +111,6 @@ public class ViewPort { */ protected boolean clearStencil = false; private boolean enabled = true; - private boolean useFrameGraphs = true; /** * Creates a new viewport. User code should generally use these methods instead:
      @@ -454,28 +453,5 @@ public void setFrameGraph(FrameGraph framegraph) { public FrameGraph getFrameGraph() { return framegraph; } - - /** - * Enables this viewport to use framegraphs when rendering. - *

      - * If false, the default forward renderer will always be used to - * render this viewport. - *

      - * default=true - * - * @param useFrameGraphs - */ - public void setUseFrameGraphs(boolean useFrameGraphs) { - this.useFrameGraphs = useFrameGraphs; - } - - /** - * Returns true if framegraphs can be used to render this viewport. - * - * @return - */ - public boolean isUseFrameGraphs() { - return useFrameGraphs; - } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/Connectable.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/Connectable.java new file mode 100644 index 0000000000..6ec9f5c812 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/Connectable.java @@ -0,0 +1,75 @@ +/* + * 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 codex + */ +public interface Connectable { + + public ResourceTicket getInput(String name); + + public ResourceTicket getOutput(String name); + + public TicketGroup getGroup(String name); + + public ResourceTicket addListEntry(String groupName); + + public default ResourceTicket getInput(String name, boolean failOnMiss) { + ResourceTicket t = getInput(name); + if (t == null && failOnMiss) { + throw new NullPointerException("Input ticket \""+name+"\" does not exist."); + } + return t; + } + + public default ResourceTicket getOutput(String name, boolean failOnMiss) { + ResourceTicket t = getOutput(name); + if (t == null && failOnMiss) { + throw new NullPointerException("Output ticket \""+name+"\" does not exist."); + } + return t; + } + + public default TicketGroup getGroup(String name, boolean failOnMiss) { + TicketGroup g = getGroup(name); + if (g == null && failOnMiss) { + throw new NullPointerException("Group \""+name+"\" does not exist."); + } + return g; + } + + public default void makeInput(Connectable source, String sourceTicket, String targetTicket) { + ResourceTicket out = source.getOutput(sourceTicket, true); + if (TicketGroup.isListTicket(targetTicket)) { + ResourceTicket t = addListEntry(TicketGroup.extractGroupName(targetTicket)); + t.setSource(out); + } else { + ResourceTicket target = getInput(targetTicket, true); + target.setSource(out); + } + } + + public default void makeGroupInput(Connectable source, String sourceGroup, String targetGroup, int sourceStart, int targetStart, int length) { + ResourceTicket[] sourceArray = source.getGroup(sourceGroup, true).getArray(); + ResourceTicket[] targetArray = getGroup(targetGroup, true).getArray(); + int n = Math.min(sourceStart+length, sourceArray.length); + int m = Math.min(targetStart+length, targetArray.length); + for (; sourceStart < n && targetStart < m; sourceStart++, targetStart++) { + targetArray[targetStart].setSource(sourceArray[sourceStart]); + } + } + + public default void makeGroupInput(Connectable source, String sourceGroup, String targetGroup) { + makeGroupInput(source, sourceGroup, targetGroup, 0, 0, Integer.MAX_VALUE); + } + + public default void makeInputToList(Connectable source, String sourceTicket, String targetGroup) { + ResourceTicket t = addListEntry(targetGroup); + t.setSource(source.getOutput(sourceTicket)); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPipelineContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPipelineContext.java new file mode 100644 index 0000000000..aeabc75a22 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPipelineContext.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.AbstractPipelineContext; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.framegraph.debug.GraphEventCapture; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Manages global pipeline context for rendering with FrameGraphs. + * + * @author codex + */ +public class FGPipelineContext extends AbstractPipelineContext { + + private static final Logger LOG = Logger.getLogger(FGPipelineContext.class.getName()); + + private final RenderObjectMap renderObjects; + private GraphEventCapture eventCapture; + + public FGPipelineContext(RenderManager rm) { + renderObjects = new RenderObjectMap(this, true); + } + + @Override + public void beginRenderFrame(RenderManager rm) { + if (eventCapture != null) { + eventCapture.beginRenderFrame(); + } + renderObjects.newFrame(); + } + @Override + public void endRenderFrame(RenderManager rm) { + if (eventCapture != null) { + eventCapture.endRenderFrame(); + } + renderObjects.flushMap(); + if (eventCapture != null && eventCapture.isComplete()) { + try { + eventCapture.export(); + } catch (IOException ex) { + LOG.log(Level.SEVERE, "Error exporting captured event data.", ex); + } + eventCapture = null; + } + } + + public void setEventCapture(GraphEventCapture eventCapture) { + this.eventCapture = eventCapture; + } + + public RenderObjectMap getRenderObjects() { + return renderObjects; + } + public GraphEventCapture getEventCapture() { + return eventCapture; + } + +} 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 8a11990269..2987c0279c 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 @@ -47,6 +47,7 @@ import com.jme3.texture.Texture2D; import java.util.function.Predicate; import com.jme3.renderer.GeometryRenderHandler; +import com.jme3.renderer.RendererException; /** * Context for FrameGraph rendering. @@ -73,6 +74,7 @@ public class FGRenderContext { private final FrameGraph frameGraph; private RenderManager renderManager; + private FGPipelineContext context; private ViewPort viewPort; private AppProfiler profiler; private float tpf; @@ -101,12 +103,14 @@ public FGRenderContext(FrameGraph frameGraph, Context clContext) { * Targets this context to the viewport. * * @param rm + * @param context * @param vp * @param profiler * @param tpf */ - public void target(RenderManager rm, ViewPort vp, AppProfiler profiler, float tpf) { + public void target(RenderManager rm, FGPipelineContext context, ViewPort vp, AppProfiler profiler, float tpf) { this.renderManager = rm; + this.context = context; this.viewPort = vp; this.profiler = profiler; this.tpf = tpf; @@ -234,6 +238,14 @@ public void setCLQueue(CommandQueue clQueue) { this.clQueue = clQueue; } + /** + * Gets the resource list belonging to the framegraph. + * + * @return + */ + public ResourceList getResources() { + return frameGraph.getResources(); + } /** * Gets the render manager. * @@ -242,6 +254,14 @@ public void setCLQueue(CommandQueue clQueue) { public RenderManager getRenderManager() { return renderManager; } + /** + * Gets the context for the FrameGraph pipeline. + * + * @return + */ + public FGPipelineContext getPipelineContext() { + return context; + } /** * Gets the viewport currently being rendered. * @@ -292,7 +312,7 @@ public FullScreenQuad getScreen() { * @return */ public GraphEventCapture getGraphCapture() { - return renderManager.getGraphCapture(); + return context.getEventCapture(); } /** * Gets the OpenCL context for compute shading. @@ -334,6 +354,14 @@ public int getWidth() { public int getHeight() { return viewPort.getCamera().getHeight(); } + /** + * Returns true if the FrameGraph is asynchronous. + * + * @return + */ + public boolean isAsync() { + return frameGraph.isAsync(); + } /** * Returns true if the app profiler is not null. @@ -349,7 +377,7 @@ public boolean isProfilerAvailable() { * @return */ public boolean isGraphCaptureActive() { - return renderManager.getGraphCapture() != null; + return context.getEventCapture() != null; } } 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 bf56cc70f9..f21f910af5 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 @@ -31,24 +31,28 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.framegraph.modules.ModuleLocator; +import com.jme3.renderer.framegraph.modules.RenderThread; +import com.jme3.renderer.framegraph.modules.ThreadLauncher; +import com.jme3.renderer.framegraph.modules.RenderModule; +import com.jme3.renderer.framegraph.export.ModuleGraphData; import com.jme3.renderer.framegraph.passes.RenderPass; import com.jme3.asset.AssetManager; import com.jme3.asset.FrameGraphKey; +import com.jme3.export.SavableObject; import com.jme3.opencl.CommandQueue; import com.jme3.opencl.Context; import com.jme3.profile.AppProfiler; -import com.jme3.profile.FgStep; import com.jme3.profile.VpStep; import com.jme3.renderer.RenderManager; -import com.jme3.renderer.RendererException; +import com.jme3.renderer.RenderPipeline; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.client.GraphSetting; import com.jme3.renderer.framegraph.debug.GraphEventCapture; -import com.jme3.renderer.framegraph.passes.Attribute; -import java.util.ArrayList; +import com.jme3.renderer.framegraph.export.FrameGraphData; import java.util.HashMap; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; +import java.util.logging.Logger; /** * Manages render passes, dependencies, and resources in a node-based parameter system. @@ -88,22 +92,21 @@ * * @author codex */ -public class FrameGraph { +public class FrameGraph implements RenderPipeline { - /** - * Index of the {@link PassThread} running on the main render thread. - */ - public static final int RENDER_THREAD = 0; + private static final Logger LOG = Logger.getLogger(FrameGraph.class.getName()); private final AssetManager assetManager; private final ResourceList resources; private final FGRenderContext context; - private final ArrayList threads = new ArrayList<>(1); private final HashMap settings = new HashMap<>(); - private final AtomicInteger incompleteQueues = new AtomicInteger(0); + private ThreadLauncher launcher = new ThreadLauncher(); private String name = "FrameGraph"; + private String docAsset = null; private boolean rendered = false; - private Exception renderException; + private boolean debugPrint = false; + private boolean interrupted = false; + private int nextModuleId = 0; /** * Creates a new blank framegraph. @@ -114,7 +117,8 @@ public FrameGraph(AssetManager assetManager) { this.assetManager = assetManager; this.resources = new ResourceList(this); this.context = new FGRenderContext(this); - this.threads.add(new PassThread(this, RENDER_THREAD)); + launcher.initializeModule(this); + launcher.getOrCreate(PassIndex.MAIN_THREAD); } /** * Creates a new framegraph from the given data. @@ -145,123 +149,91 @@ public FrameGraph(AssetManager assetManager, String dataAsset) { this(assetManager, assetManager.loadFrameGraph(dataAsset)); } - /** - * Configures the rendering context. - *

      - * Called automatically by the RenderManager before calling {@link #execute()}. - * - * @param rm - * @param vp viewport to render (not null) - * @param prof profiler (may be null) - * @param tpf time per frame - */ - public void configure(RenderManager rm, ViewPort vp, AppProfiler prof, float tpf) { - resources.setRenderManager(rm); - context.target(rm, vp, prof, tpf); + @Override + public FGPipelineContext fetchPipelineContext(RenderManager rm) { + return rm.getOrCreateContext(FGPipelineContext.class, () -> new FGPipelineContext(rm)); } - /** - * Executes this framegraph. - *

      - * The overall execution step occurs in 4 stages: - *

        - *
      1. Preparation.
      2. - *
      3. Culling.
      4. - *
      5. Rendering (execution).
      6. - *
      7. Clean (reset).
      8. - *
      - * - * @return true if this is the first execution of this FrameGraph this frame - */ - public boolean execute() { + @Override + public void beginRenderFrame(RenderManager rm) {} + @Override + public void pipelineRender(RenderManager rm, FGPipelineContext pContext, ViewPort vp, float tpf) { + + if (interrupted) { + throw new IllegalStateException("Cannot render because FrameGraph crashed."); + } + + AppProfiler prof = rm.getProfiler(); + if (prof != null) { + prof.vpStep(VpStep.BeginRender, vp, null); + } + // prepare - ViewPort vp = context.getViewPort(); - AppProfiler prof = context.getProfiler(); + rm.applyViewPort(vp); + context.target(rm, pContext, vp, prof, tpf); GraphEventCapture cap = context.getGraphCapture(); if (cap != null) { cap.renderViewPort(context.getViewPort()); } if (prof != null) prof.vpStep(VpStep.FrameGraphSetup, vp, null); if (!rendered) { - resources.beginRenderingSession(); - } - for (PassThread queue : threads) { - for (RenderPass p : queue) { - if (prof != null) prof.fgStep(FgStep.Prepare, p.getProfilerName()); - if (cap != null) cap.prepareRenderPass(p.getIndex(), p.getProfilerName()); - p.prepareRender(context); - } + resources.beginRenderFrame( + pContext.getRenderObjects(), pContext.getEventCapture()); } + launcher.prepareModuleRender(context, new PassIndex(0, 0)); resources.applyFutureReferences(); - // cull passes and resources + + // cull modules and resources if (prof != null) prof.vpStep(VpStep.FrameGraphCull, vp, null); - for (PassThread queue : threads) { - for (RenderPass p : queue) { - p.countReferences(); - } - } + launcher.countReferences(); resources.cullUnreferenced(); + // execute if (prof != null) prof.vpStep(VpStep.FrameGraphExecute, vp, null); context.pushRenderSettings(); - renderException = null; - incompleteQueues.set(threads.size()); - for (int i = threads.size()-1; i >= 0; i--) { - threads.get(i).execute(context); - } - if (renderException != null) { - renderException.printStackTrace(System.err); - throw new RendererException("An uncaught rendering exception occured, forcing the application to shut down."); + // execute threads in reverse order so that the 0th thread is executed + // last on JME's main thread. + launcher.executeModuleRender(context); + if (interrupted) { + throw new RuntimeException("FrameGraph execution was interrupted."); } context.popFrameBuffer(); + // reset if (prof != null) prof.vpStep(VpStep.FrameGraphReset, vp, null); - for (PassThread queue : threads) { - for (RenderPass p : queue) { - if (prof != null) prof.fgStep(FgStep.Reset, p.getProfilerName()); - p.resetRender(context); - } - } - // cleanup resources + launcher.resetRender(context); + pContext.getRenderObjects().clearReservations(); resources.clear(); - if (rendered) return false; - else return (rendered = true); - } - /** - * Called automatically by the RenderManager after all rendering operations are - * complete and this FrameGraph executed at least once this frame. - */ - public void renderingComplete() { - // notify passes - for (PassThread queue : threads) { - for (RenderPass p : queue) { - p.renderingComplete(); - } + rm.getRenderer().clearClipRect(); + rendered = true; + + if (prof != null) { + prof.vpStep(VpStep.EndRender, vp, null); } - // reset flags + + } + @Override + public boolean hasRenderedThisFrame() { + return rendered; + } + @Override + public void endRenderFrame(RenderManager rm) { + launcher.renderingComplete(); rendered = false; } - - private PassThread getQueue(int i) { - if (i >= threads.size()) { - PassThread queue = new PassThread(this, i); - threads.add(queue); - return queue; - } else if (i >= 0) { - return threads.get(i); - } else { - return threads.get(RENDER_THREAD); - } + @Override + public String toString() { + return "FrameGraph ("+name+")"; } /** * Adds the pass to end of the {@link PassThread} running on the main render thread. * * @param - * @param pass + * @param module * @return given pass */ - public T add(T pass) { - return getQueue(RENDER_THREAD).add(pass); + public T add(T module) { + return launcher.getOrCreate(PassIndex.MAIN_THREAD).add(module); } /** * Adds the pass at the index. @@ -278,8 +250,8 @@ public T add(T pass) { * @param index * @return */ - public T add(T pass, PassIndex index) { - return getQueue(index.getThreadIndex()).add(pass, index); + public T add(T pass, PassIndex index) { + return launcher.getOrCreate(index.getThreadIndex()).add(pass, index.queueIndex); } /** @@ -294,15 +266,15 @@ public T add(T pass, PassIndex index) { * * @param * @param array array of passes (elements may be null) - * @param function creates passes where array elements are null (may be null) + * @param factory creates passes where array elements are null (may be null) * @param inTicket name of the input ticket on each pass * @param outTicket name of the output ticket on each pass * @return array of passes * @see PassThread#addLoop(T[], int, java.util.function.Supplier, java.lang.String, java.lang.String) */ - public T[] addLoop(T[] array, Function function, + public T[] addLoop(T[] array, Function factory, String inTicket, String outTicket) { - return threads.get(RENDER_THREAD).addLoop(array, PassIndex.PASSIVE, function, inTicket, outTicket); + return launcher.getOrCreate(PassIndex.MAIN_THREAD).addLoop(array, -1, factory, inTicket, outTicket); } /** * Adds an array of passes connected in series to the framegraph. @@ -321,31 +293,8 @@ public T[] addLoop(T[] array, Function functi */ public T[] addLoop(T[] array, PassIndex index, Function function, String inTicket, String outTicket) { - return threads.get(index.getThreadIndex()).addLoop(array, index, function, inTicket, outTicket); - } - - /** - * Adds the passes from the given framegraph to this framegraph. - *

      - * The retargeting array determines where each pass thread in the given - * framegraph is added. - * - * @param frameGraph - * @param retarget indices to retarget threads to (not null, elements unaffected) - */ - public void add(FrameGraph frameGraph, PassIndex... retarget) { - final PassIndex index = new PassIndex(); - for (int i = 0; i < frameGraph.threads.size(); i++) { - PassThread source = frameGraph.threads.get(i); - index.set(retarget[i]); - PassThread target = getQueue(index.threadIndex); - for (RenderPass p : source) { - target.add(p, index); - if (!index.useDefaultThread()) { - index.queueIndex++; - } - } - } + return launcher.getOrCreate(index.getThreadIndex()).addLoop( + array, index.queueIndex, function, inTicket, outTicket); } /** @@ -355,52 +304,8 @@ public void add(FrameGraph frameGraph, PassIndex... retarget) { * @param by * @return first qualifying pass, or null */ - public T get(PassLocator by) { - for (PassThread q : threads) { - T a = q.get(by); - if (a != null) { - return a; - } - } - return null; - } - - /** - * Removes the pass at the index in the main {@link PassThread} (running on the main render thread). - *

      - * Passes above the removed pass will have their indexes shifted. - * - * @param i - * @return removed pass - * @throws IndexOutOfBoundsException if the index is less than zero or >= the queue size - */ - public RenderPass remove(int i) { - return threads.get(RENDER_THREAD).remove(i); - } - /** - * Removes the given pass from this FrameGraph. - *

      - * Passes above the removed pass will have their indices shifted to - * accomodate. - * - * @param pass - * @return true if the pass was removed from the queue - */ - public boolean remove(RenderPass pass) { - for (PassThread queue : threads) { - if (queue.remove(pass)) { - return true; - } - } - return false; - } - /** - * Clears all passes from this FrameGraph. - */ - public void clear() { - for (PassThread queue : threads) { - queue.clear(); - } + public T get(ModuleLocator by) { + return launcher.get(by); } /** @@ -425,32 +330,28 @@ public T setSetting(String name, T object) { * @param * @param name * @param object + * @param defaultValue * @param create true to create a GraphSetting, otherwise one will not be created and null returned * @return created graph setting * @see #setSetting(java.lang.String, java.lang.Object) */ - public GraphSetting setSetting(String name, T object, boolean create) { + public GraphSetting setSetting(String name, T object, T defaultValue) { setSetting(name, object); - if (create) { - return new GraphSetting<>(name); - } else { - return null; - } + return new GraphSetting<>(name, defaultValue); } /** * Sets an integer in the settings map based on a boolean value. *

      - * If the boolean is true, 0 is written, otherwise -1 is written. This is - * used primarily for Junction sources: 0 points to the first input, and -1 - * points to no input. + * If the boolean is true, 0 is written, otherwise -1 is written. Commonly + * used to enable/disable features by switching a Junction to 0 or -1. * * @param name - * @param value + * @param enable * @return * @see #setSetting(java.lang.String, java.lang.Object) */ - public int setJunctionSetting(String name, boolean value) { - return setSetting(name, value ? 0 : -1); + public int enableFeature(String name, boolean enable) { + return setSetting(name, enable ? 0 : -1); } /** * Gets the object registered under the name in the settings map, @@ -502,6 +403,15 @@ public HashMap getSettingsMap() { public void setName(String name) { this.name = name; } + /** + * Sets the asset path corresponding to a documentation file for + * this FrameGraph. + * + * @param docs asset path, or null for no documentation + */ + public void setDocumentationAsset(String docs) { + this.docAsset = docs; + } /** * Sets the OpenCL context used for compute shading. * @@ -520,29 +430,34 @@ public void setCLContext(Context clContext) { public void setCLQueue(CommandQueue clQueue) { context.setCLQueue(clQueue); } + /** + * Enables printing of information useful for debugging. + *

      + * default=false + * + * @param debugPrint + */ + public void enableDebugPrint(boolean debugPrint) { + this.debugPrint = debugPrint; + } /** - * Called automatically to notify the FrameGraph that a {@link PassThread} has completed execution. + * Called automatically to notify the FrameGraph that a {@link RenderThread} has completed execution. * - * @param queue + * @param thread */ - public void notifyComplete(PassThread queue) { - if (incompleteQueues.decrementAndGet() == 1) { - for (PassThread q : threads) { - q.notifyLast(); - } - } + public void notifyThreadComplete(RenderThread thread) { + launcher.notifyThreadComplete(thread); } /** * Called automatically when a rendering exception occurs. * * @param ex */ - public void interruptRendering(Exception ex) { - assert ex != null : "Interrupting exception cannot be null."; - renderException = ex; - for (PassThread q : threads) { - q.interrupt(); + public void interruptRendering() { + if (!interrupted) { + interrupted = true; + launcher.interrupt(); } } @@ -594,46 +509,83 @@ public Context getCLContext() { public String getName() { return name; } + /** + * Returns an asset path corresponding to a documentation file for + * this FrameGraph. + * + * @return asset path, or null if no documentation is available + */ + public String getDocumantationAsset() { + return docAsset; + } /** * Returns true if this framegraph is running asynchronous {@link PassThread}s. * * @return */ public boolean isAsync() { - return threads.size() > 1; + return launcher.isAsync(); + } + /** + * + * @return + */ + public boolean isDebugPrintEnabled() { + return debugPrint; } /** * Applies the {@link FrameGraphData} to this FrameGraph. * * @param data - * @return this instance + * @return */ public final FrameGraph applyData(FrameGraphData data) { - data.apply(this); + name = data.getName(); + for (SavableObject obj : data.getSettings()) { + setSetting(obj.getName(), obj.getObject()); + } + return applyData(data.getModules()); + } + /** + * Applies the {@link ModuleGraphData} to this FrameGraph. + * + * @param data + * @return this instance + * @throws IllegalStateException if the tree root is already a member of a FrameGraph + */ + public final FrameGraph applyData(ModuleGraphData data) { + launcher.cleanupModule(); + launcher = data.getRootModule(ThreadLauncher.class); + if (launcher.isAssigned()) { + throw new IllegalStateException("Cannot apply tree root that is already a member of a FrameGraph."); + } + launcher.initializeModule(this); return this; } /** - * Applies the {@link FrameGraphData} to this FrameGraph. + * Applies the {@link ModuleGraphData} to this FrameGraph. * * @param data * @return this instance - * @throws ClassCastException if the object is not an instance of {@link FrameGraphData}. + * @throws ClassCastException if the object is not an instance of {@link ModuleGraphData}. * @throws NullPointerException if the object is null */ public FrameGraph applyData(Object data) { if (data != null) { if (data instanceof FrameGraphData) { return applyData((FrameGraphData)data); + } else if (data instanceof ModuleGraphData) { + return applyData((ModuleGraphData)data); } else { - throw new ClassCastException(data.getClass()+" cannot be cast to "+FrameGraphData.class); + throw new ClassCastException(data.getClass()+" cannot be accepted as usable data."); } } else { - throw new NullPointerException("Proxy cannot be null"); + throw new NullPointerException("Data cannot be null."); } } /** - * Loads and applies {@link FrameGraphData} from the key. + * Loads and applies {@link ModuleGraphData} from the key. * * @param key * @return @@ -642,7 +594,7 @@ public FrameGraph loadData(FrameGraphKey key) { return applyData(assetManager.loadFrameGraph(key)); } /** - * Loads and applies {@link FrameGraphData} at the specified asset path. + * Loads and applies {@link ModuleGraphData} at the specified asset path. * * @param assetPath * @return @@ -651,17 +603,21 @@ public FrameGraph loadData(String assetPath) { return applyData(assetManager.loadFrameGraph(assetPath)); } /** - * Creates exportable snapshot of this FrameGraph as {@link FrameGraphData}. + * Creates exportable snapshot of this FrameGraph as {@link ModuleGraphData}. * * @return */ - public FrameGraphData createData() { - return new FrameGraphData(this, threads, settings); + public ModuleGraphData createModuleData() { + return new ModuleGraphData(launcher); } - @Override - public String toString() { - return "FrameGraph ("+name+")"; + /** + * Returns the next unique module id for this FrameGraph. + * + * @return + */ + public final int getNextId() { + return nextModuleId++; } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java deleted file mode 100644 index ec40fe3f9e..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphData.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2024 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.export.InputCapsule; -import com.jme3.export.JmeExporter; -import com.jme3.export.JmeImporter; -import com.jme3.export.OutputCapsule; -import com.jme3.export.Savable; -import com.jme3.export.SavableObject; -import com.jme3.renderer.framegraph.passes.RenderPass; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; - -/** - * Holds FrameGraph snapshot data ready for import or export. - * - * @author codex - */ -public class FrameGraphData implements Savable { - - private static final String DEF_NAME = "FrameGraph"; - private static final ArrayList DEF_QUEUES = new ArrayList<>(0); - private static final SavablePassConnection[] DEF_CONNECTIONS = new SavablePassConnection[0]; - private static final HashMap DEF_SETTINGS = new HashMap<>(); - - private final boolean export; - private String name; - private ArrayList queues; - private SavablePassConnection[] connections; - private Map settings; - - public FrameGraphData() { - export = false; - } - public FrameGraphData(FrameGraph fg, ArrayList queues, Map settings) { - this.name = fg.getName(); - this.queues = queues; - this.settings = new HashMap<>(); - for (String key : settings.keySet()) { - this.settings.put(key, new SavableObject(settings.get(key))); - } - export = true; - } - - @Override - public void write(JmeExporter ex) throws IOException { - if (!export) { - throw new IllegalStateException("Data is import only."); - } - if (queues == null) { - throw new IllegalStateException("Data is already consumed."); - } - final HashMap idMap = new HashMap<>(); - final LinkedList list = new LinkedList<>(); - int nextId = 0; - // remap ids - for (PassThread q : queues) { - for (RenderPass p : q) { - p.setExportId(nextId++); - idMap.put(p.getId(), p.getExportId()); - } - } - // extract connections - for (PassThread q : queues) { - for (RenderPass p : q) for (ResourceTicket t : p.getInputTickets()) { - if (t.hasSource()) { - int outId = idMap.get(t.getSource().getPassId()); - list.add(new SavablePassConnection(p.getExportId(), outId, t.getName(), t.getSource().getName())); - } - } - } - OutputCapsule out = ex.getCapsule(this); - out.write(name, "name", DEF_NAME); - out.writeSavableArrayList(queues, "passes", DEF_QUEUES); - out.write(list.toArray(new SavablePassConnection[0]), "connections", DEF_CONNECTIONS); - out.writeStringSavableMap(settings, "settings", DEF_SETTINGS); - // reset export ids - for (PassThread q : queues) { - for (RenderPass p : q) { - p.setExportId(-1); - } - } - idMap.clear(); - list.clear(); - queues = null; - settings.clear(); - } - @Override - public void read(JmeImporter im) throws IOException { - if (export) { - throw new IllegalStateException("Data is export only."); - } - InputCapsule in = im.getCapsule(this); - name = in.readString("name", "FrameGraph"); - int baseId = RenderPass.getNextId(); - queues = in.readSavableArrayList("passes", DEF_QUEUES); - for (PassThread q : queues) { - for (RenderPass p : q) { - p.shiftId(baseId); - } - } - Savable[] array = in.readSavableArray("connections", new SavablePassConnection[0]); - connections = new SavablePassConnection[array.length]; - for (int i = 0; i < array.length; i++) { - SavablePassConnection c = connections[i] = (SavablePassConnection)array[i]; - c.shiftIds(baseId); - } - settings = (Map)in.readStringSavableMap("settings", DEF_SETTINGS); - } - - /** - * Applies internal data to the FrameGraph. - *

      - * This operation consumes the data. - * - * @param fg - */ - public void apply(FrameGraph fg) { - if (export) { - throw new IllegalStateException("Data is export only."); - } - if (queues == null) { - throw new IllegalStateException("Data has already been consumed."); - } - fg.setName(name); - // cache passes by id - HashMap cache = new HashMap<>(); - for (PassThread q : queues) { - for (RenderPass p : q) { - fg.add(p, new PassIndex().setThreadIndex(q.getIndex())); - cache.put(p.getId(), p); - } - } - // read connections - for (SavablePassConnection c : connections) { - RenderPass input = cache.get(c.getInputId()); - RenderPass output = cache.get(c.getOutputId()); - input.makeInput(output, c.getOutputTicket(), c.getInputTicket()); - } - // transfer settings - for (String key : settings.keySet()) { - fg.setSetting(key, settings.get(key).getObject()); - } - cache.clear(); - queues = null; - connections = null; - } - - /** - * Returns true if this data is export only, otherwise the data is import only. - * - * @return - */ - public boolean isExportOnly() { - return export; - } - - /** - * Returns true if this data has been consumed by completing an import - * or export. - *

      - * Attempting to import or export consumed data will result in an exception. - * - * @return - */ - public boolean isConsumed() { - return queues == null; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java index f051e7bc1f..df6dca5873 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraphFactory.java @@ -34,15 +34,7 @@ import com.jme3.asset.AssetManager; import com.jme3.renderer.framegraph.light.TiledRenderGrid; import com.jme3.renderer.framegraph.client.GraphSetting; -import com.jme3.renderer.framegraph.passes.Attribute; -import com.jme3.renderer.framegraph.passes.DeferredPass; -import com.jme3.renderer.framegraph.passes.GBufferPass; -import com.jme3.renderer.framegraph.passes.Junction; -import com.jme3.renderer.framegraph.passes.LightImagePass; -import com.jme3.renderer.framegraph.passes.OutputGeometryPass; -import com.jme3.renderer.framegraph.passes.OutputPass; -import com.jme3.renderer.framegraph.passes.QueueMergePass; -import com.jme3.renderer.framegraph.passes.SceneEnqueuePass; +import com.jme3.renderer.framegraph.passes.*; /** * Utility class for constructing common {@link FrameGraph}s in code. @@ -102,7 +94,7 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled, bool FrameGraph fg = new FrameGraph(assetManager); fg.setName(tiled ? "TiledDeferred" : "Deferred"); - int asyncThread = async ? 1 : FrameGraph.RENDER_THREAD; + int asyncThread = async ? 1 : PassIndex.MAIN_THREAD; SceneEnqueuePass enqueue = fg.add(new SceneEnqueuePass(true, true)); Attribute tileInfoAttr = fg.add(new Attribute()); @@ -118,18 +110,18 @@ public static FrameGraph deferred(AssetManager assetManager, boolean tiled, bool gbuf.makeInput(enqueue, "Opaque", "Geometry"); - GraphSetting tileInfo = fg.setSetting("TileInfo", new TiledRenderGrid(), true); + GraphSetting tileInfo = new GraphSetting<>("TileInfo", new TiledRenderGrid()); tileInfoAttr.setName("TileInfo"); tileInfoAttr.setSource(tileInfo); - GraphSetting tileToggle = fg.setSetting("TileToggle", tiled ? 0 : -1, true); + GraphSetting tileToggle = fg.setSetting("EnableLightTiles", tiled ? 0 : -1, -1); tileJunct1.makeInput(tileInfoAttr, Attribute.OUTPUT, Junction.getInput(0)); tileJunct1.setIndexSource(tileToggle); lightImg.makeInput(enqueue, "OpaqueLights", "Lights"); lightImg.makeInput(tileJunct1, Junction.getOutput(), "TileInfo"); - GraphSetting lightPackMethod = fg.setSetting("LightPackMethod", tiled ? 0 : -1, true); + GraphSetting lightPackMethod = fg.setSetting("EnableLightTextures", tiled ? 0 : -1, -1); lightJunct.setName("LightPackMethod"); lightJunct.makeGroupInput(lightImg, "Textures", Junction.getInput(0), 0, 0, 3); lightJunct.makeInput(lightImg, "NumLights", Junction.getInput(0, 3)); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java index c0c5145bd1..a2b793d91c 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GeometryQueue.java @@ -31,6 +31,7 @@ */ package com.jme3.renderer.framegraph; +import com.jme3.renderer.DepthRange; import com.jme3.renderer.Camera; import com.jme3.renderer.GeometryRenderHandler; import com.jme3.renderer.RenderManager; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphRenderException.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphRenderException.java new file mode 100644 index 0000000000..633a0f0cc3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphRenderException.java @@ -0,0 +1,18 @@ +/* + * 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; + +/** + * Raised when a fatal error occurs during FrameGraph processes. + * + * @author codex + */ +public class GraphRenderException extends RuntimeException { + + public GraphRenderException(String message) { + super(message); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java index 7e23f077e2..290a32d8ed 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassIndex.java @@ -43,10 +43,15 @@ */ public final class PassIndex { + /** + * Index of the main render thread. + */ + public static final int MAIN_THREAD = 0; + /** * Index that conforms to defaults only. */ - public static final PassIndex PASSIVE = new PassIndex(-1, -1); + public static final PassIndex DEFAULT = new PassIndex(); /** * Index of the thread the pass is executed on. @@ -61,14 +66,14 @@ public final class PassIndex { * Creates a pass index with all defaults (negative indices). */ public PassIndex() { - this(-1, -1); + this(MAIN_THREAD, -1); } /** * * @param queueIndex */ public PassIndex(int queueIndex) { - this(FrameGraph.RENDER_THREAD, queueIndex); + this(MAIN_THREAD, queueIndex); } /** * @@ -174,12 +179,12 @@ public int getQueueIndex() { } /** - * Returns true if the default thread index is used (thread index is negative). + * Returns true if this thread index matches the main thread index * * @return */ - public boolean useDefaultThread() { - return threadIndex < 0; + public boolean isMainThread() { + return threadIndex == MAIN_THREAD; } /** * Returns true if the default queue index is used (queue index is negative). diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.java deleted file mode 100644 index d47b79cc83..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassThread.java +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright (c) 2024 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.export.InputCapsule; -import com.jme3.export.JmeExporter; -import com.jme3.export.JmeImporter; -import com.jme3.export.OutputCapsule; -import com.jme3.export.Savable; -import com.jme3.profile.FgStep; -import com.jme3.renderer.framegraph.passes.Attribute; -import com.jme3.renderer.framegraph.passes.RenderPass; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Objects; -import java.util.function.Function; - -/** - * A queue of RenderPasses executing on a particular thread. - *

      - * The primary PassThread runs on the main JME render thread. - * - * @author codex - */ -public class PassThread implements Runnable, Iterable, Savable { - - private static long threadTimeoutMillis = 5000; - private static int threadTimeoutAttempts = 100; - private static final ArrayList DEF_QUEUE = new ArrayList<>(0); - - private final FrameGraph frameGraph; - private final LinkedList queue = new LinkedList<>(); - private int index; - private Thread thread; - private FGRenderContext context; - private boolean async = false; - private boolean interrupted = false; - - /** - * Serialization only. - */ - public PassThread() { - frameGraph = null; - } - /** - * - * @param frameGraph - * @param index - */ - public PassThread(FrameGraph frameGraph, int index) { - this.frameGraph = frameGraph; - this.index = index; - } - - @Override - public void run() { - try { - boolean main = isMainThread(); - for (RenderPass p : queue) { - if (interrupted) { - return; - } - if (!p.isUsed()) { - continue; - } - if (main) { - if (context.isProfilerAvailable()) { - context.getProfiler().fgStep(FgStep.Execute, p.getProfilerName()); - } - if (context.isGraphCaptureActive()) { - context.getGraphCapture().executeRenderPass(p.getIndex(), p.getProfilerName()); - } - } - if (async) { - // wait until all input resources are available for use before executing - p.waitForInputs(threadTimeoutMillis, threadTimeoutAttempts); - } - p.executeRender(context); - if (main) { - context.popRenderSettings(); - } - } - frameGraph.notifyComplete(this); - } catch (Exception ex) { - if (!interrupted) { - frameGraph.interruptRendering(ex); - } - } - } - @Override - public Iterator iterator() { - return queue.iterator(); - } - @Override - public void write(JmeExporter ex) throws IOException { - OutputCapsule out = ex.getCapsule(this); - ArrayList list = new ArrayList<>(queue.size()); - list.addAll(queue); - out.writeSavableArrayList(list, "queue", DEF_QUEUE); - out.write(index, "index", 0); - } - @Override - public void read(JmeImporter im) throws IOException { - InputCapsule in = im.getCapsule(this); - queue.addAll(in.readSavableArrayList("queue", DEF_QUEUE)); - index = in.readInt("index", 0); - } - - /** - * Executes this queue with the context. - * - * @param context - */ - public void execute(FGRenderContext context) { - async = frameGraph.isAsync(); - this.context = context; - if (isMainThread()) { - run(); - } else { - thread = new Thread(this); - thread.start(); - } - } - - /** - * Notifies the queue that all other queues have completed execution. - */ - public void notifyLast() { - async = false; - } - /** - * Interrupts this queue from executing the next pass. - */ - public void interrupt() { - interrupted = true; - } - - /** - * Adds the pass to end of the pass queue. - * - * @param - * @param pass - * @return given pass - */ - public T add(T pass) { - Objects.requireNonNull(pass, "Pass to add cannot be null."); - queue.addLast(pass); - pass.initializePass(frameGraph, new PassIndex(index, queue.size()-1)); - return pass; - } - /** - * Adds the pass at the index in the pass queue. - *

      - * If the queue index is >= the current queue size, the pass will - * be added to the end of the queue. Passes above the added pass - * will have their queue indices shifted. - * - * @param - * @param pass - * @param index - * @return - */ - public T add(T pass, PassIndex index) { - Objects.requireNonNull(pass, "Pass to add cannot be null."); - int i = index.getQueueIndex(); - if (i < 0 || i >= queue.size()) { - return add(pass); - } - queue.add(i, pass); - pass.initializePass(frameGraph, new PassIndex(this.index, i)); - for (RenderPass p : queue) { - p.shiftExecutionIndex(i, true); - } - return pass; - } - /** - * Creates and adds an Attribute pass and links it to the given ticket. - *

      - * This is handy for quickly debugging various resources in the graph. - * - * @param - * @param ticket ticket to reference from - * @return created Attribute - */ - public Attribute addAttribute(ResourceTicket ticket) { - Attribute attr = add(new Attribute<>()); - attr.getInput(Attribute.INPUT).setSource(ticket); - return attr; - } - /** - * Adds a series (loop) of passes at the index. - *

      - * Passes in the loop are connecting the next and previous pass in the loop - * if they exist using the ticket names given. - * - * @param - * @param array - * @param index index to start adding passes at (unaffected) - * @param function creates render passes, or null to use what is already - * in the array. - * @param inTicket the input ticket for each pass to connect with the - * previous pass in the loop - * @param outTicket the output ticket for each pass to connect with - * the next pass in the loop - * @return pass array - */ - public T[] addLoop(T[] array, PassIndex index, - Function function, String inTicket, String outTicket) { - PassIndex ind = new PassIndex(index); - for (int i = 0; i < array.length; i++) { - if (function != null && array[i] == null) { - array[i] = function.apply(i); - } - if (index.queueIndex < 0) { - add(array[i]); - } else { - add(array[i], ind); - ind.queueIndex++; - } - if (i > 0) { - array[i].makeInput(array[i-1], outTicket, inTicket); - } - } - return array; - } - - /** - * Gets the first pass that qualifies. - * - * @param - * @param by - * @return first qualifying pass, or null - */ - public T get(PassLocator by) { - for (RenderPass p : queue) { - T a = by.accept(p); - if (a != null) { - return a; - } - } - return null; - } - - /** - * Removes the pass at the index in the queue. - *

      - * Passes above the removed pass will have their indexes shifted. - * - * @param i - * @return removed pass - * @throws IndexOutOfBoundsException if the index is less than zero or >= the queue size - */ - public RenderPass remove(int i) { - if (i < 0 || i >= queue.size()) { - throw new IndexOutOfBoundsException("Index "+i+" is out of bounds for size "+queue.size()); - } - int j = 0; - RenderPass removed = null; - for (Iterator it = queue.iterator(); it.hasNext();) { - RenderPass p = it.next(); - if (removed != null) { - p.disconnectInputsFrom(removed); - p.shiftExecutionIndex(i, false); - } else if (j++ == i) { - removed = p; - it.remove(); - } - } - if (removed != null) { - removed.cleanupPass(frameGraph); - } - return removed; - } - /** - * Removes the given pass from the queue. - *

      - * Passes above the removed pass will have their indexes shifted. - * - * @param pass - * @return true if the pass was removed from the queue - */ - public boolean remove(RenderPass pass) { - int i = 0; - boolean found = false; - for (Iterator it = queue.iterator(); it.hasNext();) { - RenderPass p = it.next(); - if (found) { - // shift execution indices down - p.disconnectInputsFrom(pass); - p.shiftExecutionIndex(i, false); - continue; - } - if (p == pass) { - it.remove(); - found = true; - } - i++; - } - if (found) { - pass.cleanupPass(frameGraph); - return true; - } - return false; - } - /** - * Clears all passes from the pass queue. - */ - public void clear() { - for (RenderPass p : queue) { - p.cleanupPass(frameGraph); - } - queue.clear(); - } - - /** - * Shifts the thread index if the thread index is above {@code i}. - * - * @param i - * @param pos - * @return - */ - public int shiftThreadIndex(int i, boolean pos) { - if (index > i) { - index += pos ? 1 : -1; - } - for (RenderPass p : queue) { - p.getIndex().shiftThread(i, pos); - } - return index; - } - - /** - * Gets the number of passes in this queue. - * - * @return - */ - public int size() { - return queue.size(); - } - /** - * Gets the thread index of this queue. - * - * @return - */ - public int getIndex() { - return index; - } - /** - * Returns true if this queue is running on the main render thread. - * - * @return - */ - public boolean isMainThread() { - return index == FrameGraph.RENDER_THREAD; - } - - /** - * Sets the duration, in milliseconds, that executors will wait - * for pass inputs to be available before aborting execution. - *

      - * Timeouts can only occur when multiple threads are running. - *

      - * default=5000 (5 seconds) - * - * @param threadTimeoutMillis - */ - public static void setThreadTimeoutMillis(long threadTimeoutMillis) { - PassThread.threadTimeoutMillis = threadTimeoutMillis; - } - /** - * Sets the maximum number of attempts executors will make - * for pass inputs to be available before aboring execution. - *

      - * default=100 - * - * @param threadTimeoutAttempts - */ - public static void setThreadTimeoutAttempts(int threadTimeoutAttempts) { - PassThread.threadTimeoutAttempts = threadTimeoutAttempts; - } - - /** - * - * @return - */ - public static long getThreadTimeoutMillis() { - return threadTimeoutMillis; - } - /** - * - * @return - */ - public static int getThreadTimeoutAttempts() { - return threadTimeoutAttempts; - } - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java index 491708c6c9..3120cffbfb 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderObjectMap.java @@ -46,7 +46,7 @@ */ public class RenderObjectMap { - private final RenderManager renderManager; + private final FGPipelineContext context; private final Map objectMap; private int staticTimeout = 1; @@ -62,11 +62,11 @@ public class RenderObjectMap { /** * - * @param renderManager + * @param context * @param async */ - public RenderObjectMap(RenderManager renderManager, boolean async) { - this.renderManager = renderManager; + public RenderObjectMap(FGPipelineContext context, boolean async) { + this.context = context; objectMap = new ConcurrentHashMap<>(); } @@ -107,7 +107,7 @@ private void allocateSync(ResourceView resource) { if (resource.isUndefined()) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); } - GraphEventCapture cap = renderManager.getGraphCapture(); + GraphEventCapture cap = context.getEventCapture(); totalAllocations++; ResourceDef def = resource.getDefinition(); if (def.isUseExisting()) { @@ -154,7 +154,7 @@ private void allocateSync(ResourceView resource) { objectsCreated++; } private boolean allocateSpecificSync(ResourceView resource) { - GraphEventCapture cap = renderManager.getGraphCapture(); + GraphEventCapture cap = context.getEventCapture(); ResourceDef def = resource.getDefinition(); long id = resource.getTicket().getObjectId(); if (id < 0) return false; @@ -162,7 +162,7 @@ private boolean allocateSpecificSync(ResourceView resource) { RenderObject obj = objectMap.get(id); if (obj != null) { if (cap != null) cap.attemptReallocation(id, resource.getIndex()); - if (isAvailable(obj) && (obj.claimReservation(resource.getProducer().getExecutionIndex()) + if (isAvailable(obj) && (obj.claimReservation(resource.getProducer().getIndex()) || !obj.isReservedWithin(resource.getLifeTime()))) { // reserved object is only applied if it is accepted by the definition T r = def.applyDirectResource(obj.getObject()); @@ -186,7 +186,7 @@ private void allocateAsync(ResourceView resource) { if (resource.isUndefined()) { throw new IllegalArgumentException("Cannot allocate object to an undefined resource."); } - GraphEventCapture cap = renderManager.getGraphCapture(); + GraphEventCapture cap = context.getEventCapture(); totalAllocations++; ResourceDef def = resource.getDefinition(); if (def.isUseExisting()) { @@ -275,7 +275,7 @@ private void allocateAsync(ResourceView resource) { objectsCreated++; } private boolean allocateSpecificAsync(ResourceView resource) { - GraphEventCapture cap = renderManager.getGraphCapture(); + GraphEventCapture cap = context.getEventCapture(); ResourceDef def = resource.getDefinition(); long id = resource.getTicket().getObjectId(); if (id < 0) return false; @@ -285,7 +285,7 @@ private boolean allocateSpecificAsync(ResourceView resource) { if (cap != null) cap.attemptReallocation(id, resource.getIndex()); if (isAvailable(obj)) synchronized (obj) { obj.startInspect(); - if (obj.claimReservation(resource.getProducer().getExecutionIndex()) + if (obj.claimReservation(resource.getProducer().getIndex()) || !obj.isReservedWithin(resource.getLifeTime())) { // reserved object is only applied if it is accepted by the definition T r = def.applyDirectResource(obj.getObject()); @@ -326,8 +326,8 @@ public boolean reserve(long objectId, PassIndex index) { if (obj != null) { obj.reserve(index); officialReservations++; - if (renderManager.getGraphCapture() != null) { - renderManager.getGraphCapture().reserveObject(objectId, index); + if (context.getEventCapture() != null) { + context.getEventCapture().reserveObject(objectId, index); } return true; } @@ -344,8 +344,8 @@ public void dispose(ResourceView resource) { RenderObject obj = objectMap.remove(id); if (obj != null) { obj.dispose(); - if (renderManager.getGraphCapture() != null) { - renderManager.getGraphCapture().disposeObject(id); + if (context.getEventCapture() != null) { + context.getEventCapture().disposeObject(id); } } } @@ -378,7 +378,7 @@ public void clearReservations() { */ public void flushMap() { totalObjects = objectMap.size(); - GraphEventCapture cap = renderManager.getGraphCapture(); + GraphEventCapture cap = context.getEventCapture(); if (cap != null) cap.flushObjects(totalObjects); for (Iterator it = objectMap.values().iterator(); it.hasNext();) { RenderObject obj = it.next(); @@ -407,7 +407,7 @@ public void flushMap() { * All tracked render objects are disposed. */ public void clearMap() { - GraphEventCapture cap = renderManager.getGraphCapture(); + GraphEventCapture cap = context.getEventCapture(); for (RenderObject obj : objectMap.values()) { if (cap != null) cap.disposeObject(obj.getId()); obj.dispose(); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java index ca6f7f7865..45e903c9f4 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceList.java @@ -38,7 +38,6 @@ import com.jme3.texture.Texture; import java.util.ArrayList; import java.util.LinkedList; -import java.util.concurrent.TimeoutException; /** * Manages {@link ResourceView} declarations, references, and @@ -53,6 +52,11 @@ public class ResourceList { */ private static final int INITIAL_SIZE = 20; + /** + * Maximum time to wait in milliseconds before throwing an exception. + */ + public static final long WAIT_TIMEOUT = 5000; + private final FrameGraph frameGraph; private RenderManager renderManager; private RenderObjectMap map; @@ -70,8 +74,8 @@ public ResourceList(FrameGraph frameGraph) { this.frameGraph = frameGraph; } - private ResourceView create(ResourceProducer producer, ResourceDef def) { - ResourceView res = new ResourceView<>(producer, def, new ResourceTicket<>()); + private ResourceView create(ResourceUser producer, ResourceDef def, String name) { + ResourceView res = new ResourceView<>(producer, def, new ResourceTicket<>(name)); res.getTicket().setLocalIndex(add(res)); return res; } @@ -159,12 +163,30 @@ public boolean validate(ResourceTicket ticket) { * @param store * @return */ - public ResourceTicket declare(ResourceProducer producer, ResourceDef def, ResourceTicket store) { - ResourceView resource = create(producer, def); - if (cap != null) cap.declareResource(resource.getIndex(), (store != null ? store.getName() : "")); + public ResourceTicket declare(ResourceUser producer, ResourceDef def, ResourceTicket store) { + String name = (store != null ? store.getName() : null); + ResourceView resource = create(producer, def, name); + if (cap != null) cap.declareResource(resource.getIndex(), name); return resource.getTicket().copyIndexTo(store); } + /** + * Declares a temporary resource with an unregistered ticket. + *

      + * Temporary resources do not participate in culling. + * + * @param + * @param producer + * @param def + * @param store + * @return + */ + public ResourceTicket declareTemporary(ResourceUser producer, ResourceDef def, ResourceTicket store) { + store = declare(producer, def, store); + locate(store).setTemporary(true); + return store; + } + /** * If the ticket contains a valid object ID, that render object will be reserved * at the index. @@ -195,14 +217,18 @@ public void reserve(PassIndex passIndex, ResourceTicket... tickets) { } } - private void reference(PassIndex passIndex, ResourceTicket ticket, boolean optional) { - ResourceView resource = locate(ticket, false); + private void reference(PassIndex index, ResourceTicket ticket, boolean optional) { + boolean sync = !frameGraph.isAsync(); + if (optional && sync && !ResourceTicket.validate(ticket)) { + return; + } + ResourceView resource = locate(ticket, sync); if (resource != null) { - resource.reference(passIndex); + resource.reference(index); if (cap != null) cap.referenceResource(resource.getIndex(), ticket.getName()); } else { // save for later, since the resource hasn't been declared yet - futureRefs.add(new FutureReference(passIndex, ticket, optional)); + futureRefs.add(new FutureReference(index, ticket, optional)); } } @@ -314,16 +340,6 @@ public void setConstantOptional(ResourceTicket ticket) { } } - /** - * Sets the resource at the ticket so that it cannot be culled - * by number of references. - * - * @param ticket - */ - public void setSurvivesReferenceCull(ResourceTicket ticket) { - locate(ticket).setSurvivesRefCull(true); - } - /** * Returns true if the resource associated with the ticket is virtual. *

      @@ -352,30 +368,23 @@ public boolean isVirtual(ResourceTicket ticket, boolean optional) { * * @param ticket ticket to locate resource with * @param thread current thread - * @param attempts - * @param timeoutMillis maximum wait time (in milliseconds) before throwing a timeout exception - * @throws java.util.concurrent.TimeoutException if wait times out */ - public void wait(ResourceTicket ticket, int thread, long timeoutMillis, int attempts) throws TimeoutException { + public void waitForResource(ResourceTicket ticket, int thread) { if (ResourceTicket.validate(ticket)) { - if (attempts <= 0) { - throw new TimeoutException("Thread "+thread+": Resource at "+ticket+" was assumed " - + "unreachable after a number of unsuccessful attempts."); - } // wait for resource to become available to this context long start = System.currentTimeMillis(); ResourceView res; // TODO: determine why not locating the resource on each try results in timeouts. while (!(res = fastLocate(ticket)).isReadAvailable()) { - if (System.currentTimeMillis()-start >= timeoutMillis) { - throw new TimeoutException("Thread "+thread+": Resource at "+ticket+" was assumed " - + "unreachable after "+timeoutMillis+" milliseconds."); + if (System.currentTimeMillis()-start >= WAIT_TIMEOUT) { + throw new IllegalStateException("Thread "+thread+": Resource at "+ticket+" was assumed " + + "unreachable after "+WAIT_TIMEOUT+" milliseconds."); } } // claim read permisions // for resources that are read concurrent, this won't matter if (!res.claimReadPermissions()) { - wait(ticket, thread, timeoutMillis, --attempts); + waitForResource(ticket, thread); } } } @@ -660,8 +669,12 @@ public void releaseOptional(ResourceTicket... tickets) { * Prepares this for rendering. *

      * This should only be called once per frame. + * @param map + * @param cap */ - public void beginRenderingSession() { + public void beginRenderFrame(RenderObjectMap map, GraphEventCapture cap) { + this.map = map; + this.cap = cap; textureBinds = 0; } @@ -686,20 +699,23 @@ public void applyFutureReferences() { public void cullUnreferenced() { LinkedList cull = new LinkedList<>(); for (ResourceView r : resources) { - if (r != null && !r.isReferenced() && !r.isSurvivesRefCull()) { + if (r != null && !r.isReferenced() && !r.isTemporary()) { cull.add(r); } } ResourceView resource; while ((resource = cull.pollFirst()) != null) { // dereference producer of resource - ResourceProducer producer = resource.getProducer(); + ResourceUser producer = resource.getProducer(); if (producer == null) { remove(resource.getIndex()); continue; } - if (!producer.dereference()) { - // if producer is not referenced, dereference all input resources + if (!producer.isUsed()) { + continue; + } + producer.dereference(); + if (!producer.isUsed()) { for (ResourceTicket t : producer.getInputTickets()) { if (!validate(t)) { continue; @@ -710,9 +726,10 @@ public void cullUnreferenced() { cull.addLast(r); } } - // remove all output resources for (ResourceTicket t : producer.getOutputTickets()) { - remove(t.getLocalIndex()); + if (!t.hasSource()) { + remove(t.getLocalIndex()); + } } } } @@ -742,17 +759,6 @@ public int getTextureBinds() { return textureBinds; } - /** - * Sets the render manager. - * - * @param renderManager - */ - public void setRenderManager(RenderManager renderManager) { - this.renderManager = renderManager; - this.map = this.renderManager.getRenderObjectMap(); - this.cap = this.renderManager.getGraphCapture(); - } - /** * Represents a reference to a resource that will exist in the future. */ diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java deleted file mode 100644 index a955ce3e33..0000000000 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceProducer.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2024 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.Collection; - -/** - * Interface for objects that use and produce resources. - * - * @author codex - */ -public interface ResourceProducer { - - /** - * Gets the index of execution. - * - * @return - */ - public PassIndex getExecutionIndex(); - - /** - * Dereferences this producer. - * - * @return - */ - public boolean dereference(); - - /** - * Returns true if this producer is used. - * - * @return - */ - public boolean isUsed(); - - /** - * Gets a collection of all input tickets. - * - * @return - */ - public Collection getInputTickets(); - - /** - * Gets a collection of all output tickets. - * - * @return - */ - public Collection getOutputTickets(); - -} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java index c7f01e64ba..6a36eea9aa 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceTicket.java @@ -31,6 +31,9 @@ */ package com.jme3.renderer.framegraph; +import java.util.Collection; +import java.util.LinkedList; + /** * References a {@link RenderResource} by index. *

      @@ -44,14 +47,17 @@ */ public class ResourceTicket { - private String name, groupName; - private int passId = -1; + public static final String RESERVED = "#"; + + private String name; private int localIndex; private long objectId = -1; private ResourceTicket source; + private final LinkedList> targets = new LinkedList<>(); + private int exportGroupId = -1; /** - * Creates a blank ticket with a negative local index. + * */ public ResourceTicket() { this(null, -1); @@ -64,25 +70,6 @@ public ResourceTicket() { public ResourceTicket(String name) { this(name, -1); } - /** - * Creates a ticket with the name, belonging to the named group, - * and with a negative local index. - * - * @param name - * @param groupName - */ - public ResourceTicket(String name, String groupName) { - this(name, -1); - this.groupName = groupName; - } - /** - * Creates a ticket with the local index. - * - * @param index - */ - public ResourceTicket(int index) { - this(null, index); - } /** * Creates a ticket with the name and local index. * @@ -94,6 +81,16 @@ public ResourceTicket(String name, int index) { this.localIndex = index; } + /** + * Clears all target tickets. + */ + public void clearAllTargets() { + for (ResourceTicket t : targets) { + t.source = null; + } + targets.clear(); + } + /** * Copies this ticket's resource index to the target ticket. * @@ -126,7 +123,13 @@ public ResourceTicket copyObjectTo(ResourceTicket target) { * @param source */ public void setSource(ResourceTicket source) { + if (this.source != null) { + this.source.targets.remove(this); + } this.source = source; + if (this.source != null) { + this.source.targets.add(this); + } } /** * Sets the name of this ticket. @@ -138,14 +141,6 @@ public ResourceTicket setName(String name) { this.name = name; return this; } - /** - * Sets the id of this pass this ticket belongs to. - * - * @param passId - */ - public void setPassId(int passId) { - this.passId = passId; - } /** * Sets the local index. *

      @@ -167,28 +162,23 @@ protected ResourceTicket setLocalIndex(int index) { public void setObjectId(long objectId) { this.objectId = objectId; } - - /** - * - * @return - */ - public String getName() { - return name; - } /** - * Gets the name of the group this ticket is a member of, if any. + * Sets the id of the group this ticket is exported with. + *

      + * Called internally. Do not use. * - * @return group name, or null + * @param exportGroupId */ - public String getGroupName() { - return groupName; + public void setExportGroupId(int exportGroupId) { + this.exportGroupId = exportGroupId; } + /** * * @return */ - public int getPassId() { - return passId; + public String getName() { + return name; } /** * Gets the world index. @@ -234,12 +224,24 @@ public ResourceTicket getSource() { public boolean hasSource() { return source != null; } + /** + * Gets all tickets depending on this ticket. + * + * @return + */ + public Collection> getTargets() { + return targets; + } + public int getExportGroupId() { + return exportGroupId; + } @Override public String toString() { return "Ticket[name="+name+", worldIndex="+getWorldIndex()+"]"; } + /** * Returns true if the ticket is valid for locating a resource. *

      @@ -253,4 +255,10 @@ public static boolean validate(ResourceTicket ticket) { return ticket != null && ticket.getWorldIndex() >= 0; } + public static void validateUserTicketName(String name) { + if (name.startsWith(RESERVED)) { + throw new IllegalArgumentException("Cannot start ticket name with reserved \""+RESERVED+"\"."); + } + } + } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceUser.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceUser.java new file mode 100644 index 0000000000..16407c6af6 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceUser.java @@ -0,0 +1,28 @@ +/* + * 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.LinkedList; +import java.util.List; + +/** + * + * @author codex + */ +public interface ResourceUser { + + public LinkedList getInputTickets(); + + public LinkedList getOutputTickets(); + + public PassIndex getIndex(); + + public void countReferences(); + + public void dereference(); + + public boolean isUsed(); + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceView.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceView.java index bdb7aa8301..09fbe09b02 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceView.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/ResourceView.java @@ -47,14 +47,14 @@ */ public class ResourceView { - private final ResourceProducer producer; + private final ResourceUser producer; private final ResourceDef def; private final ResourceTicket ticket; private final TimeFrame lifetime; private RenderObject object; private T resource; private int refs = 0; - private boolean survivesRefCull = false; + private boolean temporary = false; private boolean undefined = false; private final AtomicBoolean released = new AtomicBoolean(false); @@ -64,11 +64,11 @@ public class ResourceView { * @param def * @param ticket */ - public ResourceView(ResourceProducer producer, ResourceDef def, ResourceTicket ticket) { + public ResourceView(ResourceUser producer, ResourceDef def, ResourceTicket ticket) { this.producer = producer; this.def = def; this.ticket = ticket; - this.lifetime = new TimeFrame(this.producer.getExecutionIndex(), 0); + this.lifetime = new TimeFrame(this.producer.getIndex(), 0); } /** @@ -159,10 +159,10 @@ public void setUndefined() { /** * Returns true if this resource always survives cull by reference. * - * @param survivesRefCull + * @param temporary */ - public void setSurvivesRefCull(boolean survivesRefCull) { - this.survivesRefCull = survivesRefCull; + public void setTemporary(boolean temporary) { + this.temporary = temporary; } /** @@ -170,7 +170,7 @@ public void setSurvivesRefCull(boolean survivesRefCull) { * * @return */ - public ResourceProducer getProducer() { + public ResourceUser getProducer() { return producer; } /** @@ -282,8 +282,8 @@ public boolean isUndefined() { * * @return */ - public boolean isSurvivesRefCull() { - return survivesRefCull; + public boolean isTemporary() { + return temporary; } /** * Return true if this resource is available for reading. @@ -296,9 +296,9 @@ public boolean isReadAvailable() { return released.get(); } -// @Override -// public String toString() { -// return "RenderResource[index="+ticket.getWorldIndex()+"]"; -// } + @Override + public String toString() { + return "RenderResource["+producer+", "+ticket+"]"; + } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/TicketGroup.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TicketGroup.java new file mode 100644 index 0000000000..dc6dfe8b55 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/TicketGroup.java @@ -0,0 +1,118 @@ +/* + * 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 class TicketGroup { + + /** + * Prefix for tickets that are members of a list. + */ + public static final String LIST = "#list:"; + + private final String name; + private ResourceTicket[] array; + private boolean list = false; + + public TicketGroup(String name) { + this.name = name; + this.array = new ResourceTicket[0]; + this.list = true; + } + public TicketGroup(String name, int length) { + this.name = name; + this.array = new ResourceTicket[length]; + } + + public ResourceTicket create(int i) { + String tName; + if (!list) { + tName = arrayTicketName(name, i); + } else { + tName = listTicketName(name); + } + return new ResourceTicket<>(tName); + } + + public ResourceTicket add() { + ResourceTicket[] temp = new ResourceTicket[array.length+1]; + System.arraycopy(array, 0, temp, 0, array.length); + array = temp; + return (array[array.length-1] = create(array.length-1)); + } + public int remove(ResourceTicket t) { + requireAsList(true); + int i = array.length-1; + for (; i >= 0; i--) { + if (array[i] == t) break; + } + if (i >= 0) { + ResourceTicket[] temp = new ResourceTicket[array.length-1]; + if (i > 0) { + System.arraycopy(array, 0, temp, 0, i); + } + if (i < array.length-1) { + System.arraycopy(array, i+1, temp, i, array.length-i-1); + } + array = temp; + } + return i; + } + + public void requireAsList(boolean list) { + if (this.list != list) { + throw new IllegalStateException("Group must be "+(list ? "a list" : "an array")+" in this context."); + } + } + + public String getName() { + return name; + } + public ResourceTicket[] getArray() { + return array; + } + public boolean isList() { + return list; + } + + /** + * + * @param group + * @param i + * @return + */ + public static String arrayTicketName(String group, int i) { + return group+'['+i+']'; + } + /** + * + * @param group + * @return + */ + public static String listTicketName(String group) { + return LIST+group; + } + /** + * + * @param name + * @return + */ + public static boolean isListTicket(String name) { + return name.startsWith(LIST); + } + /** + * + * @param name + * @return + */ + public static String extractGroupName(String name) { + return name.substring(LIST.length()); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java index 9fab8efc9c..32351c9264 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/client/GraphSetting.java @@ -36,6 +36,7 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; +import com.jme3.export.SavableObject; import com.jme3.renderer.ViewPort; import com.jme3.renderer.framegraph.FrameGraph; import java.io.IOException; @@ -50,31 +51,51 @@ public class GraphSetting implements GraphSource, GraphTarget, Savable private String name; private ViewPortFilter filter; + private T defValue; /** * Serialization only. */ public GraphSetting() { - this(""); + this("", null); } /** - * Graph setting that interacts with the named setting. + * Graph setting that interacts with the named setting + * stored in the FrameGraph. * * @param name */ public GraphSetting(String name) { + this(name, null); + } + /** + * Graph setting that interacts with the named setting + * stored in the FrameGraph. + * + * @param name + * @param defValue + */ + public GraphSetting(String name, T defValue) { this.name = name; + this.defValue = defValue; } @Override public T getGraphValue(FrameGraph frameGraph, ViewPort viewPort) { + assert name != null : "Setting name cannot be null."; if (filter == null || filter.accept(viewPort)) { - return frameGraph.getSetting(name); + T value = frameGraph.getSetting(name); + if (value != null) { + return value; + } else { + return defValue; + } } return null; } @Override public boolean setGraphValue(FrameGraph frameGraph, ViewPort viewPort, T value) { + assert name != null : "Setting name cannot be null."; if (filter == null || filter.accept(viewPort)) { frameGraph.setSetting(name, value); return true; @@ -84,16 +105,18 @@ public boolean setGraphValue(FrameGraph frameGraph, ViewPort viewPort, T value) @Override public void write(JmeExporter ex) throws IOException { OutputCapsule out = ex.getCapsule(this); - out.write(name, "name", ""); + out.write(name, "name", null); if (filter != null && filter instanceof Savable) { out.write((Savable)filter, "filter", new DefaultSavableFilter()); } + out.write(new SavableObject(defValue), "defValue", SavableObject.NULL); } @Override public void read(JmeImporter im) throws IOException { InputCapsule in = im.getCapsule(this); - name = in.readString("name", ""); + name = in.readString("name", null); filter = (ViewPortFilter)in.readSavable("filter", new DefaultSavableFilter()); + defValue = (T)in.readSavableObject("defValue", SavableObject.NULL).getObject(); } /** @@ -108,6 +131,18 @@ public void setFilter(ViewPortFilter filter) { this.filter = filter; } + /** + * Sets the default value used if no value is available in + * the FrameGraph settings. + *

      + * default=null + * + * @param defValue + */ + public void setDefaultValue(T defValue) { + this.defValue = defValue; + } + /** * Gets the name of the setting this interacts with. * @@ -126,6 +161,14 @@ public ViewPortFilter getFilter() { return filter; } + /** + * + * @return + */ + public T getDefaultValue() { + return defValue; + } + public static class DefaultSavableFilter implements ViewPortFilter, Savable { @Override diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java index 47b32bdc4a..d188d1702a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/debug/GraphEventCapture.java @@ -53,7 +53,7 @@ public class GraphEventCapture { private final File target; private final LinkedList events = new LinkedList<>(); - private int frame = 0; + private int frame = 0, targetFrames = 10; private boolean includeNanos = true; private long userNanos = 0; @@ -93,8 +93,8 @@ public void value(String name, Object value) { /** * Logs a render frame start event. */ - public void startRenderFrame() { - add(new Event("SUPEREVENT", "StartRenderFrame", frame)); + public void beginRenderFrame() { + add(new Event("SUPEREVENT", "BeginRenderFrame", frame)); } /** * Logs a render frame end event. @@ -333,6 +333,13 @@ public void export() throws IOException { writer.close(); } + /** + * + * @param targetFrames + */ + public void setTargetFrames(int targetFrames) { + this.targetFrames = targetFrames; + } /** * Set the export file to include nanos with each event. * @@ -342,6 +349,9 @@ public void setIncludeNanos(boolean includeNanos) { this.includeNanos = includeNanos; } + public int getTargetFrames() { + return targetFrames; + } /** * * @return @@ -350,6 +360,14 @@ public boolean isIncludeNanos() { return includeNanos; } + public boolean isComplete() { + return frame >= targetFrames; + } + + public void resetFrameCount() { + frame = 0; + } + private static class Event { protected String eventType; @@ -415,30 +433,6 @@ public String getEventType() { return "VALUE"; } - } - private static class Failure extends Event { - - public Failure(String operation, Check... checks) { - super(operation, new Object[checks.length]); - int i = 0; - for (; i < checks.length; i++) { - if (!checks[i].run()) { - arguments[i] = checks[i].name; - if (checks[i].terminal) break; - } else { - arguments[i] = '-'; - } - } - for (; i < checks.length; i++) { - arguments[i] = '?'; - } - } - - @Override - public String getEventType() { - return "FAILURE"; - } - } private static class Check { diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/export/FrameGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/export/FrameGraphData.java new file mode 100644 index 0000000000..2c6df70960 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/export/FrameGraphData.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.export; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.export.SavableObject; +import com.jme3.renderer.framegraph.FrameGraph; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Holds savable data for a FrameGraph. + * + * @author codex + */ +public class FrameGraphData implements Savable { + + private String name; + private ModuleGraphData modules; + private ArrayList settings = new ArrayList<>(); + + public FrameGraphData() {} + public FrameGraphData(FrameGraph frameGraph) { + this.name = frameGraph.getName(); + this.modules = frameGraph.createModuleData(); + HashMap settingsMap = frameGraph.getSettingsMap(); + for (String key : settingsMap.keySet()) { + settings.add(new SavableObject(key, settingsMap.get(key))); + } + } + + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(name, "name", "FrameGraph"); + out.write(modules, "modules", null); + out.writeSavableArrayList(settings, "settings", new ArrayList<>()); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + name = in.readString("name", "FrameGraph"); + modules = in.readSavable("modules", ModuleGraphData.class, null); + settings = in.readSavableArrayList("settings", new ArrayList<>()); + } + + public String getName() { + return name; + } + public ModuleGraphData getModules() { + return modules; + } + public ArrayList getSettings() { + return settings; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/export/ModuleGraphData.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/export/ModuleGraphData.java new file mode 100644 index 0000000000..b01f3e7209 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/export/ModuleGraphData.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2024 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.export; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.renderer.framegraph.Connectable; +import com.jme3.renderer.framegraph.modules.RenderModule; +import com.jme3.renderer.framegraph.ResourceTicket; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.function.Consumer; + +/** + * Holds savable data for a root module and its descendents. + * + * @author codex + */ +public class ModuleGraphData implements Savable { + + private static final ArrayList DEF_CONNECTIONS = new ArrayList<>(); + + private RenderModule rootModule; + + public ModuleGraphData() {} + public ModuleGraphData(RenderModule root) { + this.rootModule = root; + } + + @Override + public void write(JmeExporter ex) throws IOException { + if (rootModule == null) { + throw new NullPointerException("Root module cannot be null."); + } + // extract connections + final ArrayList connections = new ArrayList<>(); + final LinkedList members = new LinkedList<>(); + rootModule.traverse(new ModuleTreeExtractor(members)); + // descend the queue, so that output ids can be reset in the same pass + for (Iterator it = members.descendingIterator(); it.hasNext();) { + RenderModule m = it.next(); + for (ResourceTicket t : m.getInputTickets()) { + if (t.hasSource()) { + int sourceId = t.getSource().getExportGroupId(); + if (sourceId < 0) { + connections.add(new SavableConnection(m.getId(), sourceId, + t.getName(), t.getSource().getName())); + } + } + } + // reset output ids, since they will no longer be used + for (ResourceTicket t : m.getOutputTickets()) { + t.setExportGroupId(-1); + } + } + // write + OutputCapsule out = ex.getCapsule(this); + out.write(rootModule, "root", null); + out.writeSavableArrayList(connections, "connections", DEF_CONNECTIONS); + connections.clear(); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + rootModule = in.readSavable("root", RenderModule.class, null); + final ArrayList connections = in.readSavableArrayList("connections", DEF_CONNECTIONS); + final HashMap registry = new HashMap<>(); + rootModule.traverse(m -> { if (registry.put(m.getId(), m) != null) + throw new IllegalStateException("Modules with duplicate ids imported."); }); + for (SavableConnection c : connections) { + Connectable source = registry.get(c.getSourceId()); + if (source == null) { + throw new NullPointerException("Source of connection not found."); + } + Connectable target = registry.get(c.getTargetId()); + if (target == null) { + throw new NullPointerException("Target of connection not found."); + } + target.makeInput(source, c.getSourceTicket(), c.getTargetTicket()); + } + connections.clear(); + registry.clear(); + } + + public void setRootModule(RenderModule rootModule) { + this.rootModule = rootModule; + } + public RenderModule getRootModule() { + return rootModule; + } + public T getRootModule(Class requiredType) { + if (rootModule != null && !requiredType.isAssignableFrom(rootModule.getClass())) { + throw new ClassCastException("Module tree root is a "+rootModule.getClass().getName() + + " when required as a "+requiredType.getName()); + } + return (T)rootModule; + } + + private static class ModuleTreeExtractor implements Consumer { + + private final LinkedList members; + + public ModuleTreeExtractor(LinkedList members) { + this.members = members; + } + + @Override + public void accept(RenderModule m) { + members.add(m); + // only need to apply id to export tickets, since we will have the + // correct id handy for input tickets when we extract connections. + for (ResourceTicket t : m.getOutputTickets()) { + t.setExportGroupId(m.getId()); + } + } + + public LinkedList getMembers() { + return members; + } + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/export/SavableConnection.java similarity index 57% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/export/SavableConnection.java index 454dbd8a66..13eb2a73f2 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/SavablePassConnection.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/export/SavableConnection.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.framegraph; +package com.jme3.renderer.framegraph.export; import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; @@ -43,112 +43,102 @@ * * @author codex */ -public class SavablePassConnection implements Savable { +public class SavableConnection implements Savable { - private int inputId, outputId; - private String inputTicket, outputTicket; + private int targetId, sourceId; + private String targetTicket, sourceTicket; /** * Serialization only. */ - public SavablePassConnection() {} + public SavableConnection() {} /** * - * @param inputId - * @param outputId - * @param inputTicket - * @param outputTicket + * @param targetId + * @param sourceId + * @param targetTicket + * @param sourceTicket */ - public SavablePassConnection(int inputId, int outputId, String inputTicket, String outputTicket) { - this.inputId = inputId; - this.outputId = outputId; - this.inputTicket = inputTicket; - this.outputTicket = outputTicket; + public SavableConnection(int targetId, int sourceId, String targetTicket, String sourceTicket) { + this.targetId = targetId; + this.sourceId = sourceId; + this.targetTicket = targetTicket; + this.sourceTicket = sourceTicket; } /** - * Shifts the input and output pass ids. * - * @param shift + * @param targetId */ - public void shiftIds(long shift) { - inputId += shift; - outputId += shift; - } - - /** - * - * @param inputId - */ - public void setInputId(int inputId) { - this.inputId = inputId; + public void setTargetId(int targetId) { + this.targetId = targetId; } /** * - * @param outputId + * @param sourceId */ - public void setOutputId(int outputId) { - this.outputId = outputId; + public void setSourceId(int sourceId) { + this.sourceId = sourceId; } /** * - * @param inputTicket + * @param targetTicket */ - public void setInputTicket(String inputTicket) { - this.inputTicket = inputTicket; + public void setTargetTicket(String targetTicket) { + this.targetTicket = targetTicket; } /** * - * @param outputTicket + * @param sourceTicket */ - public void setOutputTicket(String outputTicket) { - this.outputTicket = outputTicket; + public void setSourceTicket(String sourceTicket) { + this.sourceTicket = sourceTicket; } /** * * @return */ - public int getInputId() { - return inputId; + public int getTargetId() { + return targetId; } /** * * @return */ - public int getOutputId() { - return outputId; + public int getSourceId() { + return sourceId; } /** * * @return */ - public String getInputTicket() { - return inputTicket; + public String getTargetTicket() { + return targetTicket; } /** * * @return */ - public String getOutputTicket() { - return outputTicket; + public String getSourceTicket() { + return sourceTicket; } @Override public void write(JmeExporter ex) throws IOException { OutputCapsule out = ex.getCapsule(this); - out.write(inputId, "inputId", -1); - out.write(outputId, "outputId", -1); - out.write(inputTicket, "inputTicket", ""); - out.write(outputTicket, "outputTicket", ""); + out.write(targetId, "inputId", -1); + out.write(sourceId, "outputId", -1); + out.write(targetTicket, "inputTicket", ""); + out.write(sourceTicket, "outputTicket", ""); } @Override public void read(JmeImporter im) throws IOException { InputCapsule in = im.getCapsule(this); - inputId = in.readInt("inputId", -1); - outputId = in.readInt("outputId", -1); - inputTicket = in.readString("inputTicket", ""); - outputTicket = in.readString("outputTicket", ""); + targetId = in.readInt("inputId", -1); + sourceId = in.readInt("outputId", -1); + targetTicket = in.readString("inputTicket", ""); + sourceTicket = in.readString("outputTicket", ""); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/ModuleLocator.java similarity index 83% rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/ModuleLocator.java index 0ee4bec444..685bc2d95a 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/PassLocator.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/ModuleLocator.java @@ -29,9 +29,9 @@ * 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; +package com.jme3.renderer.framegraph.modules; -import com.jme3.renderer.framegraph.passes.RenderPass; +import com.jme3.renderer.framegraph.modules.RenderModule; /** * Locates a pass. @@ -39,15 +39,15 @@ * @author codex * @param */ -public interface PassLocator { +public interface ModuleLocator { /** - * Determines if the pass qualifies for this locator. + * Determines if the module qualifies for this locator. * - * @param pass + * @param module * @return pass, or null if not accepted */ - public T accept(RenderPass pass); + public T accept(RenderModule module); /** * Locates a pass by its type. @@ -56,7 +56,7 @@ public interface PassLocator { * @param type * @return */ - public static PassLocator by(Class type) { + public static ModuleLocator by(Class type) { return pass -> { if (type.isAssignableFrom(pass.getClass())) { return (R)pass; @@ -74,7 +74,7 @@ public static PassLocator by(Class type) { * @param name * @return */ - public static PassLocator by(Class type, String name) { + public static ModuleLocator by(Class type, String name) { return pass -> { if (name.equals(pass.getName()) && type.isAssignableFrom(pass.getClass())) { return (R)pass; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderContainer.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderContainer.java new file mode 100644 index 0000000000..4c2e2b0289 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderContainer.java @@ -0,0 +1,204 @@ +/* + * 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.modules; + +import com.jme3.renderer.framegraph.modules.RenderModule; +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.PassIndex; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * + * @author codex + * @param + */ +public class RenderContainer extends RenderModule implements Iterable { + + protected final ArrayList queue = new ArrayList<>(); + + @Override + public void initModule(FrameGraph frameGraph) { + for (RenderModule m : queue) { + m.initializeModule(frameGraph); + } + } + @Override + public void cleanupModule(FrameGraph frameGraph) { + for (RenderModule m : queue) { + m.cleanupModule(); + } + } + @Override + public void prepareModuleRender(FGRenderContext context, PassIndex index) { + super.prepareModuleRender(context, index); + for (RenderModule m : queue) { + index.queueIndex++; + m.prepareModuleRender(context, index); + } + } + @Override + public void prepareRender(FGRenderContext context) {} + @Override + public void executeRender(FGRenderContext context) { + for (RenderModule m : queue) { + if (isInterrupted()) { + break; + } + m.executeModuleRender(context); + } + } + @Override + public void resetRender(FGRenderContext context) { + for (RenderModule m : queue) { + m.resetRender(context); + } + } + @Override + public void renderingComplete() { + for (RenderModule m : queue) { + m.renderingComplete(); + } + } + @Override + public void countReferences() { + for (RenderModule m : queue) { + m.countReferences(); + } + } + @Override + public boolean isUsed() { + // if executing a container becomes heavy on its own, change this to + // check isUsed() for each contained module. + return !queue.isEmpty(); + } + @Override + public void interrupt() { + super.interrupt(); + for (RenderModule m : queue) { + m.interrupt(); + } + } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + OutputCapsule out = ex.getCapsule(this); + ArrayList array = new ArrayList<>(); + array.addAll(queue); + out.writeSavableArrayList(array, "queue", new ArrayList<>(0)); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + InputCapsule in = im.getCapsule(this); + ArrayList array = in.readSavableArrayList("queue", new ArrayList<>(0)); + queue.addAll(array); + } + @Override + public Iterator iterator() { + return queue.iterator(); + } + @Override + public void traverse(Consumer traverser) { + traverser.accept(this); + for (RenderModule m : queue) { + m.traverse(traverser); + } + } + + public T add(T module, int index) { + assert module != null : "Cannot add null module."; + assert this != module : "Cannot add container to itself."; + if (module.getParent() != null) { + module.getParent().remove(module); + } + if (index < 0) { + index = queue.size(); + } + queue.add(index, module); + if (module.setParent(this)) { + if (isAssigned()) { + module.initializeModule(frameGraph); + } + return module; + } + throw new IllegalArgumentException(module+" cannot be added to this container."); + } + public T add(T module) { + return add(module, queue.size()); + } + public T[] addLoop(T[] array, int start, Function factory, String source, String target) { + for (int i = 0; i < array.length; i++) { + T module = array[i]; + if (module == null) { + if (factory == null) { + throw new NullPointerException("Module to add cannot be null."); + } + module = array[i] = factory.apply(i); + } + if (start >= 0) { + add(module, start++); + } else { + add(module); + } + if (i > 0) { + array[i].makeInput(array[i-1], source, target); + } + } + return array; + } + public R get(int index) { + return queue.get(index); + } + public T get(ModuleLocator by) { + for (RenderModule m : queue) { + T module = by.accept(m); + if (module != null) { + return module; + } else if (m instanceof RenderContainer) { + module = (T)((RenderContainer)m).get(by); + if (module != null) { + return module; + } + } + } + return null; + } + public boolean remove(R module) { + if (queue.remove(module)) { + module.cleanupModule(); + return true; + } + return false; + } + public R remove(int index) { + if (index < 0 || index >= queue.size()) { + return null; + } + R m = queue.remove(index); + m.cleanupModule(); + return m; + } + public void clear() { + for (RenderModule m : queue) { + m.cleanupModule(); + } + queue.clear(); + } + + public int size() { + return queue.size(); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderModule.java new file mode 100644 index 0000000000..87d10e9ac4 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderModule.java @@ -0,0 +1,324 @@ +/* + * 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.modules; + +import com.jme3.export.InputCapsule; +import com.jme3.export.JmeExporter; +import com.jme3.export.JmeImporter; +import com.jme3.export.OutputCapsule; +import com.jme3.export.Savable; +import com.jme3.renderer.framegraph.Connectable; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.FrameGraph; +import com.jme3.renderer.framegraph.PassIndex; +import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.ResourceUser; +import com.jme3.renderer.framegraph.TicketGroup; +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.function.Consumer; +import java.util.stream.Stream; + +/** + * + * @author codex + */ +public abstract class RenderModule implements Connectable, ResourceUser, Savable { + + protected FrameGraph frameGraph; + protected String name = "RenderModule"; + protected RenderContainer parent; + protected final PassIndex index = new PassIndex(); + protected final LinkedList inputs = new LinkedList<>(); + protected final LinkedList outputs = new LinkedList<>(); + protected final HashMap groups = new HashMap<>(); + private boolean interrupted = false; + private int refs = 0; + private int id = -1; + + @Override + public LinkedList getInputTickets() { + return inputs; + } + @Override + public LinkedList getOutputTickets() { + return outputs; + } + @Override + public PassIndex getIndex() { + return index; + } + @Override + public void countReferences() { + refs = outputs.size(); + } + @Override + public void dereference() { + refs--; + } + @Override + public boolean isUsed() { + return refs > 0; + } + @Override + public void write(JmeExporter ex) throws IOException { + OutputCapsule out = ex.getCapsule(this); + out.write(name, "name", "RenderModule"); + out.write(id, "exportId", -1); + } + @Override + public void read(JmeImporter im) throws IOException { + InputCapsule in = im.getCapsule(this); + name = in.readString("name", "RenderModule"); + id = in.readInt("exportId", -1); + } + + @Override + public ResourceTicket getInput(String name) { + return getTicketFromStream(inputs.stream(), name); + } + @Override + public ResourceTicket getOutput(String name) { + return getTicketFromStream(outputs.stream(), name); + } + @Override + public TicketGroup getGroup(String name) { + return groups.get(name); + } + @Override + public ResourceTicket addListEntry(String groupName) { + TicketGroup g = getGroup(name, true); + g.requireAsList(true); + return addInput(g.add()); + } + + public int getId() { + return id; + } + + /** + * Adds the ticket as input. + * + * @param + * @param input + * @return given ticket + */ + public ResourceTicket addInput(ResourceTicket input) { + getInputTickets().add(input); + return input; + } + /** + * Adds the ticket as output. + * + * @param + * @param output + * @return given ticket + */ + public ResourceTicket addOutput(ResourceTicket output) { + getOutputTickets().add(output); + return output; + } + /** + * Creates and registers a new ticket as input. + * + * @param + * @param name name assigned to the new ticket + * @return created ticket + */ + public ResourceTicket addInput(String name) { + ResourceTicket.validateUserTicketName(name); + return addInput(new ResourceTicket<>(name)); + } + /** + * Creates and registers a new ticket as output. + * + * @param + * @param name name assigned to the new ticket + * @return created ticket + */ + public ResourceTicket addOutput(String name) { + ResourceTicket.validateUserTicketName(name); + return addOutput(new ResourceTicket<>(name)); + } + /** + * Creates and adds a ticket array as a group input of the specified length under the given name. + *

      + * A group bundles several tickets together so that they can easily be used together. + * Each individual ticket is handled just like any other, it is just registered with the group as well. + * Names are formatted as {@code groupName+"["+index+"]"}. + * + * @param + * @param name + * @param length + * @return created ticket array + */ + public ResourceTicket[] addInputGroup(String name, int length) { + ResourceTicket.validateUserTicketName(name); + TicketGroup group = new TicketGroup(name, length); + for (int i = 0; i < length; i++) { + group.getArray()[i] = addInput(group.create(i)); + } + groups.put(name, group); + return group.getArray(); + } + /** + * Creates and adds a ticket array as a group output of the specified length under the given name. + *

      + * A group bundles several tickets together so that they can easily be used together. + * Each individual ticket is handled just like any other, it is just registered with the group as well. + * Names are formatted as {@code groupName+"["+index+"]"}. + * + * @param + * @param name + * @param length + * @return create ticket array + */ + public ResourceTicket[] addOutputGroup(String name, int length) { + ResourceTicket.validateUserTicketName(name); + TicketGroup group = new TicketGroup(name, length); + for (int i = 0; i < length; i++) { + group.getArray()[i] = addOutput(group.create(i)); + } + groups.put(name, group); + return group.getArray(); + } + /** + * Creates an input ticket list. + *

      + * A ticket list is an extension of a ticket group where the size is indefinite, meaning connections + * can be added or removed at will. The order of connections is not guaranteed, especially + * when a ticket list is loaded from a save file. + *

      + * Each addition or removal from a ticket list requires an array resize, so it a ticket + * list should remain static where possible. + * + * @param name + */ + public void addInputList(String name) { + ResourceTicket.validateUserTicketName(name); + groups.put(name, new TicketGroup(name)); + } + + private static ResourceTicket getTicketFromStream(Stream stream, String name) { + return stream.filter(t -> name.equals(t.getName())).findFirst().orElse(null); + } + public ResourceTicket[] getGroupArray(String name) { + return getGroup(name, true).getArray(); + } + + /** + * Interrupts execution of this module. + */ + public void interrupt() { + interrupted = true; + } + + public void initializeModule(FrameGraph frameGraph) { + if (this.frameGraph != null) { + throw new IllegalStateException("Module already initialized."); + } + this.frameGraph = frameGraph; + id = this.frameGraph.getNextId(); + initModule(this.frameGraph); + } + public void prepareModuleRender(FGRenderContext context, PassIndex index) { + this.index.set(index); + prepareRender(context); + } + public void executeModuleRender(FGRenderContext context) { + if (!isUsed()) { + return; + } + executeRender(context); + } + public void cleanupModule() { + id = -1; + if (frameGraph != null) { + cleanupModule(frameGraph); + frameGraph = null; + } + } + + /** + * Initializes the RenderModule implementation. + *

      + * For most cases, use {@link #initializeModule(com.jme3.renderer.framegraph.FrameGraph)} + * instead. + * + * @param frameGraph + */ + protected abstract void initModule(FrameGraph frameGraph); + /** + * Prepares the RenderModule implementation. + *

      + * For most cases, use {@link #prepareModuleRender(com.jme3.renderer.framegraph.FGRenderContext, com.jme3.renderer.framegraph.PassIndex)} + * instead. + * + * @param context + */ + protected abstract void prepareRender(FGRenderContext context); + /** + * Executes the RenderModule implementation. + *

      + * For most cases, use {@link #executeModuleRender(com.jme3.renderer.framegraph.FGRenderContext)} + * instead. + * + * @param context + */ + protected abstract void executeRender(FGRenderContext context); + /** + * Resets the RenderModule after execution. + * + * @param context + */ + protected abstract void resetRender(FGRenderContext context); + /** + * Cleans up the RenderModule implementation. + *

      + * For most cases, use {@link #cleanupModule()} instead. + * + * @param frameGraph + */ + protected abstract void cleanupModule(FrameGraph frameGraph); + + protected abstract void renderingComplete(); + public abstract void traverse(Consumer traverser); + + public void setName(String name) { + this.name = name; + } + protected boolean setParent(RenderContainer parent) { + this.parent = parent; + return true; + } + + public String getName() { + return name; + } + public RenderContainer getParent() { + return parent; + } + public boolean isAssigned() { + return frameGraph != null; + } + public boolean isInterrupted() { + return interrupted; + } + public boolean isAsync() { + return !index.isMainThread(); + } + public boolean isAncenstor(RenderModule ancestor) { + RenderModule p = parent; + while (p != null) { + if (p == ancestor) { + return true; + } + p = p.parent; + } + return false; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderThread.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderThread.java new file mode 100644 index 0000000000..50fa0b13cc --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/RenderThread.java @@ -0,0 +1,61 @@ +/* + * 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.modules; + +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.modules.RenderContainer; +import com.jme3.renderer.framegraph.modules.RenderModule; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author codex + */ +public class RenderThread extends RenderContainer implements Runnable { + + private static final Logger LOG = Logger.getLogger(RenderThread.class.getName()); + + private FGRenderContext context; + + @Override + public void run() { + try { + executeModuleRender(context); + } catch (Exception ex) { + LOG.log(Level.SEVERE, "An exception occured while executing RenderThread at index "+index.threadIndex+'.', ex); + frameGraph.interruptRendering(); + } finally { + frameGraph.notifyThreadComplete(this); + } + } + + /** + * Starts running the group of modules contained by this RenderThread. + *

      + * If the thread index of this module is asynchronous (index != + * {@link PassIndex#MAIN_THREAD}), a new thread is spawned for this + * to execute on. + *

      + * All exceptions that occur under this module are caught and + * the FrameGraph notified to ensure graceful interruption of other threads. + * + * @param context + */ + public void startThreadExecution(FGRenderContext context) { + this.context = context; + if (isInterrupted()) { + frameGraph.notifyThreadComplete(this); + return; + } + if (!isAsync()) { + run(); + } else { + Thread t = new Thread(this); + t.start(); + } + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/ThreadLauncher.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/ThreadLauncher.java new file mode 100644 index 0000000000..34c38c5f7b --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/modules/ThreadLauncher.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.modules; + +import com.jme3.renderer.RendererException; +import com.jme3.renderer.framegraph.FGRenderContext; +import com.jme3.renderer.framegraph.PassIndex; + +/** + * Container that launches renderering threads. + *

      + * This module cannot be added to another container. It is designed to be + * handled by the FrameGraph directly. + * + * @author codex + */ +public class ThreadLauncher extends RenderContainer { + + private static final long threadTimeoutMillis = 2000; + + private int activeThreads = 0; + + public ThreadLauncher() {} + + @Override + public void prepareModuleRender(FGRenderContext context, PassIndex index) { + super.prepareModuleRender(context, index); + for (RenderThread t : queue) { + t.prepareModuleRender(context, index); + index.threadIndex++; + index.queueIndex = 0; + } + } + @Override + public void executeRender(FGRenderContext context) { + activeThreads = queue.size(); + for (int i = queue.size()-1; i >= 0; i--) { + if (isInterrupted()) { + break; + } + queue.get(i).startThreadExecution(context); + } + long start = System.currentTimeMillis(); + while (activeThreads > 0) { + // wait for all threads to complete + if (System.currentTimeMillis()-start > threadTimeoutMillis) { + throw new RendererException("Timeout occured waiting for threads to complete."); + } + } + } + @Override + protected boolean setParent(RenderContainer parent) { + return false; + } + + public void notifyThreadComplete(RenderThread thread) { + activeThreads--; + } + + public RenderThread getOrCreate(int i) { + if (i >= queue.size()) { + return add(); + } else if (i >= 0) { + return queue.get(i); + } else { + return queue.get(PassIndex.MAIN_THREAD); + } + } + public RenderThread add() { + return add(new RenderThread()); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GeometryPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GeometryPass.java index 8412fe1742..ffee861d66 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GeometryPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/GeometryPass.java @@ -36,7 +36,7 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.math.ColorRGBA; -import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.GeometryQueue; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java index 2e3330ffe5..30074567c0 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/Junction.java @@ -80,43 +80,43 @@ public Junction(int length, int groupSize) { protected void initialize(FrameGraph frameGraph) { for (int i = 0; i < length; i++) { if (groupSize > 1) { - addInputGroup(Junction.getInput(i), groupSize); + addInputGroup(getInput(i), groupSize); } else { - addInput(Junction.getInput(i)); + addInput(getInput(i)); } } if (groupSize > 1) { - addOutputGroup(Junction.getOutput(), groupSize); + addOutputGroup(getOutput(), groupSize); } else { - output = addOutput(Junction.getOutput()); + output = addOutput(getOutput()); } } @Override protected void prepare(FGRenderContext context) { int size; if (groupSize > 1) { - size = getNumGroups()-1; + size = groups.size()-1; } else { - size = getInputTickets().size()-EXTRA_INPUTS; + size = inputs.size()-EXTRA_INPUTS; } // remove excess tickets while (size > length) { size--; if (groupSize > 1) { - ResourceTicket[] array = removeGroup(Junction.getInput(size)); + ResourceTicket[] array = removeGroup(getInput(size)); for (ResourceTicket t : array) { t.setSource(null); } } else { - getInputTickets().removeLast().setSource(null); + inputs.removeLast().setSource(null); } } // add deficit tickets while (size < length) { if (groupSize > 1) { - addInputGroup(Junction.getInput(size), groupSize); + addInputGroup(getInput(size), groupSize); } else { - addInput(Junction.getInput(size)); + addInput(getInput(size)); } size++; } @@ -158,21 +158,21 @@ public void read(JmeImporter im) throws IOException { defaultIndex = in.readInt("defaultIndex", 0); source = (GraphSource)in.readSavable("source", null); } - @Override - public ResourceTicket addTicketSlot(String group) { - throw new UnsupportedOperationException("Cannot resize group."); - } private void connect(int i) { boolean assignNull = i < 0 || i >= length; if (groupSize > 1) { - ResourceTicket[] inArray = getGroupArray(Junction.getInput(i)); - ResourceTicket[] outArray = getGroupArray(Junction.getOutput()); - for (int j = 0; j < groupSize; j++) { - outArray[j].setSource(assignNull ? null : inArray[j]); + ResourceTicket[] outArray = getGroupArray(getOutput()); + if (!assignNull) { + ResourceTicket[] inArray = getGroupArray(getInput(i)); + for (int j = 0; j < groupSize; j++) { + outArray[j].setSource(inArray[j]); + } + } else for (ResourceTicket t : outArray) { + t.setSource(null); } } else { - output.setSource(assignNull ? null : getInputTickets().get(i)); + output.setSource(assignNull ? null : inputs.get(i)); } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputGeometryPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputGeometryPass.java index 7fa82a256a..55d52cd368 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputGeometryPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/OutputGeometryPass.java @@ -35,7 +35,7 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; -import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.GeometryQueue; diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java index f3e5bdf4fe..8bcc4150b1 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/QueueMergePass.java @@ -78,7 +78,6 @@ protected void prepare(FGRenderContext context) { } @Override protected void execute(FGRenderContext context) { - System.out.println("acquire queues to merge"); GeometryQueue[] queues = acquireArray("Queues", n -> new GeometryQueue[n]); for (GeometryQueue q : queues) { target.add(q); diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java index 33f555748b..9d54f8e066 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/RenderPass.java @@ -36,22 +36,20 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; +import com.jme3.renderer.framegraph.modules.RenderModule; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; -import com.jme3.renderer.framegraph.PassIndex; import com.jme3.renderer.framegraph.ResourceList; -import com.jme3.renderer.framegraph.ResourceProducer; import com.jme3.renderer.framegraph.ResourceTicket; +import com.jme3.renderer.framegraph.TicketGroup; import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.definitions.ResourceDef; import com.jme3.texture.FrameBuffer; import java.io.IOException; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.Objects; -import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import java.util.function.Function; /** @@ -59,88 +57,63 @@ * * @author codex */ -public abstract class RenderPass implements ResourceProducer, Savable { +public abstract class RenderPass extends RenderModule implements Savable { - private static final String LIST_PREFIX = "#ElementOfList:"; - private static int nextId = 0; - - private int id = nextId++; - private int exportId = -1; - private String name; - protected FrameGraph frameGraph; - private PassIndex index; - private int refs = 0; - private final LinkedList inputs = new LinkedList<>(); - private final LinkedList outputs = new LinkedList<>(); private final LinkedList frameBuffers = new LinkedList<>(); - private final HashMap groups = new HashMap<>(); protected ResourceList resources; protected boolean autoTicketRelease = true; - /** - * Initializes the pass to the framegraph. - * - * @param frameGraph - * @param index execution index - */ - public void initializePass(FrameGraph frameGraph, PassIndex index) { - this.frameGraph = frameGraph; - this.index = index; - this.resources = frameGraph.getResources(); - if (name == null) { - name = getClass().getSimpleName(); - } + @Override + public String toString() { + return getClass().getSimpleName(); + } + @Override + public void write(JmeExporter ex) throws IOException { + super.write(ex); + write(ex.getCapsule(this)); + } + @Override + public void read(JmeImporter im) throws IOException { + super.read(im); + read(im.getCapsule(this)); + } + @Override + public void traverse(Consumer traverser) { + traverser.accept(this); + } + + @Override + public void initModule(FrameGraph frameGraph) { initialize(frameGraph); } - /** - * Prepares the pass for rendering. - * - * @param context - */ + @Override public void prepareRender(FGRenderContext context) { - if (index == null) { - throw new IllegalStateException("Pass is not properly initialized for rendering."); - } + resources = context.getResources(); prepare(context); } - /** - * Executes the pass. - * - * @param context - */ + @Override public void executeRender(FGRenderContext context) { + if (context.isAsync()) { + waitToExecute(); + } execute(context); if (autoTicketRelease) { releaseAll(); } + if (index.isMainThread()) { + context.popRenderSettings(); + } } - /** - * Resets the pass from rendering. - * - * @param context - */ + @Override public void resetRender(FGRenderContext context) { reset(context); } - /** - * Cleans up the pass's participation in the framegraph. - * - * @param frameGraph - */ - public void cleanupPass(FrameGraph frameGraph) { + @Override + public void cleanupModule(FrameGraph frameGraph) { cleanup(frameGraph); - for (ResourceTicket t : inputs) { - t.setSource(null); - t.setPassId(-1); - } - for (ResourceTicket t : outputs) { - t.setSource(null); - t.setPassId(-1); - } inputs.clear(); outputs.clear(); groups.clear(); - index = null; this.frameGraph = null; } @@ -186,6 +159,7 @@ public void cleanupPass(FrameGraph frameGraph) { * Called when all rendering is complete in a rendering frame this pass * participated in. */ + @Override public void renderingComplete() { for (Iterator it = frameBuffers.iterator(); it.hasNext();) { PassFrameBuffer fb = it.next(); @@ -199,16 +173,29 @@ public void renderingComplete() { } /** - * Declares a new resource. + * Declares a new resource using a registered ticket. * * @param * @param def definition for new resource * @param ticket ticket to store resulting index * @return given ticket + * @see #declareTemporary(com.jme3.renderer.framegraph.definitions.ResourceDef, com.jme3.renderer.framegraph.ResourceTicket) */ protected ResourceTicket declare(ResourceDef def, ResourceTicket ticket) { return resources.declare(this, def, ticket); } + /** + * Declares a resource using an unregistered ticket. + * + * @param + * @param def + * @param ticket + * @return + * @see #declare(com.jme3.renderer.framegraph.definitions.ResourceDef, com.jme3.renderer.framegraph.ResourceTicket) + */ + protected ResourceTicket declareTemporary(ResourceDef def, ResourceTicket ticket) { + return resources.declareTemporary(this, def, ticket); + } /** * Reserves the {@link com.jme3.renderer.framegraph.RenderObject RenderObject} associated with the ticket. * @@ -266,14 +253,10 @@ protected void referenceOptional(ResourceTicket... tickets) { *

      * An incoming resource is deemed ready when {@link com.jme3.renderer.framegraph.ResourceView#claimReadPermissions() read * permissions are claimed}. - * - * @param timeout maximum wait time for each ticket before a timeout exception is thrown - * @param attempts maximum attempts for each ticket before a timeout exception is thrown - * @throws java.util.concurrent.TimeoutException if wait times out */ - public void waitForInputs(long timeout, int attempts) throws TimeoutException { + public void waitToExecute() { for (ResourceTicket t : inputs) { - resources.wait(t, index.getThreadIndex(), timeout, attempts); + resources.waitForResource(t, index.threadIndex); } } @@ -286,7 +269,7 @@ public void waitForInputs(long timeout, int attempts) throws TimeoutException { * @return */ protected T[] acquireArray(String name, T[] array) { - ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); + ResourceTicket[] tickets = getGroup(name).getArray(); int n = Math.min(array.length, tickets.length); for (int i = 0; i < n; i++) { array[i] = resources.acquire(tickets[i]); @@ -303,7 +286,7 @@ protected T[] acquireArray(String name, T[] array) { * @return */ protected T[] acquireArray(String name, Function func) { - ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); + ResourceTicket[] tickets = getGroup(name).getArray(); T[] array = func.apply(tickets.length); int n = Math.min(array.length, tickets.length); for (int i = 0; i < n; i++) { @@ -324,7 +307,7 @@ protected T[] acquireArray(String name, Function func) { * @return */ protected T[] acquireArrayOrElse(String name, T[] array, T val) { - ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); + ResourceTicket[] tickets = getGroup(name).getArray(); int n = Math.min(array.length, tickets.length); for (int i = 0; i < n; i++) { array[i] = resources.acquireOrElse(tickets[i], val); @@ -344,7 +327,7 @@ protected T[] acquireArrayOrElse(String name, T[] array, T val) { * @return */ protected T[] acquireArrayOrElse(String name, Function func, T val) { - ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); + ResourceTicket[] tickets = getGroup(name).getArray(); T[] array = func.apply(tickets.length); int n = Math.min(array.length, tickets.length); for (int i = 0; i < n; i++) { @@ -364,7 +347,7 @@ protected List acquireList(String name, List list) { if (list == null) { list = new LinkedList<>(); } - ResourceTicket[] tickets = Objects.requireNonNull(getGroupArray(name), "Ticket group cannot be null."); + ResourceTicket[] tickets = getGroup(name).getArray(); for (ResourceTicket t : tickets) { T res = resources.acquireOrElse(t, null); if (res != null) list.add(res); @@ -386,117 +369,6 @@ protected void releaseAll() { } } - /** - * Adds the ticket as input. - * - * @param - * @param input - * @return given ticket - */ - private ResourceTicket addInput(ResourceTicket input) { - inputs.add(input); - input.setPassId(id); - return input; - } - /** - * Adds the ticket as output. - * - * @param - * @param output - * @return given ticket - */ - private ResourceTicket addOutput(ResourceTicket output) { - outputs.add(output); - output.setPassId(id); - return output; - } - /** - * Creates and registers a new ticket as input. - * - * @param - * @param name name assigned to the new ticket - * @return created ticket - */ - protected ResourceTicket addInput(String name) { - validateUserTicketName(name); - return addInput(new ResourceTicket<>(name)); - } - /** - * Creates and registers a new ticket as output. - * - * @param - * @param name name assigned to the new ticket - * @return created ticket - */ - protected ResourceTicket addOutput(String name) { - validateUserTicketName(name); - return addOutput(new ResourceTicket<>(name)); - } - /** - * Creates and adds a ticket array as a group input of the specified length under the given name. - *

      - * A group bundles several tickets together so that they can easily be used together. - * Each individual ticket is handled just like any other, it is just registered with the group as well. - * Names are formatted as {@code groupName+"["+index+"]"}. - * - * @param - * @param name - * @param length - * @return created ticket array - */ - protected ResourceTicket[] addInputGroup(String name, int length) { - validateUserTicketName(name); - TicketGroup group = new TicketGroup(name, length); - for (int i = 0; i < length; i++) { - group.array[i] = addInput(group.create(i)); - } - groups.put(name, group); - return group.array; - } - /** - * Creates and adds a ticket array as a group output of the specified length under the given name. - *

      - * A group bundles several tickets together so that they can easily be used together. - * Each individual ticket is handled just like any other, it is just registered with the group as well. - * Names are formatted as {@code groupName+"["+index+"]"}. - * - * @param - * @param name - * @param length - * @return create ticket array - */ - protected ResourceTicket[] addOutputGroup(String name, int length) { - validateUserTicketName(name); - TicketGroup group = new TicketGroup(name, length); - for (int i = 0; i < length; i++) { - group.array[i] = addOutput(group.create(i)); - } - groups.put(name, group); - return group.array; - } - /** - * Creates an input ticket list. - *

      - * A ticket list is an extension of a ticket group where the size is indefinite, meaning connections - * can be added or removed at will. The order of connections is not guaranteed, especially - * when a ticket list is loaded from a save file. - *

      - * Each addition or removal from a ticket list requires an array resize, so it a ticket - * list should remain static where possible. - * - * @param name - */ - protected void addInputList(String name) { - validateUserTicketName(name); - groups.put(name, new TicketGroup(name)); - } - - private void validateUserTicketName(String name) { - if (name.startsWith("#")) { - throw new IllegalArgumentException("Cannot start ticket name with reserved '#' symbol."); - } - } - /** * Removes all members of the named group from the input and output lists. * @@ -512,8 +384,8 @@ protected ResourceTicket[] removeGroup(String name) { // Once we determine which list group members were added to, we only // need to remove from that list for future members. byte state = 0; - if (group.list) state = 1; - for (ResourceTicket t : group.array) { + if (group.isList()) state = 1; + for (ResourceTicket t : group.getArray()) { if (state >= 0 && inputs.remove(t)) { state = 1; } @@ -521,170 +393,7 @@ protected ResourceTicket[] removeGroup(String name) { state = -1; } } - return group.array; - } - - /** - * Gets the named input ticket, or null if none exists. - * - * @param name - * @return - */ - public ResourceTicket getInput(String name) { - for (ResourceTicket t : inputs) { - if (name.equals(t.getName())) { - return t; - } - } - return null; - } - /** - * Gets the named output ticket, or null if none exists. - * - * @param name - * @return - */ - public ResourceTicket getOutput(String name) { - for (ResourceTicket t : outputs) { - if (name.equals(t.getName())) { - return t; - } - } - return null; - } - /** - * Gets the ticket array registered under the name. - * - * @param name - * @return - */ - public ResourceTicket[] getGroupArray(String name) { - TicketGroup group = groups.get(name); - if (group != null) { - return group.array; - } else { - return null; - } - } - - /** - * Makes the named source (output) group belonging to the given pass the source of - * the named target (input) group belonging to this pass. - * - * @param sourcePass - * @param sourceGroup - * @param targetGroup - * @param sourceStart start index (inclusive) for the source group - * @param targetStart start index (inclusive) for the target group - * @param length number of tickets to connect (clamped to group lengths) - */ - public void makeGroupInput(RenderPass sourcePass, String sourceGroup, String targetGroup, int sourceStart, int targetStart, int length) { - ResourceTicket[] sourceArray = Objects.requireNonNull(sourcePass.getGroupArray(sourceGroup), "Source group cannot be null."); - ResourceTicket[] targetArray = Objects.requireNonNull(getGroupArray(targetGroup), "Target group cannot be null."); - int n = Math.min(sourceStart+length, sourceArray.length); - int m = Math.min(targetStart+length, targetArray.length); - for (int i = sourceStart, j = targetStart; i < n && j < m; i++, j++) { - targetArray[j].setSource(sourceArray[i]); - } - } - /** - * - * @param sourcePass - * @param sourceGroup - * @param targetGroup - */ - public void makeGroupInput(RenderPass sourcePass, String sourceGroup, String targetGroup) { - makeGroupInput(sourcePass, sourceGroup, targetGroup, 0, 0, Integer.MAX_VALUE); - } - /** - * Makes the named source (output) ticket belonging to the given pass the source of - * the named target (input) ticket belonging to this pass. - *

      - * If both the source name and target name correspond to ticket groups, the - * groups will be connected. - * - * @param sourcePass - * @param sourceTicket - * @param targetTicket - */ - public void makeInput(RenderPass sourcePass, String sourceTicket, String targetTicket) { - ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); - if (targetTicket.startsWith(LIST_PREFIX)) { - TicketGroup g = Objects.requireNonNull(groups.get(targetTicket.substring(LIST_PREFIX.length())), "List group cannot be null."); - g.requireAsList(true); - g.add().setSource(source); - } else { - ResourceTicket target = Objects.requireNonNull(getInput(targetTicket), "Target ticket cannot be null."); - target.setSource(source); - } - } - /** - * Adds the indicated source ticket as an input to the target indefinite group. - * - * @param sourcePass - * @param sourceTicket - * @param targetGroup - */ - public void makeInputToList(RenderPass sourcePass, String sourceTicket, String targetGroup) { - ResourceTicket source = Objects.requireNonNull(sourcePass.getOutput(sourceTicket), "Source ticket cannot be null."); - TicketGroup target = Objects.requireNonNull(groups.get(targetGroup), "Target group cannot be null."); - target.requireAsList(true); - target.add().setSource(source); - } - /** - * Adds a ticket to the end of a group. - *

      - * The group cannot be a list. - * - * @param - * @param group - * @return added ticket - */ - public ResourceTicket addTicketSlot(String group) { - TicketGroup g = groups.get(group); - if (g == null) { - throw new NullPointerException("Ticket group cannot be null."); - } - g.requireAsList(false); - return g.add(); - } - - /** - * Disconnects all input tickets in this pass that have the given ticket as - * their source. - * - * @param ticket - */ - public void disconnectInputsFrom(ResourceTicket ticket) { - for (ResourceTicket in : inputs) { - if (in.getSource() == ticket) { - in.setSource(null); - if (in.getGroupName() != null) { - TicketGroup g = groups.get(in.getGroupName()); - if (g != null && g.list) { - g.remove(in); - } - } - } - } - } - /** - * Nullifies all sources belonging to the given pass. - * - * @param pass - */ - public void disconnectInputsFrom(RenderPass pass) { - for (ResourceTicket in : inputs) { - if (pass.getOutputTickets().contains(in.getSource())) { - in.setSource(null); - if (in.getGroupName() != null) { - TicketGroup g = groups.get(in.getGroupName()); - if (g != null && g.list) { - g.remove(in); - } - } - } - } + return group.getArray(); } /** @@ -776,84 +485,6 @@ protected FrameBuffer getFrameBuffer(FGRenderContext context, String tag, int sa return getFrameBuffer(context.getGraphCapture(), tag, context.getWidth(), context.getHeight(), samples); } - /** - * Counts the number of potential references to this pass. - *

      - * Used for determining if this pass should be culled. - *

      - * Called automatically. Do not use. - */ - public final void countReferences() { - refs = outputs.size(); - } - /** - * Shifts the execution index if this pass's index is greater than the - * specified threshold. - *

      - * Used to alter the index if another pass was inserted below this in the same - * {@link com.jme3.renderer.framegraph.PassThread PassThread}. - *

      - * Called automatically. Do not use. - * - * @param threshold - * @param positive - */ - public void shiftExecutionIndex(int threshold, boolean positive) { - index.shiftQueue(threshold, positive); - } - /** - * Shifts the id of this pass. - *

      - * Used to ensure that all RenderPass ids are unique after loading from a save file. - *

      - * Called automatically. Do not use. - * - * @param shift - */ - public void shiftId(int shift) { - id += shift; - } - /** - * Sets the name of this pass. - * - * @param name - */ - public void setName(String name) { - this.name = name; - } - /** - * Sets the unique id of this pass. - *

      - * Called automatically. Do not use. - * - * @param id - */ - public void setId(int id) { - this.id = id; - } - /** - * Sets the id used when exporting. - *

      - * Export id counted from zero for each pass in the FrameGraph, which will not - * necessarily be globally unique or match the normal id. Only in use during - * export operations. - *

      - * Called automatically. Do not use. - * - * @param id - */ - public void setExportId(int id) { - this.exportId = id; - } - - /** - * Gets the name assigned to this RenderPass. - * - * @return - */ - public String getName() { - return name; - } /** * Gets the name given to a profiler, which may be more compact or informative. * @@ -862,86 +493,6 @@ public String getName() { public String getProfilerName() { return getName(); } - /** - * Gets the unique id of this pass. - * - * @return - */ - public int getId() { - return id; - } - /** - * Gets the export id of this pass used only during export operations. - * - * @return - */ - public int getExportId() { - return exportId; - } - /** - * Gets the index of this pass. - * - * @return - */ - public PassIndex getIndex() { - return index; - } - /** - * Returns true if this pass is assigned to a framegraph. - * - * @return - */ - public boolean isAssigned() { - return index != null; - } - /** - * Gets the number of active ticket groups in this pass. - * - * @return - */ - public int getNumGroups() { - return groups.size(); - } - - @Override - public PassIndex getExecutionIndex() { - return index; - } - @Override - public boolean dereference() { - refs--; - return isUsed(); - } - @Override - public boolean isUsed() { - return refs > 0; - } - @Override - public LinkedList getInputTickets() { - return inputs; - } - @Override - public LinkedList getOutputTickets() { - return outputs; - } - @Override - public String toString() { - return getClass().getSimpleName(); - } - @Override - public void write(JmeExporter ex) throws IOException { - OutputCapsule out = ex.getCapsule(this); - out.write((exportId >= 0 ? exportId : id), "id", -1); - out.write(name, "name", "RenderPass"); - write(out); - } - @Override - public void read(JmeImporter im) throws IOException { - InputCapsule in = im.getCapsule(this); - id = in.readInt("id", -1); - name = in.readString("name", "RenderPass"); - read(in); - } /** * Convenience method for writing pass properties to the output capsule. @@ -958,33 +509,6 @@ protected void write(OutputCapsule out) throws IOException {} */ protected void read(InputCapsule in) throws IOException {} - /** - * Gets the next generated id. - * - * @return - */ - public static int getNextId() { - return nextId; - } - - /** - * - * @param group - * @param i - * @return - */ - public static String groupTicketName(String group, int i) { - return group+'['+i+']'; - } - /** - * - * @param group - * @return - */ - public static String listTicketName(String group) { - return LIST_PREFIX+group; - } - private static class PassFrameBuffer { public static final String DEF_TAG = "#DefaultTag"; @@ -1018,63 +542,5 @@ public void dispose() { } } - private static class TicketGroup { - - public final String name; - public ResourceTicket[] array; - public boolean list = false; - - public TicketGroup(String name) { - this.name = name; - this.array = new ResourceTicket[0]; - this.list = true; - } - public TicketGroup(String name, int length) { - this.name = name; - this.array = new ResourceTicket[length]; - } - - public ResourceTicket create(int i) { - String tName; - if (!list) { - tName = groupTicketName(name, i); - } else { - tName = listTicketName(name); - } - return new ResourceTicket<>(tName, name); - } - - public ResourceTicket add() { - ResourceTicket[] temp = new ResourceTicket[array.length+1]; - System.arraycopy(array, 0, temp, 0, array.length); - array = temp; - return (array[array.length-1] = create(array.length-1)); - } - public int remove(ResourceTicket t) { - requireAsList(true); - int i = array.length-1; - for (; i >= 0; i--) { - if (array[i] == t) break; - } - if (i >= 0) { - ResourceTicket[] temp = new ResourceTicket[array.length-1]; - if (i > 0) { - System.arraycopy(array, 0, temp, 0, i); - } - if (i < array.length-1) { - System.arraycopy(array, i+1, temp, i, array.length-i-1); - } - array = temp; - } - return i; - } - - public void requireAsList(boolean asList) { - if (list != asList) { - throw new IllegalStateException("Group must be "+(asList ? "a list" : "an array")+" in this context."); - } - } - - } } diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java index 25a92302f8..08bb7cd9e3 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java +++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/passes/SceneEnqueuePass.java @@ -40,7 +40,7 @@ import com.jme3.light.LightList; import com.jme3.renderer.Camera; import com.jme3.renderer.ViewPort; -import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.DepthRange; import com.jme3.renderer.framegraph.FGRenderContext; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.GeometryQueue; @@ -95,7 +95,7 @@ public class SceneEnqueuePass extends RenderPass { TRANSLUCENT = "Translucent"; private boolean runControlRender = true; - private final HashMap buckets = new HashMap<>(); + private final HashMap queues = new HashMap<>(); private String defaultBucket = OPAQUE; /** @@ -122,14 +122,14 @@ public SceneEnqueuePass(boolean runControlRender, boolean useDefaultBuckets) { @Override protected void initialize(FrameGraph frameGraph) { - for (Queue b : buckets.values()) { + for (Queue b : queues.values()) { b.geometry = addOutput(b.name); b.lights = addOutput(b.name+"Lights"); } } @Override protected void prepare(FGRenderContext context) { - for (Queue b : buckets.values()) { + for (Queue b : queues.values()) { declare(null, b.geometry); declare(null, b.lights); } @@ -142,15 +142,14 @@ protected void execute(FGRenderContext context) { vp.getCamera().setPlaneState(0); queueSubScene(context, scenes.get(i), null); } - System.out.println("set queue resources"); - for (Queue b : buckets.values()) { + for (Queue b : queues.values()) { resources.setPrimitive(b.geometry, b.queue); resources.setPrimitive(b.lights, b.lightList); } } @Override protected void reset(FGRenderContext context) { - for (Queue b : buckets.values()) { + for (Queue b : queues.values()) { b.queue.clear(); b.lightList.clear(); } @@ -163,7 +162,7 @@ public void write(JmeExporter ex) throws IOException { OutputCapsule out = ex.getCapsule(this); out.write(runControlRender, "runControlRender", true); ArrayList list = new ArrayList<>(); - list.addAll(buckets.values()); + list.addAll(queues.values()); out.writeSavableArrayList(list, "buckets", new ArrayList<>()); out.write(defaultBucket, "defaultBucket", OPAQUE); } @@ -175,7 +174,7 @@ public void read(JmeImporter im) throws IOException { ArrayList list = in.readSavableArrayList("buckets", new ArrayList<>()); for (Savable s : list) { Queue b = (Queue)s; - buckets.put(b.name, b); + queues.put(b.name, b); } defaultBucket = in.readString("defaultBucket", OPAQUE); } @@ -192,10 +191,10 @@ private void queueSubScene(FGRenderContext context, Spatial spatial, String pare } // get target bucket String value = getSpatialBucket(spatial, parentBucket); - Queue bucket = (value != null ? buckets.get(value) : null); + Queue queue = (value != null ? queues.get(value) : null); // accumulate lights - if (bucket != null) for (Light l : spatial.getLocalLightList()) { - bucket.lightList.add(l); + if (queue != null) for (Light l : spatial.getLocalLightList()) { + queue.lightList.add(l); } if (spatial instanceof Node) { int camState = cam.getPlaneState(); @@ -204,13 +203,13 @@ private void queueSubScene(FGRenderContext context, Spatial spatial, String pare cam.setPlaneState(camState); queueSubScene(context, s, value); } - } else if (bucket != null && spatial instanceof Geometry) { + } else if (queue != null && spatial instanceof Geometry) { // add to the render queue Geometry g = (Geometry)spatial; if (g.getMaterial() == null) { throw new IllegalStateException("No material is set for Geometry: " + g.getName()); } - bucket.queue.add(g); + queue.queue.add(g); } } private String getSpatialBucket(Spatial spatial, String parentValue) { @@ -257,7 +256,7 @@ public final SceneEnqueuePass add(String name, GeometryComparator comparator, De if (isAssigned()) { throw new IllegalStateException("Cannot add buckets while assigned to a framegraph."); } - buckets.put(name, new Queue(name, comparator, depth, perspective)); + queues.put(name, new Queue(name, comparator, depth, perspective)); return this; } diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert index 0187b54681..651b349ab7 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/Screen.vert @@ -4,9 +4,11 @@ attribute vec3 inPosition; varying vec2 texCoord; +const vec2 sub = vec2(1.0); + void main() { texCoord = inPosition.xy; - vec2 pos = inPosition.xy * vec2(2.0) - vec2(1.0); + vec2 pos = inPosition.xy * 2.0 - sub; gl_Position = vec4(pos, 0.0, 1.0); } diff --git a/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java b/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java index d71f1e6989..07e5928959 100644 --- a/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java +++ b/jme3-effects/src/main/java/com/jme3/post/framegraph/BloomPass.java @@ -53,7 +53,7 @@ *

      * Inputs: *

        - *
      • Color ({@link Texture2D}): color texture to apply bloom effect to (optional).
      • + *
      • Color ({@link Texture2D}): color texture to apply bloom effect to.
      • *
      • Objects ({@link GeometryQueue}): specific geometries to apply bloom effect to (optional).
      • *
      * Outputs: @@ -84,6 +84,7 @@ protected void initialize(FrameGraph frameGraph) { inColor = addInput("Color"); objects = addInput("Objects"); result = addOutput("Color"); + midTex = new ResourceTicket("MiddleTex"); AssetManager assets = frameGraph.getAssetManager(); extractMat = new Material(assets, "Common/MatDefs/Post/BloomExtract.j3md"); hBlurMat = new Material(assets, "Common/MatDefs/Blur/HGaussianBlur.j3md"); @@ -93,7 +94,7 @@ protected void initialize(FrameGraph frameGraph) { @Override protected void prepare(FGRenderContext context) { declare(texDef, result); - declare(texDef, midTex); + declareTemporary(texDef, midTex); reserve(result, midTex); referenceOptional(inColor, objects); } @@ -111,7 +112,7 @@ protected void execute(FGRenderContext context) { FrameBuffer midFb = getFrameBuffer("mid", w, h, 1); Texture2D midTarget = resources.acquireColorTarget(midFb, midTex); GeometryQueue geometry = resources.acquireOrElse(objects, null); - Texture2D scene = resources.acquireOrElse(inColor, null); + Texture2D scene = resources.acquire(inColor); context.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha); // geometry render @@ -141,13 +142,13 @@ protected void execute(FGRenderContext context) { hBlurMat.setTexture("Texture", midTarget); hBlurMat.setFloat("Size", w); hBlurMat.setFloat("Scale", blurScale); - render(context, outFb, hBlurMat); + //render(context, outFb, hBlurMat); // vertical blur vBlurMat.setTexture("Texture", outTarget); vBlurMat.setFloat("Size", h); vBlurMat.setFloat("Scale", blurScale); - render(context, midFb, vBlurMat); + //render(context, midFb, vBlurMat); // final output outMat.setTexture("Texture", scene); @@ -186,6 +187,7 @@ public void read(JmeImporter im) throws IOException { private void render(FGRenderContext context, FrameBuffer fb, Material mat) { context.getRenderer().setFrameBuffer(fb); context.getRenderer().clearBuffers(true, true, true); + context.resizeCamera(fb.getWidth(), fb.getHeight(), false, false, false); context.renderFullscreen(mat); } diff --git a/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java index 0d974134da..4efe0d464b 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestDeferredShading.java @@ -12,7 +12,6 @@ import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; -import com.jme3.renderer.framegraph.PassLocator; import com.jme3.renderer.framegraph.light.TiledRenderGrid; import com.jme3.renderer.framegraph.passes.LightImagePass; import com.jme3.scene.Geometry; @@ -20,6 +19,7 @@ import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; import com.jme3.system.AppSettings; +import com.jme3.renderer.framegraph.modules.ModuleLocator; /** * https://en.wikipedia.org/wiki/Deferred_shading/ @@ -44,8 +44,8 @@ public static void main(String[] args) { public void simpleInitApp() { FrameGraph fg = FrameGraphFactory.deferred(assetManager, true, true); - fg.setJunctionSetting("LightPackMethod", true); - fg.get(PassLocator.by(LightImagePass.class)).setMaxLights(4096); + fg.enableFeature("LightPackMethod", true); + fg.get(ModuleLocator.by(LightImagePass.class)).setMaxLights(4096); fg.setSetting("TileInfo", new TiledRenderGrid(4, -1)); viewPort.setFrameGraph(fg); diff --git a/jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphImportExport.java b/jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphImportExport.java index 45acba407b..c7685d174e 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphImportExport.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestFrameGraphImportExport.java @@ -83,9 +83,9 @@ public void simpleInitApp() { FrameGraph graph = FrameGraphFactory.forward(assetManager); try { if (xml) { - XMLExporter.getInstance().save(graph.createData(), file); + XMLExporter.getInstance().save(graph.createModuleData(), file); } else { - BinaryExporter.getInstance().save(graph.createData(), file); + BinaryExporter.getInstance().save(graph.createModuleData(), file); } } catch (IOException ex) { Logger.getLogger(TestFrameGraphImportExport.class.getName()).log(Level.SEVERE, null, ex); diff --git a/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java index a1240011df..4f6eadc0ba 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestPBRTerrainRenderPath.java @@ -50,7 +50,6 @@ import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; -import com.jme3.renderer.framegraph.PassLocator; import com.jme3.renderer.framegraph.light.TiledRenderGrid; import com.jme3.renderer.framegraph.passes.LightImagePass; import com.jme3.system.AppSettings; @@ -61,6 +60,7 @@ import com.jme3.terrain.heightmap.ImageBasedHeightMap; import com.jme3.texture.Texture; import com.jme3.texture.Texture.WrapMode; +import com.jme3.renderer.framegraph.modules.ModuleLocator; /** * This test uses 'PBRTerrain.j3md' to create a terrain Material for PBR. @@ -201,7 +201,7 @@ else if(name.equals("addPointLight") && !pressed){ public void simpleInitApp() { FrameGraph fg = FrameGraphFactory.deferred(assetManager, true); - fg.get(PassLocator.by(LightImagePass.class)).setMaxLights(1024); + fg.get(ModuleLocator.by(LightImagePass.class)).setMaxLights(1024); fg.setSetting("TileInfo", new TiledRenderGrid(7, -1)); //viewPort.setFrameGraph(fg); flyCam.setDragToRotate(true); diff --git a/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java index 893fabae54..dddf37a3d9 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/TestSimpleDeferredLighting.java @@ -54,7 +54,6 @@ import com.jme3.post.filters.ToneMapFilter; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.FrameGraphFactory; -import com.jme3.renderer.framegraph.PassLocator; import com.jme3.renderer.framegraph.debug.GraphEventCapture; import com.jme3.renderer.framegraph.passes.Junction; import com.jme3.renderer.queue.RenderQueue; @@ -74,6 +73,7 @@ import com.jme3.util.TangentBinormalGenerator; import com.jme3.util.mikktspace.MikktspaceTangentGenerator; import java.io.File; +import com.jme3.renderer.framegraph.modules.ModuleLocator; public class TestSimpleDeferredLighting extends SimpleApplication implements ActionListener { @@ -677,7 +677,7 @@ public void simpleInitApp() { rootNode.addLight(new AmbientLight(ColorRGBA.White)); - Junction lightingMethod = deferred.get(PassLocator.by(Junction.class, "LightPackMethod")); + Junction lightingMethod = deferred.get(ModuleLocator.by(Junction.class, "LightPackMethod")); //lightingMethod.setIndexSource((fg, vp) -> 0); File capTarget = new File(System.getProperty("user.home")+"/earlyFrameCapture.txt"); diff --git a/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java b/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java index 12ba25c00f..feecfccb70 100644 --- a/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java +++ b/jme3-examples/src/main/java/jme3test/framegraph/sandbox/Main.java @@ -11,7 +11,7 @@ import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.post.framegraph.CartoonEdgePass; -import com.jme3.renderer.framegraph.DepthRange; +import com.jme3.renderer.DepthRange; import com.jme3.renderer.framegraph.FrameGraph; import com.jme3.renderer.framegraph.passes.GeometryPass; import com.jme3.renderer.framegraph.passes.OutputPass;