[SHADER] Screen Space Reflections for JME


#1

Hello,
In the last 3 days i’ve been working on an SSR shader that does simple raymarching in world space. It is still far from perfect, expecially with high frequency normals, but i suppose it might be a starting point for other people interested in this effect, for this reason i’m opensourcing it. (it is not required by the license, but if you manage to improve it, you are welcome to share it back :wink: )

In my game i don’t use JME’s filter system, and i don’t know how to use it, so you will have to implement your own java part. The usage is quite simple and explained below.

Rendering the reflection scene

The material used for this pass is ssr.j3md

What you need in order to make this work is

  1. The texture containing the color buffer of your scene (what is rendered with outFragColor)
  2. The texture containing the depth buffer of your scene

Optional requirement

  1. A texture containing X and Y components of the world space normals of your scene encoded in R and G channels and glossiness encoded in the B channel

If this texture is not provided, the shader will approximate the normals using the depth buffer

You will have also to provide the following vars

  • SceneViewProjectionMatrixInverse
  • SceneViewProjectionMatrix
  • CameraPosition
  • FrustumNearFar.

The extract below shows the code for my postprocessing pipeline

in("Scene", /** TEXTURE CONTAINING YOUR SCENE **/);

in("SceneDepth", /** TEXTURE CONTAINING THE DEPTH OF YOUR SCENE **/);

// OPTIONAL
// in("SceneNormals", /** TEXTURE CONTAINING THE WORLD NORMALS in RG and GLOSSINESS in B **/);

in("SceneViewProjectionMatrixInverse", 
  camera.getViewProjectionMatrix().invert()
);
		
in("SceneViewProjectionMatrix", 
  camera.getViewProjectionMatrix().clone()
);

in("CameraPosition", 
  camera.getLocation()
);

Vector2f frustumNearFar = new Vector2f();
frustumNearFar.x = camera.getFrustumNear();
frustumNearFar.y = camera.getFrustumFar();
in("FrustumNearFar",frustumNearFar);

Note: this pass renders an RGBA texture that contains the reflected scene in RGB and the strength of the reflection in A, so the output format must be set accordingly.

More settings are available, see the j3md

Once you have your reflection scene it is time to blur and merge it to your scene

Merging the reflection scene

Note: you can decide to skip this entire part and use a simple alpha blending

The material used for this pass is ssrmerger.j3md
This pass can be called multiple times and does horizontal and vertical gaussian blur, you only need to set the Size of your blur, the reflections rendered in the previous pass and the direction, in the last pass you will have to set also the scene to perform the merging.

So a two pass blur looks as follow

new SSRMerger().in("SSR",ssrout).in("Size",1.5).in("Horrizontal",true).out("scene",blur1);
new SSRMerger().in("SSR",blur1).in("Size",1.5).in("Vertical",true).out("scene",blur2);
new SSRMerger().in("SSR",blur2).in("Size",1.5).in("Horizontal",true).out("scene",blur3);
new SSRMerger().in("SSR",blur3).in("Scene",scenein).in("Size",1.5).in("Vertical",true).out("scene",sceneout);

Note in the last pass in(“Scene”,scenein) is the input color scene (from your forward rendering or previous filter) and out(“scene”,sceneout) will be the final scene with the reflections merged.

Some screenshots with different settings

License

BSD-3 https://github.com/riccardobl/SimpleSSRShader/blob/master/LICENSE


#2

Awesome! I did something similar (SSR), but it also takes a bit more work, especially for the underwater case.

What are these cool stats you use?


#3

Nice, if you don’t mind, could you explain how your raymarching works?

They are provided by the drivers (mesa) it’s called gallium hud