Rectangular water filter

I’m very interested on making rivers, lakes and such so I’m just experimenting with shaders and filters. What I really learned is that this subjects are enourmous beasts xD. Well, however I could tweak the default waterfilter to support rectangles too (so it supports now circles, squares and rectangles). I could find that @Ben1 made it to work with any polygon but it’s not the easiest nor the better way for regular shapes.

Ok, here is the code (just as easy as adding another parameter to the shader xD):

First of all we modify the filter:

WaterFilter.java

We’ll use the radius as the height (x-axis) and we’ll add a new variable: the width (z-axis):

    @Override
    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
        ....
        if (center != null) {
            material.setVector3("Center", center);
            material.setFloat("Radius", radius * radius);
            material.setFloat("Width", width * width);
            material.setBoolean("SquareArea", shapeType==AreaShape.Square);
            material.setBoolean("RectangleArea", shapeType==AreaShape.Rectangle);
        }
        ....
    }
    /**
     * Set the width of the effect.
     * By default the water will extent to the entire scene.
     * By setting a center, a radius (x-axis in this case) and a width (z-axis) you can restrain it to a rectangular portion of the scene.
     * @param width the width (z-axis) of the effect
     */
    public void setWidth(float width) {
        this.width = width;
        if (material != null) {
            material.setFloat("Width", width * width);
        }
    }

    ....
    ....

    /**
     * Set the shape of the water area (Circular (default), Square or Rectangular).
     * if the shape is square or rectangular the radius is considered as an extent.
     * If rectangular the radius is considered the x-axis dimension and the width the z-axis dimension.
     * @param shapeType the shape type
     */
    public void setShapeType(AreaShape shapeType) {
        this.shapeType = shapeType;
        if (material != null) {
            material.setBoolean("SquareArea", shapeType==AreaShape.Square);
            material.setBoolean("RectangleArea", shapeType==AreaShape.Rectangle);
        }
    }

Now is the time of the material definition:

Water.j3md:

Add the material width parameter (for the height we are using the already set radius):

    MaterialParameters {
        ....
        Float Radius
        Float Width
        Vector3 Center
        ....
    }

Modify the defines for both techniques to add the “RECTANGLE_AREA”:

        Defines {
            ...
            SQUARE_AREA : SquareArea
            RECTANGLE_AREA : RectangleArea
            ...
        }

WaterUtil.glsl:

#ifdef ENABLE_AREA
    #ifdef RECTANGLE_AREA
        bool isOverExtent(vec3 position,vec3 center,float height,float width){
            vec2 dist = position.xz-center.xz;
            return dist.x*dist.x >height || dist.y*dist.y >width;
        }
    #else
        bool isOverExtent(vec3 position,vec3 center,float radius){
            vec2 dist = position.xz-center.xz;
            #ifdef SQUARE_AREA 
                return dist.x*dist.x >radius || dist.y*dist.y >radius;
            #else
                return dot(dist,dist)>radius;
            #endif
        }
    #endif
#endif

WaterX.frag:

First add the width uniform:

#ifdef ENABLE_AREA
uniform vec3 m_Center;
uniform float m_Radius;
#ifdef RECTANGLE_AREA
    uniform float m_Width;
#endif
#endif

Wherever there was:

#ifdef ENABLE_AREA
    if(isOverExtent(...)){
    .....
    }
#endif

just replace with:

#ifdef ENABLE_AREA
    #ifdef RECTANGLE_AREA
        if(isOverExtent(..., m_Width)){
        .....
        }
    #else
        if(isOverExtent(...)){
        .....
        }
    #endif
#endif

As you can see is just as efficient as the square and circular but helpful for rivers when no having strong “lateral limitations”.

The issue with the water filter is that reflections are only defined for a flat plane, because they are derived from the current camera. Also the filter works as a post-process which means the shape has to be definable in the fragment shader.

By using local reflection maps you can create a water filter that would work on any shape, e.g. a jME Geometry for example. @nehon is working on something similar for his PBR branch.

Do you have any idea of when the PBR would be ready (approximately)?, or at least the 3.1 beta/stable?. If I’m right 3.1 stable is including the PBR system so that two questions are tied.

Note that PBR env maps are used for lighting and reflection, and are static.
The reflection computed for the water filter is dynamic.

3.1 won’t have PBR… at least that was the plan at first… but the branch is quite stable now, you can use it