Vertex Shader with dynamic material parameter

Hi,

I created custom vertex shader (copy of the jME Lighting.vert, plus my modification) that is supposed to make wave effect on a water surface. It works. However, the wave movement is driven by a WaveTime parameter that I pass to the shader via material parameters. In the update-loop of my app I increase the WaveTime value of the material that uses the shader. I have two issues/questins.

  1. I noticed that every time I increase the material parameter value using material.setFloat("WaveTime", timeAccumulated); the shader count displayed in the debug HUD increases:

I’m surprised to see that… is that normal? Why does it happen?

  1. I have performance issues: the “frames per second” count drops significantly when using the shader. (I only use one mesh with this material). Might be related to the issue above (multiplying shaders)…?
    It seems that sending the parameter value to GPU is the bottleneck: if I limit the material parameter update rate, then FPS gets higher. But I can’t adjust the update rate high enough for the effect too look nice without dropping FPS too badly.
    What is the best way to drive vertex shader with a parameter? Is there a better way than material.setFloat()? I was thinking about some tricks for the shader itself to make it able to accumulate time instead of taking it from CPU… perhaps storing it in a texture or something. I’m not sure. I’d be grateful for any advise on the topic.

Cheers!

That is not supposed to happen i think. Have you setup your parameter as define?

Jme already provides you with a Time variable.

Here are all uniforms provided by jme: UniformBinding (jMonkeyEngine3)

you still have to declare m_Time add the Time parameter to the j3md.

From the stats view it looks also like you are using 400 textures…

1 Like

Thank you for you answer :slight_smile:

Here is how I added perameters to my .j3md material definition file:

MaterialDef Phong Lighting {

    MaterialParameters {
(...)
        Boolean UseWave  //   <--- bunch of my parameters
        Float WaveTime
        Float WaveAmplitude
        Float WaveLength
        Int WaveSpeedEnum   // enum:   NONE = 0, SLOW = 1, NORMAL = 2, FAST = 3
    }

(...)
    Technique {
        LightMode SinglePass
(...)

        Defines {  
(...)
            USE_WAVE : UseWave  //   <--- bunch of my parameters
            WAVE_TIME : WaveTime
            WAVE_AMPLITUDE : WaveAmplitude
            WAVE_LENGTH : WaveLength
            WAVE_SPEED_ENUM : WaveSpeedEnum
        }
    }

    Technique {

        LightMode MultiPass
(...)

        Defines {  
(...)
            USE_WAVE : UseWave  //   <--- bunch of my parameters
            WAVE_TIME : WaveTime
            WAVE_AMPLITUDE : WaveAmplitude
            WAVE_LENGTH : WaveLength
            WAVE_SPEED_ENUM : WaveSpeedEnum
        }
    }
(...)
}

In the shader I only use USE_WAVE in #ifdef, and then I use the other parameters with m_ prefix, like m_WaveTime.

You mean declare m_Time in shader? And add Time somewhere in the .j3md?

That is probably OK, there is a lot of other objects on the scene as well.

EDIT: BTW. I now noticed that I have not giveny my material a custom name in the definition file, but this will probably not

you have to specify the variable in the Defines list only if you actually use then in an #ifdef
so in your case, remove all but USE_WAVE.

The reason behind is that the shader has to be recompiled if a variable used as define is changed. Variables only declared in the material parameters can be updated without recompilation

2 Likes

Yes, declare float m_Time in the shader and Time in the WorldParameters in the j3md.
It could be g_Time in the shader actually.

This helped! :slight_smile:
Shader count no longer rising. And no more FPS drop.
I’m including the fixed .j3md below - maybe it will help someone:

MaterialDef Phong Lighting {

    MaterialParameters {
(...)
        Boolean UseWave  //   <--- bunch of my parameters
        Float WaveTime
        Float WaveAmplitude
        Float WaveLength
        Int WaveSpeedEnum   // enum:   NONE = 0, SLOW = 1, NORMAL = 2, FAST = 3
    }

(...)
    Technique {
        LightMode SinglePass
(...)

        Defines {  
(...)
            USE_WAVE : UseWave  //   <--- only this here (will be used in #ifdef in shader)
        }
    }

    Technique {

        LightMode MultiPass
(...)

        Defines {  
(...)
            USE_WAVE : UseWave  //   <---only this here (will be used in #ifdef in shader)
        }
    }
(...)
}
2 Likes

Indeed, the g_Time variable starts to work in the shader, after adding Time to the list of WorldParameters in the Technique descriptions in .j3md :slight_smile:
Good to know.

Thank you @zzuegg ! :heart:

1 Like