GLSL snow shader and noise

Hello,



just finished a simple shader to simulate the snow, and I'd like to share and also to get your opinion:



Vertex:

attribute vec3 tangent;
attribute vec3 binormal;

varying   vec3 g_lightVec;

void main()
{
   gl_Position = ftransform();
   gl_TexCoord[0] = gl_MultiTexCoord0;
   
   mat3 TBN_Matrix = gl_NormalMatrix * mat3(tangent, binormal, gl_Normal);
   vec4 mv_Vertex = gl_ModelViewMatrix * gl_Vertex   ;

   vec4 lightEye = gl_ModelViewMatrix *  gl_LightSource[0].position;
   vec3 lightVec =0.02* (lightEye.xyz - mv_Vertex.xyz);            
   g_lightVec = lightVec * TBN_Matrix;
}



Frag:

uniform sampler2D snowNoise;

varying   vec3 g_lightVec;

void main()
{
   float LightAttenuation = clamp(1.0 - dot(g_lightVec, g_lightVec), 0.0, 1.0);
   vec3 lightVec = normalize(g_lightVec);

   vec4 color_base = vec4(0.94,0.94,1.0,1.0)*0.7; //this gives the intensity of the snow color modify it as you feel (did it slightly bue)
   vec3 bump = texture2D(snowNoise, gl_TexCoord[0].xy).rgb * 2.0 - 1.0;
   bump = normalize(bump);   

   float diffuse = clamp(dot(lightVec, bump), 0.0, 1.0);   
   
   gl_FragColor = vec4(color_base.rgb * gl_LightSource[0].diffuse.rgb
               * (diffuse +0.7 * color_base.a) 
               * LightAttenuation,1.0);
   
}



also, please note that the most important maybe is the noise you apply, here are two examples:
here's a noise of my own making (the gimp, used Filter->Distort-> Ripple and Wind and also any kind of noise, but mot too much so that the grain remains pretty fine - you'd lose the aspect of snow)


Also, another texture extracted from shader designer that gives you several samples of grain:


I find the best one in the sample is the one bottom left, what do you think?

this shader is inspired from the bump_mapping from shader designer (http://www.typhoonlabs.com/),

Advises on the way to generate snow noise are welcome,
Hope this helps,
Adrien

Maybe I'm just slow, but I can't get anything to show with it; wanna post a quick test showing how to use it?

Sure,



Will do tonight after work (so far just tested with shader designer)

basically I just quickly and dirtily modified TestGLSLShaderAttributes from jME, anyway, in the following code, you should just have to modify the three paths (texture, .frag and .vert)



once you run it, you'll observe what I've been trying to fix for now 20 minutes: there's no effect of direction from the light. I really don't understand why since it's perfectly working in shaderdesigner, but it's as if the light was taken as an "ambient" light, I'll work on it a little more, any help welcome (and after I'll work on an ice shader),



Adrien


/*
 * Copyright (c) 2003-2007 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 java.nio.FloatBuffer;
import java.util.logging.Logger;

import com.jme.app.SimpleGame;
import com.jme.image.Texture;
import com.jme.input.NodeHandler;
import com.jme.light.PointLight;
import com.jme.light.SimpleLightNode;
import com.jme.math.FastMath;
import com.jme.scene.state.*;
import com.jme.math.Vector3f;
import com.jme.math.Vector2f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.CullState;
import com.jme.scene.state.GLSLShaderObjectsState;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jme.util.geom.BufferUtils;

/**
 * Tests GLSL shader attributes functionality
 *
 * @author Rikard Herlitz (MrCoder)
 */
public class TestGLSLShaderAttributes extends SimpleGame {
    private ColorQuad quad0, quad1, quad2, quad3;

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

    protected void simpleInitGame() {
        display.setTitle("Test GLSL attributes");

        cam.setLocation(new Vector3f(0, 0, 2));
        cam.update();
        input = new NodeHandler(rootNode, 10, 2);
       
        lightState.detachAll();
        PointLight light = new PointLight();
        light.setSpecular(ColorRGBA.red);
      light.setDiffuse(ColorRGBA.white);
      //light.setAmbient(ColorRGBA.white);
      light.setEnabled(true);
      light.setLocation(new Vector3f(0.0f,10.0f,10.0f));
      LightState lState = display.getRenderer().createLightState();
      lState.detachAll();
      lState.attach(light);
      lState.setEnabled(true);
      
      CullState cs = display.getRenderer().createCullState();
      cs.setCullMode(CullState.CS_FRONT);
      cs.setEnabled(true);

      rootNode.setRenderState(cs);
      
      rootNode.setRenderState(lState);
      rootNode.updateRenderState();
      
        quad0 = new ColorQuad(ColorRGBA.red.clone(), 1.0f);
        rootNode.attachChild(quad0);
        quad0.getLocalTranslation().x -= 0.5f;
        quad0.getLocalTranslation().y -= 0.5f;
        rootNode.updateRenderState();

    }

    private class ColorQuad extends Quad {
        /** Shader attribute buffer for vertex colors */
        private FloatBuffer vertexColors;
        /** Shader attribute buffer for amount of offset to normal */
        private FloatBuffer vertexOffset;

        public ColorQuad(ColorRGBA color, float size) {
            super("glslQuad", 1f, 1f);

            GLSLShaderObjectsState so = display.getRenderer()
                    .createGLSLShaderObjectsState();

            // Check is GLSL is supported on current hardware.
            if (!so.isSupported()) {
                quit();
            }

            //setDefaultColor(color);

            so.load(TestGLSLShaderAttributes.class
                            .getClassLoader()
                            .getResource(
                                  "shaders/Snow.vert"),
                    TestGLSLShaderAttributes.class
                            .getClassLoader()
                            .getResource(
                                  "shaders/Snow.frag"));
            so.setUniform("snowNoise", 0);
                     
            Texture tex = TextureManager.loadTexture(
                  TestGLSLShaderAttributes.class.getClassLoader().getResource(
                        "textures/map/snowtest.jpg"),
                        Texture.MM_LINEAR_LINEAR,
                        Texture.FM_LINEAR);
            tex.setWrap(Texture.WM_WRAP_S_WRAP_T);

       
           
            TextureState brick = display.getRenderer().createTextureState();
            brick.setTexture(tex, 0);
                     
            brick.setEnabled(true);
            setRenderState(brick);
           
            vertexOffset = BufferUtils.createFloatBuffer(4);
         
            so.setEnabled(true);

            setRenderState(so);
        }

        public void update(float speed) {
            vertexOffset.rewind();
            vertexOffset.put(
                            FastMath.sin(timer.getTimeInSeconds() * speed) * 0.5f + 0.5f)
                        .put(
                            FastMath.sin(timer.getTimeInSeconds() * speed
                                    + 1.0f) * 0.5f + 0.5f).put(
                            FastMath.sin(timer.getTimeInSeconds() * speed
                                    + 2.0f) * 0.5f + 0.5f).put(
                            FastMath.sin(timer.getTimeInSeconds() * speed
                                    + 3.0f) * 0.5f + 0.5f);
        }

    }
}

vec4 lightEye = gl_ModelViewMatrix *  gl_LightSource[0].position;


Multiplying by ModelViewMatrix is not needed, in GLSL, light position is already in modelview space.
Replace with: vec4 lightEye = gl_LightSource[0].position;

vec3 lightVec =0.02* (lightEye.xyz - mv_Vertex.xyz);   


You're using that for attenuation right? I would suggest you use a different method.. It seems like sort of a hack right now.

Pretty interesting …



so with the first correction of Momoko_Fan, the vertex shader:


attribute vec3 tangent;
attribute vec3 binormal;

varying   vec3 g_lightVec;

void main()
{
   gl_Position = ftransform();
   gl_TexCoord[0] = gl_MultiTexCoord0;
   
   mat3 TBN_Matrix = gl_NormalMatrix * mat3(tangent, binormal, gl_Normal);
   vec4 mv_Vertex = gl_ModelViewMatrix * gl_Vertex   ;

   vec4 lightEye = gl_LightSource[0].position;
   vec3 lightVec = 0.02*(lightEye.xyz - mv_Vertex.xyz);            
   g_lightVec = lightVec * TBN_Matrix;
}



works perfectly fine (as I wanted) on the demo,

however, I tested the older shader (without the correction) on a bigger piece of code, using the same shader (included in a single render state) on several quads (same exact render state on plenty of quads) and I obtain this behavior:



now that I have made the correction, the shader that works on the demo (when you move the texture, it takes the direction of the light into consideration) doesn't work at all on the my big piece of code ...

I draw two conclusions from this:

1 - the transition from my shader editor to jME is not as smooth as I expected (it's not sufficient that it looks good on shaderdesigner to make it work correctly on jME)

2 - Except if someone proposes another solution, I'll try to create one shader for each quad on my big code to have an independent behavior (apparently it must just copy the same exact rendering to all the quads), but I guess I'll lose a lot of fps... (so in that case, my snow shader is useless and I should as well use a simple snow texture to have it run faster)

(3 ? I still have to figure out about the second remark from Momoko_Fan, since this line is directly taken from another predefined shader from shaderdesigner, and also, why the new version of the shader doesn't work on my other jME class)

anyway, thanks Mamako
Adrien

Edit: In order to complete this post, my issue was due to the fact that I locked my meshes:
http://www.jmonkeyengine.com/jmeforum/index.php?topic=9384.msg72624#msg72624
when unlocked, the shader has a good behavior