Enhancements to the JME3 Rendering Engine

The frameGraph is designed to be configurable, I just mean: the built-in rendering pipeline in JME should be Full Feature (includes all graphics features) pipeline, just like JME3 has a default PBRLighting.j3md, then users can not use it, but use their own SimplePBRLighting.j3md.

I wrote related test cases in an independent branch, this branch is created for developing the future Mult-Pass module.
The following is a custom GBuffer, using only 3 RTs, two 16f RTs and one DepthRT:

/**
 * This code demonstrates how to define a custom GBufferPass.
 * @author JhonKkk
 */
public class CustomGBufferPass extends GBufferPass {
    CustomGBufferPass(){
        super("CustomGBufferPass");
    }
    @Override
    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){
            // recreate
            gBufferData0 = new Texture2D(w, h, Image.Format.RGBA16F);
            gBufferData1 = new Texture2D(w, h, Image.Format.RGBA16F);
            this.getSinks().clear();
            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 rt4 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData4);
            gBuffer.addColorTarget(rt0);
            gBuffer.addColorTarget(rt1);
            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_4, rt4));
            registerSource(new DeferredLightDataSource(S_LIGHT_DATA, lightData));
            bHasDrawVarSource = new FGVarSource<Boolean>(S_EXECUTE_STATE, bHasDraw);
            registerSource(bHasDrawVarSource);
            registerSource(new FGFramebufferSource(S_FB, gBuffer));
        }
    }
}

After that you can create your own FrameGraph in two ways, one is to fully organize the FrameGraph yourselfļ¼ˆThis method allows you to override the default FrameGraph completely, and organize required Passes dynamically.ļ¼‰, as follows:

public class TestCustomPipeline extends SimpleApplication {
    private FrameGraph customFrameGraph;
    // ------------------------------ā†“In this example, we only customize the GBufferPass, so get the other built-in Passes from the system
    private DeferredShadingPass defaultDeferredShadingPass;
    private TileDeferredShadingPass defaultTileDeferredShadingPass;
    private OpaquePass defaultOpaquePass;
    private SkyPass defaultSkyPass;
    private TransparentPass defaultTransparentPass;
    private GuiPass defaultGuiPass;
    private PostProcessorPass defaultPostProcessorPass;
    // ------------------------------ā†‘In this example, we only customize the GBufferPass, so get the other built-in Passes from the system
    private CustomGBufferPass customGBufferPass;
    @Override
    public void simpleUpdate(float tpf) {
        super.simpleUpdate(tpf);
        if(customFrameGraph != null){
            // Switch rendering path per frame, reorganize FrameGraph, noteworthy is, no need to add all system FramePasses, just a minimal test case.
            customFrameGraph.reset();
            if(renderManager.getRenderPath() == RenderManager.RenderPath.Deferred){
                customFrameGraph.addPass(customGBufferPass);
                defaultDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_0, customGBufferPass.getName() + "." + GBufferPass.S_RT_0);
                defaultDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_1, customGBufferPass.getName() + "." + GBufferPass.S_RT_1);
                defaultDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_4, customGBufferPass.getName() + "." + GBufferPass.S_RT_4);
                defaultDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_LIGHT_DATA, customGBufferPass.getName() + "." + GBufferPass.S_LIGHT_DATA);
                defaultDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_EXECUTE_STATE, customGBufferPass.getName() + "." + GBufferPass.S_EXECUTE_STATE);
                defaultDeferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, customGBufferPass.getName() + "." + GBufferPass.S_FB);
                customFrameGraph.addPass(defaultDeferredShadingPass);
            }
            else if(renderManager.getRenderPath() == RenderManager.RenderPath.TiledDeferred){
                customFrameGraph.addPass(customGBufferPass);
                defaultTileDeferredShadingPass.setSinkLinkage(TileDeferredShadingPass.S_RT_0, customGBufferPass.getName() + "." + GBufferPass.S_RT_0);
                defaultTileDeferredShadingPass.setSinkLinkage(TileDeferredShadingPass.S_RT_1, customGBufferPass.getName() + "." + GBufferPass.S_RT_1);
                defaultTileDeferredShadingPass.setSinkLinkage(TileDeferredShadingPass.S_RT_4, customGBufferPass.getName() + "." + GBufferPass.S_RT_4);
                defaultTileDeferredShadingPass.setSinkLinkage(TileDeferredShadingPass.S_LIGHT_DATA, customGBufferPass.getName() + "." + GBufferPass.S_LIGHT_DATA);
                defaultTileDeferredShadingPass.setSinkLinkage(TileDeferredShadingPass.S_EXECUTE_STATE, customGBufferPass.getName() + "." + GBufferPass.S_EXECUTE_STATE);
                defaultTileDeferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, customGBufferPass.getName() + "." + GBufferPass.S_FB);
                customFrameGraph.addPass(defaultTileDeferredShadingPass);
            }
            customFrameGraph.addPass(defaultOpaquePass);
            customFrameGraph.addPass(defaultSkyPass);
            customFrameGraph.addPass(defaultTransparentPass);
            customFrameGraph.addPass(defaultGuiPass);
            customFrameGraph.addPass(defaultPostProcessorPass);
        }
    }

    private final void setupScene(){
        Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
        TangentBinormalGenerator.generate(teapot.getMesh(), true);

        teapot.setLocalScale(2f);
        renderManager.setSinglePassLightBatchSize(1);
        Material mat = new Material(assetManager, "jme3test/materials/MyCustomLighting.j3md");
        mat.setFloat("Shininess", 25);
        cam.setLocation(new Vector3f(0.015041917f, 0.4572918f, 5.2874837f));
        cam.setRotation(new Quaternion(-1.8875003E-4f, 0.99882424f, 0.04832061f, 0.0039016632f));

        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 final void setupCustomFrameGraph(){
        customFrameGraph = new FrameGraph(new FGRenderContext(renderManager, null, viewPort));
        defaultDeferredShadingPass = FGBuilderTool.findPass(DeferredShadingPass.class);
        defaultTileDeferredShadingPass = FGBuilderTool.findPass(TileDeferredShadingPass.class);
        // Redefine the overloaded material definition used by the custom ShadingModel here.
        if(defaultDeferredShadingPass != null){
            defaultDeferredShadingPass.setOverlyMat(new Material((MaterialDef) assetManager.loadAsset("jme3test/materials/MyCustomDeferredShading.j3md")));
            defaultDeferredShadingPass.reset();
            defaultDeferredShadingPass.getSinks().clear();
            defaultDeferredShadingPass.getBinds().clear();
            defaultDeferredShadingPass.init();
        }
        if(defaultTileDeferredShadingPass != null){
            defaultTileDeferredShadingPass.setOverlyMat(new Material((MaterialDef) assetManager.loadAsset("jme3test/materials/MyCustomTileBasedDeferredShading.j3md")));
            defaultTileDeferredShadingPass.reset();
            defaultTileDeferredShadingPass.getSinks().clear();
            defaultTileDeferredShadingPass.getBinds().clear();
            defaultTileDeferredShadingPass.init();
        }
        defaultOpaquePass = FGBuilderTool.findPass(OpaquePass.class);
        defaultSkyPass = FGBuilderTool.findPass(SkyPass.class);
        defaultTransparentPass = FGBuilderTool.findPass(TransparentPass.class);
        defaultGuiPass = FGBuilderTool.findPass(GuiPass.class);
        defaultPostProcessorPass = FGBuilderTool.findPass(PostProcessorPass.class);
        customGBufferPass = new CustomGBufferPass();
        FGBuilderTool.registerPass(CustomGBufferPass.class, customGBufferPass);
        viewPort.setFrameGraph(customFrameGraph);
        flyCam.setMoveSpeed(10.0f);
        renderManager.setRenderPath(RenderManager.RenderPath.Deferred);
        new RenderPathHelper(this, new Vector3f(10, cam.getHeight() - 10, 0), KeyInput.KEY_SPACE, "SPACE");
    }

    @Override
    public void simpleInitApp() {
        setupScene();
        setupCustomFrameGraph();
    }

    public static void main(String[] args) {
        TestCustomPipeline testCustomPipeline = new TestCustomPipeline();
        testCustomPipeline.start();
    }
}

The other method is to set the CustomGBufferPass as overridden, that is, replace the built-in default GBufferPass:

/**
 * Custom SimplePipeline, this example demonstrates the basic usage of CustomPipeline by customizing a GBufferPass.
 * @author JhonKkk
 */
public class TestSimplePipeline extends SimpleApplication {
    private CustomGBufferPass customGBufferPass;
    @Override
    public void simpleUpdate(float tpf) {
        super.simpleUpdate(tpf);
    }

    private final void setupScene(){
        Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
        TangentBinormalGenerator.generate(teapot.getMesh(), true);

        teapot.setLocalScale(2f);
        renderManager.setSinglePassLightBatchSize(1);
        Material mat = new Material(assetManager, "jme3test/materials/MyCustomLighting.j3md");
        mat.setFloat("Shininess", 25);
        cam.setLocation(new Vector3f(0.015041917f, 0.4572918f, 5.2874837f));
        cam.setRotation(new Quaternion(-1.8875003E-4f, 0.99882424f, 0.04832061f, 0.0039016632f));

        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 final void setupCustomFrameGraph(){
        DeferredShadingPass defaultDeferredShadingPass = FGBuilderTool.findPass(DeferredShadingPass.class);
        TileDeferredShadingPass defaultTileDeferredShadingPass = FGBuilderTool.findPass(TileDeferredShadingPass.class);
        // Redefine the overloaded material definition used by the custom ShadingModel here.
        if(defaultDeferredShadingPass != null){
            defaultDeferredShadingPass.setOverlyMat(new Material((MaterialDef) assetManager.loadAsset("jme3test/materials/MyCustomDeferredShading.j3md")));
            defaultDeferredShadingPass.reset();
            defaultDeferredShadingPass.getSinks().clear();
            defaultDeferredShadingPass.getBinds().clear();
            defaultDeferredShadingPass.init();
        }
        if(defaultTileDeferredShadingPass != null){
            defaultTileDeferredShadingPass.setOverlyMat(new Material((MaterialDef) assetManager.loadAsset("jme3test/materials/MyCustomTileBasedDeferredShading.j3md")));
            defaultTileDeferredShadingPass.reset();
            defaultTileDeferredShadingPass.getSinks().clear();
            defaultTileDeferredShadingPass.getBinds().clear();
            defaultTileDeferredShadingPass.init();
        }
        customGBufferPass = new CustomGBufferPass();
        // Override the default GBufferPass
        FGBuilderTool.registerPass(GBufferPass.class, customGBufferPass);
        flyCam.setMoveSpeed(10.0f);
        renderManager.setRenderPath(RenderManager.RenderPath.Deferred);
        new RenderPathHelper(this, new Vector3f(10, cam.getHeight() - 10, 0), KeyInput.KEY_SPACE, "SPACE");
    }

    @Override
    public void simpleInitApp() {
        setupScene();
        setupCustomFrameGraph();
    }

    public static void main(String[] args) {
        TestCustomPipeline testCustomPipeline = new TestCustomPipeline();
        testCustomPipeline.start();
    }
}

If you donā€™t pack the GBuffer in the default way, you need to override the default TileBasedDeferredShading (e.g. MyCustomTileBasedDeferredShading here) and DeferredShading (e.g. MyCustomDeferredShading here), then parse the GBuffer and corresponding ShadingModel in your own way:

void main(){
    vec2 innerTexCoord;
#if defined(USE_LIGHTS_CULL_MODE)
    innerTexCoord = gl_FragCoord.xy * g_ResolutionInverse;
#else
    innerTexCoord = texCoord;
#endif
    // unpack GBuffer
    vec4 buff0 = texture2D(Context_InGBuff0, innerTexCoord);
    vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord);
    int shadingModelId = int(floor(buff0.a));
    if(shadingModelId == MY_CUSTOM_PHONG_LIGHTING){
        vec3 vPos = getPosition(innerTexCoord, viewProjectionMatrixInverse);
        vec4 diffuseColor = buff0;
        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 = min(fract(diffuseColor.a) * 100.0f, 0.0f);
        vec3 normal = -approximateNormal(vPos, innerTexCoord, viewProjectionMatrixInverse).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;
        float lightTexSizeInv = 1.0f / (float(lightNum) - 1.0f);
        #endif

        // These built-in resolvers will be encapsulated into .glsllib in future versions, for you to directly utilize tileBasedFunction without copying.
        // 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, gridIndex).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 += int(temp / float(g_TileLightOffsetSize));
                    temp = float(int(temp) % g_TileLightOffsetSize);
                }
                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);

                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
            }
        }
    }
    else{
        // todo:Calling the shading model library function encapsulated inside the system
        gl_FragColor = vec4(0.0f, 0.0f, 0.0f, 1);
    }
}

Below are the RenderDoc data in custom DeferredShading and custom Tile-Based DeferredShading:



You can find related test code in this development branch.dev-tech-multi-pass-lab
They are located in the examples/pipeline folder.

5 Likes

First of all, could you please stop posting stuff you did on various other branches and refer to the pull request if thats what you want to have reviewed?

So i took the time to look to the other branch as well:
The way i can use custom framegraphs is to overwrite the once you hardcoded in rendermanager?

I really think you made a bad design choice to hardcode your first class citizen framegraphs into rendermanager. As you can see you had to add a bunch of tools, static accessors to be able to use a custom framegraph at all. I think that all is unnecessary and you made your life harder by not working out a clean integration in the first place.

Please take a step back and review your current integration.

ViewPort{
 FrameGraph fg;
 set/get fg
}

RenderManager{
 if(viewport.getFg!=null){
  renderWithFG
 }else{
   renderTheOldWay
 }
}

To be honest, i think a code similar to that above would be enough to

  • enable FG rendering
  • having different FGā€™s for each viewport.
  • setting up custom FGā€™s the same way the already build in are setup
  • no need for overwriting/replacing hard coded things.

Note, because there might be a naming issue, a jme viewport is only minimal related to a viewport in all the graphic apis

The current FG system is an early version, and now you are asking for the final product. During this transition period, I need to add intermediate artifacts like a FG member variable in RenderManager to facilitate my development and test the compatibility of the rendering path, rather than handling stuff like overriding FG in each Viewport first.
Perhaps you should have seen that I added renderPath in Viewport, but it is actually not used yet. The final version would be:
Viewport{
RenderPath renderPath;
FrameGraph frameGraph;
}
Please note this is not my priority work right now. My priority is: RenderPath ā†’ GI ā†’ VRS ā†’ Occlusion Culling ā†’ Mult-Pass. I will complete the final FG version during Mult-Pass; Also please note currently itā€™s just me alone, if anyone has time I think we could develop this part together, maybe you or someone else familiar with this code should develop this part, otherwise, currently I need some intermediate artifacts (but not too much impact to application layer) like adding a FG member variable in RenderManager to facilitate development of the above modules.

5 Likes

So, how should we proceed with the code review / merging process?

On any thing i said up to now the response is it is going to be done differently in the final product.

So i am basically reviewing code you already know you are going to remove again

I hope these features could transition gradually from JM3 ā†’ JME4, rather than after I complete the final version, require you to port everything from JME3 to JME4 all at once. Perhaps this idea is just my personal ideal. Maybe we should take your suggestion to keep the PR open for 2+ years, review slowly, until you feel all the technologies here are finalized (final RenderPath, final GI, final VRS, final Mult-passā€¦). To be honest, Iā€™m not sure if others could understand what I mean by ā€œgradual transition from JME3 to JME4ā€, this is just my vision.

3 Likes

I hope you see the dilemma i am in reviewing the code. Basically i have two options:

  1. Approving ā€œdirtyā€ code to be merged in the hope you are going to fix it later
  2. Voting against a merge and take the shitstorm

I understand what you are saying, and I appreciate everyoneā€™s hard work reviewing my ā€œearlyā€ code. However, I have chosen the path of ā€œgradually improving the technologyā€ rather than spending 1 year all at once to complete the final version of all technologies and announcing that everyone can try ā€œitā€. I am not sure which of these two approaches benefits us the most at this stage, but I have chosen the former path. You can vote to reject the merge (if you get backlash from others for doing so, I cannot compensate you for the mental abuse you may receive - I can only apologize to you here), that is fine. I also allow this PR to exist for 1 year or even 2 years or more, and everyone can still see the code I will gradually submit later on this PR (assuming the PR exists for over 1 year, then more code will be submitted to the PR later on, not just the rendering path and basic FG), rather than uploading thousands of Java files at once. I hope the whole thing is a gradual process.

6 Likes

No need to worry about that :wink: i am fairly stable

This is a nice gesture, but i hope for another solution, it would also be beneficial to have a test group. Also people seems to be eager to throw 1000 lights in their games. I will think about it

1 Like

Perhaps new technologies should not be implemented through PRs. I thought of a solution, but I donā€™t have the authority to do it. The solution may not be the best, but how about creating a jme3-lab branch where new technologies can incubate, and regular new versions can be released, such as jme3-core3.7.jar and jme3-core3.7-lab.jar. The jme3-lab branch would regularly merge changes from the jme3-master branch, and the lab branch release cycle would be higher than the jme3-master branch. This way, users could quickly test the lab versions.
Another solution, which I mentioned in another post that you may have missed: Continue using PRs. The PRs may take a very long time before merging into master, and the contents of the PRs may not be the final versions. In the meantime, users could test and provide feedback using something like jhonkkk-jme3-core.jar through maven, but this solution has a big problem - other than the people in this post, most users may not even know that libraries like jhonkkk-jme3-core.jar exist.

4 Likes

There is also the option that you go the last meter and interage it cleanly. (for the current pr not that much work)

No unused stuff, no hardcoding. minimal required code changes to the already existing files.

Current Idea:

If this PRs would go into release like you planned, then everything would work fine. Both non-topic-active-readers would know about this and still could test and provide feedback in reasonable amount of time.

About Idea 1:
We could go this way, but then in future time you might need more ā€œalternativeā€ packages than just ā€œ-coreā€ ones. Depends what features you might want add.

For example if you would be at stage of ā€œrender backendsā€ later. This might be problematic way to go.

You mean the ones that can merge? could if possible to resolve conflicts easly.

About Idea 2:

The PRs may take a very long time before merging into master, and the contents of the PRs may not be the final versions. In the meantime, users could test and provide feedback using something like jhonkkk-jme3-core.jar through maven, but this solution has a big problem - other than the people in this post, most users may not even know that libraries like jhonkkk-jme3-core.jar exist.

Yes its not the best idea, tho based on history at least PRs like this were merged finally.
I think it would be better if it stay like it is now, so 1.0 and 2.0 and etc PRs.

Idea 3:
like @danielp and @yan said:

This is something Iā€™ve been pondering over for a while now, and Iā€™m leaning towards forking for jME 4. I expect that jME 4 is likely to have some pretty major architectural changes, so I think itā€™s likely to widely diverge from the existing codebase. At some point having two wildly divergent branches in the same repo seems counterproductive. Iā€™m not hard set in that opinion, and of course it will be some time before we know just how extensive major changes are likely to be.

That is not bad idea too.

At least i prefer when there is some logical conversation that help this Improvement.

There were 4 code rewiewers and for sure more non-commented ones so far.

Well, this is exactly what Code Check is for. But referring to some specific code, not generally.

Its same here, comment every area what and how generally to change or if move to later 2.0 stage / etc.

By just telling general things like this without marking any specific code lines, imo its not how-to-do code check. If there is specific comment, then author can also explain why exactly this part of code.

We can just tell ā€œdo this betterā€, ā€œless codeā€, ā€œadd it for laterā€, but it should refer to specific lines of code or files.

So I belive this should be more speficic here. If you say its not much work, then i belive you can refer to specific code per point you said here.

1 Like

I personally vote for merging JhonKkk PR into master. The sooner we get and test the cool stuff, the better. Any other solution will just slow down things or create confusion.

The current 3.6 version is always available and isnā€™t going anywhere.

13 Likes

+1

1 Like

+++1

4 Likes

Iā€™m with you in spirit. However, there is still some unresolved discussion at GitHub.

1 Like

I guess that is my issue, i am going to write a in depth resume later the evening. Then you can do whatever you like. I am out of this story.

There is still an java DONā€™T in the code where every IDE i know shows a bit fat warning. Since nobody else found it yet i assume i am the only one that checked the code actually out.

Would be great if somebody else REALLY code reviews it. (Keeping in mind that this is supposed to be the new rendering spine for the future and not some utility library) You as a gamedev are supposed to setup the framegraph to match your needs, and not just enable it.

thats exactly the problem.

You should use Code Check and point out every line issue. Like many people did, and you might also not notice their pointed out issues.

But you just say ā€œah there is one issue line but i will hide this from othersā€

I just hope instead of personal reasons and stealing code, you could even share code and make Code Check properly commenting specific lines and pointing out your ā€œhidden issue lineā€.

Because all i see is personal reason to block this PR.

Just make this code check how it should be - it is write every issue related to lines/code you see on github code check process.

No, the problem is that people like you would like to force a merge trough public demand without even looking at the code. I have not yet seen a single argument beside ā€œI want thisā€

Anyway, i stated my points on the PR, and i am out of this

noone ever forces anything.

But if you hide noticed issues and do not even make code check properly just saying ā€œcode is ā€œdirtyā€ā€

i hope you will just make code check properly, thats all.

And again on github you just wrote general comment without any specific code related linked. Again.

This is Incorrect Code check. Code check refer to specific code.

Up to this point the discussion with JohnLKKK have always been productive. I think he understands quite well what issues i have. If you donā€™t get it. Its not my problem.

Should i link RenderManager.java for you?