[SOLVED]I want something divine like

Hi monkeys, I got a strange idea in mind.

I was in fog, I can’t see things clearly.

But among them, there is a thing I can see it very clear in a far distance, just like a divine.

My question is:

Is there any way to let one of the cubes not be affected by the FogFilter?

My code.

package net.jmecn.effect;

import com.jme3.app.SimpleApplication;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
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.FogFilter;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Quad;

public class HelloFog extends SimpleApplication {

    @Override
    public void simpleInitApp() {
        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
        fpp.setNumSamples(4);
        viewPort.addProcessor(fpp);

        FogFilter fog = new FogFilter(ColorRGBA.White, 1.5f, 20f);
        fpp.addFilter(fog);

        createScene();

        addLights();
        
        flyCam.setMoveSpeed(10f);
    }

    private void createScene() {
        Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

        Geometry geom = new Geometry("Floor", new Quad(40, 40));
        geom.setMaterial(mat);
        geom.rotate(-FastMath.HALF_PI, 0, 0);
        rootNode.attachChild(geom);

        for (int y = 0; y < 30; y += 4) {
            for (int x = 0; x < 30; x += 4) {
                geom = new Geometry("Cube", new Box(0.5f, 0.5f, 0.5f));
                geom.setMaterial(mat);
                geom.move(x + 4, 0.5f, -y - 4);
                rootNode.attachChild(geom);
            }
        }
    }

    private void addLights() {
        DirectionalLight sunLight = new DirectionalLight();
        sunLight.setDirection(new Vector3f(-1, -2, -3).normalizeLocal());
        sunLight.setColor(new ColorRGBA(0.8f, 0.8f, 0.8f, 1f));

        AmbientLight ambientLight = new AmbientLight();
        ambientLight.setColor(new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));

        rootNode.addLight(sunLight);
        rootNode.addLight(ambientLight);
    }

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

}
1 Like

Try placing a light in that position.

1 Like

Short answer : no.

Long answer 1: You could drop the fog filter and compute the fog in every materials of the scene. Meaning changing the lighting j3md so that it computes the fog (maybe the sky material too…if you have one). Add a define to the shader to switch fog on off, then switch it off for your particular cube.

Long answer 2: Keep the filter but overlay another viewport on top of it. and render your cube in this viewport while the rest of the scene is rendered in the background viewport. There may be some frame buffer wiring to do to setup this correctly but it might work.

there could be a long answer 3 where you would render a stencil mask in the lighting.frag then read it in the fog filter shader… but IMO that doubles the work of the 2 previous answers.

Answer 2 might be the easiest one…

4 Likes

Thank you!
May I ask some examples about how to do it in the 2nd way?

1 Like

this should be a good start`

1 Like

Thanks again.
I have learned this example long ago, I still want to learn about how to overlay another viewport on top of it.

Add custom SceneProcessor at the end of the pipeline. Rerender your geometry there using default technique. This is how I made this (highlight on item in the middle):

4 Likes
      ViewPort view2 = renderManager.createMainView("overlay", camera);//use the same viewport camera
      view2.setClearFlags(false, false, false); // set it to not clear the colors/depth/stencil rendered by the first viewport
      view2.attachScene(cube);

Edit: Note that you have to call updateLogicalState() and updateGeometricState() on the cube on each update though.

2 Likes

and this is long answer 4 :stuck_out_tongue:

1 Like

Not that long, only 150+ lines of code :wink: Mostly overriding empty functions.

1 Like

Thank you. I’m also reading the source code of WaterFilter. This filter seems using another viewPort too.

1 Like

Yes but it’s not related, it’s to compute the reflection on the water. Don’t use this it’s gonna be misleading.

1 Like

awesome! I will try this one day!

1 Like

but not now…it is 3:06 AM here, I will do in the daytime.
Again, thanks for your advices.

2 Likes

It’s like three lines of code to add fog to a regular shader and is technically the “right answer”. You will have so much more control this way… whether letting lights not have fog or using different fog colors for different objects, etc…

To me, it is by far the easiest way… to the point where this is 100% how I’ve always done fog in JME and only used the FogFilter once for about 5 seconds 6+ years ago.

1 Like

Good morning/afternoon/night monkeys. I’m back.

1. Using Overlay viewport

I first tried with overlay viewport. This is the result, and here is the code: TestOverlayViewport.java

It looks fine at first, but quickly I realized the problem.

As the subscene is rendered in another viewport, it mean spatials in root scene wont obscured my vision. It is OVERLAY.

Although it’s not what I want, but it make the cube more divine like in my eyes. I feel it was saying “I am what I am”. :smirk:

2. Using fog shader

I seems to be the easiest way. But if you never learned about GLSL…

You should learn it! :smiley:

I wrote a simple fog shader, and using it to switch on/off the fog effect as your advise.

The VertexShader.

https://github.com/jmecn/jME3Tutorials/blob/master/src/main/resources/Materials/Fog/Fog.vert

The FragmentShader

The MaterialDefine

The test code.

3. Using fog shader with lighting.j3dm

It’s not too hard to make a fog shader, but soon I’m facing another problem:

How to apply the fog shader with Lighting.j3md or Unshaded.j3md? :confused:

I think the surest way is to rewrite the Lighting.vert / Lighting.frag, and add fog shader into it. But before that I wanna try to reuse the code.

Maybe I can:

  1. Only rewrite a .j3md file and add a Technique to it, is a Technique equals a Pass?
  2. Make a FogControl and override the controlRender method?
  3. or SceneProcessor?

I tried the 1st way, but I failed.

FATAL: Uncaught exception thrown in Thread[jME3 Main,5,main]
com.jme3.asset.AssetLoadException: An exception has occured while loading asset: 
Materials/Fog/Lighting.j3md
    at 
com.jme3.asset.DesktopAssetManager.loadLocatedAsset(DesktopAssetManager.java:261)
	at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:373)
	at com.jme3.material.Material.<init>(Material.java:108)
    at net.jmecn.effect.TestFogLightingShader.createScene(TestFogLightingShader.java:42)
	at net.jmecn.effect.TestFogLightingShader.simpleInitApp(TestFogLightingShader.java:26)
	at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:220)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:211)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: Shader statement syntax incorrect: VertexShader GLSL100 
GLSL150:   Common/MatDefs/Light/SPLighting.vert
	at com.jme3.material.plugins.J3MLoader.readShaderStatement(J3MLoader.java:103)
	at com.jme3.material.plugins.J3MLoader.readTechniqueStatement(J3MLoader.java:543)
	at com.jme3.material.plugins.J3MLoader.readTechnique(J3MLoader.java:613)
	at com.jme3.material.plugins.J3MLoader.loadFromRoot(J3MLoader.java:736)
	at com.jme3.material.plugins.J3MLoader.load(J3MLoader.java:757)
	at 
com.jme3.asset.DesktopAssetManager.loadLocatedAsset(DesktopAssetManager.java:259)
	... 8 more

What I did is just copied the Lighting.j3md and add some MaterialParameters and one Technique at end of the file. This is my code.

The exception confused me, why it happend? I read the source of J3MLoader#readShaderStatement, then I’m more confused…

I modified every statement with mult GLSL Version declaration…

VertexShader GLSL100 GLSL150:   Common/MatDefs/Light/SPLighting.vert
FragmentShader GLSL100 GLSL150: Common/MatDefs/Light/SPLighting.frag

to this.

VertexShader GLSL100 :   Common/MatDefs/Light/SPLighting.vert
FragmentShader GLSL100 : Common/MatDefs/Light/SPLighting.frag

Run again, the exception disappeared. But I didn’t got what I want. There is no fog at all.

I tried to invoke Material#selectTechnique("Fog", renderManager); method, but it disabled the Default Technique.

	geom.addControl(new AbstractControl() {

		@Override
		protected void controlUpdate(float tpf) {
			// TODO Auto-generated method stub
					
		}

		@Override
		protected void controlRender(RenderManager rm, ViewPort vp) {
			Geometry geom = (Geometry)spatial;
			geom.getMaterial().selectTechnique("Fog", renderManager);
		}
            	
    });

So, is there a way I can add a pass after Lighting shader?

Anyway, I rewrite the Lighting.vert and Lighting.frag to add fog shader.

In Lighting.vert I add these:

#ifdef USE_FOG
    uniform float m_FogDensity;

    varying float fogFactor;

    const float LOG2 = 1.442695;
#endif

void main(){
    // ...    
    #ifdef USE_FOG
        fogFactor = exp2(-m_FogDensity * m_FogDensity * wvPosition.z *  wvPosition.z * LOG2 );
        fogFactor = clamp(fogFactor, 0.0, 1.0);
    #endif  
}

Lighting.frag

#ifdef USE_FOG
    uniform vec4 m_FogColor;
    varying float fogFactor;
#endif

void main(){
    // ...
    #ifdef USE_FOG
        gl_FragColor = mix(m_FogColor, gl_FragColor, fogFactor);
    #endif
}

Also I add MaterialParameters to the default Technique. Now it works as my wish.

4. Using ShaderNode (Not yet)

I searched the wiki, and found this article.

http://jmonkeyengine.github.io/wiki/jme3/advanced/jme3_shadernodes.html

It tell just what exactly I want one hour ago.

I even find a already made fog shader node…

And, an example tells how to use shader node.

Why I have waste so much time doing all above… :joy:

2 Likes

So… where exactly is YOUR version of this file located? Probably not at that path…

1 Like

Oh, I’m too excited about what learned today that I forget to paste the source.

TestFogLightingShader.java

Materials/Fog/Lighting.j3md

Materials/Fog/Lighting.frag

Materials/Fog/Lighting.vert

1 Like

Note the difference between that and:

Seems like you aren’t even using the .vert file that you mean to.

If you were getting errors about that before then you might be running single-pass lighting instead of multipass.

1 Like

I didn’t modified this file. It’s in the jme3-core-3.1.0-stable.jar.

1 Like