Loop offset texture in shader?

I don’t think this is a hard problem, I just think I’m not good enough with shaders to think through this properly (I’m sure its been done before). I have this texture on my tube, and I want it to rotate around the tube. Since the UV coords are between 0 and 1, I thought I could just mod the g_Time by a number and divide it (to keep it between 0 and 1), and add it the InTexCoord to get the uvCoord. Then, if the y ends up over 1, just subtract 1 to loop it. However, I get some funny banding, which I don’t quite understand. It indeed rotates around, just with the banding included. I’ve got the code and an image:

// vertex shader 
    uvCoord = inTexCoord + vec2(0.0,mod(g_Time, 10.0)/10.0);
    
    //uvCoord = inTexCoord + vec2(0.0,0.1);

    if (uvCoord.y > 1.0){
        uvCoord.y = uvCoord.y - 1.0;
    }

Here’s an idea, try removing the modulus (and the if sentence) and set the texture’s wrap mode to WrapMode.Repeat. That might be smoother.

You can also set some anisotropic filtering while you’re at it if you haven’t yet.

1 Like

Consider this picture:

It looks like what would happen on that last span… that texture has to interpolate between 0.8 and 0 and so will have most of the texture squashed. Really what you’d want is for it to go from 0.8 to 1.

So as MoffKalast suggests, let the texture mapping do the wrapping for you and let the texture coordinates climb up and up.

Even better, instead of g_Time use your own time based offset that you can wrap occasionally to avoid eventual floating point error.

Thanks guys, that helped a bunch. I didn’t realize that the repeat option dealt with increasing texCoords. @pspeed can you explain your last sentence a little more? I don’t understand when I would apply my own offset to avoid the error. Everything’s working like a charm, I just want to know a little more.

g_Time is just a floating point number sent to your shader like any other material parameter. But it increases forever. Floating point starts to lose resolution pretty quickly and so if you run your game long enough then you may start to see glitches in the textures.

Instead, you could pass your own float to you shader and wrap it back to 0 once it got to some amount that was compatible with your multipliers. (You don’t want your textures to jump suddenly after all.)

Edit: wrap it back to 0 before sending it to your shader. Not in the shader.

float myTime;
public void update( float tpf ) {
    myTime += tpf;
    if( myTime > 10 ) myTime -= 10;
    material.setFloat("myTime", myTime);
}

or something like that… use a value instead of 10 that will seamlessly work with whatever your in-shader multiplier is doing.

1 Like

Note to self: I’m doomed. I use this like everywere lol.

Wouldn’t that degrade performance by recompiling the shader every frame? I noticed that if you set an object (like a color) as a parameter in a shader then it auto updates if the object is changed. Does that trigger a recompile too, or none of these?

None of these. Only parameters linked to defines will cause the shader to recompile because the shader source itself changes.

All JME is going with its g_XXX parameters is calling the same code you do when you set a material parameter, basically. Just a small bypass to change from m_ to g_ in the shader.

1 Like

So if I understand you right, only clearing a param or setting a new one (that changes how the shader is set up) triggers a recompile? I mean even if you have define on say, colormap, the shader source shouldn’t change because it suddently got a new texture.

Correct.

1 Like

@pspeed @MoffKalast This has all been tremendously useful, thanks for the info!