Waterfall Demo (UV Density)

Posted on

Hi all, this week we will create a waterfall. Also I’ll show you such basic technique as using UV density to make different speed of texture animation. And as usual we will use one texture and nothing extra.

So, I had a look at waterfall references and realized that I need a texture at first 🙂 Here is a pretty good photo of falling water I got from website about Alaska:

waterfall reference
waterfall reference

And after 10 min it turns to a texture:

falling water texture
falling water texture

I can explain how to make texture from that image, but it seems too easy for me – just perspective transformation and stamp tool in Photoshop. So, ask me if you think that this information will be useful

Now we need the model, surface of our waterfall and rock behind it.

waterfall surface
waterfall surface

Okey, our preparations are done.

Let’s make some magic stuff.

magic

First of all, our simple animation shader:


use namespace flare;
use namespace flare.transforms;
use namespace flare.filters;

sampler2D texture;
param TIME time;

technique main
{
    output sourceFactor = "sourceAlpha";
    output destFactor = "oneMinusSourceAlpha";
    output depthWrite = false;

    output vertex = transform();
    
    float4 tex = sampler2D( texture, iUV0+float2(0,-time.z) );
    
    output fragment = tex;
}

Nothing special. But texture looks good. So, as I did it earlier, water needs multiple layers to look more realistic. So, retry those steps again:


sampler2D texture;
param TIME time;

param float2 firstLayerScale = float2(5,9);
param float2 secondLayerScale = float2(3,7);

param float speedFactor = 1;

technique main
{
    output sourceFactor = "sourceAlpha";
    output destFactor = "oneMinusSourceAlpha";
    output depthWrite = false;

    output vertex = transform();
    
    
    float4 tex1 = sampler2D( texture, iUV0*firstLayerScale+0.3+float2(0,-time.x/2)*speedFactor ) ;
    float4 tex2 = sampler2D( texture, iUV0*secondLayerScale+float2(0,-time.x)*speedFactor ) ;
    
    float4 tex = overlay(tex1,tex2);
    
    output fragment = tex;
}

Nothing new, but pay your attention to first sampler with 0.3 offset. It is important, because without it textures will match periodically. Offset resolves the problem.

The second effect I want is to make this movement less linear. We can use the same texture, but tile it less, to make big noise and calculate alpha with it:

    float4 tex1 = sampler2D( texture, iUV0*firstLayerScale+0.3+float2(0,-time.x/2)*speedFactor ) ;
    float4 tex2 = sampler2D( texture, iUV0*secondLayerScale+float2(0,-time.x)*speedFactor ) ;
    float4 tex3 = sampler2D( texture, iUV0*thirdLayerScale+0.1+float2(0,-time.z/20)*speedFactor ) ;
    
    float4 tex = overlay(tex1,tex2);
    
    float a = pow(overlay(tex,tex3).r,2)+0.2;
    
    output fragment = float4(tex.rgb,a);

So, it seems to be completed.. but no.

Let’s look at our model. We have two extreme falls on it:

two waterfalls
two waterfalls

I want to make movement of water on these falls faster than on other parts of mountain. How to make it?

The secret is in UV density. Look at basic UV of simple plane:

simple UV of plane
simple UV of plane

The interpolation between vertexes is linear. It means that UV of left bottom vertex is (0;0), next one will be with +0.25 value: 0,0.25,0.5,0.75,1.0. If we increase first UV step to 0.5 without vertex movement, the bigger texture will be drawn at the same distance, so movement will be slower:

So, we need to return to 3ds max to complete our UV

completed UV

That’s it. Final code:


use namespace flare;
use namespace flare.transforms;
use namespace flare.filters;
use namespace flare.blendMode;

param float4 waterColor <ui = "color"> = float4( 1, 1, 1, 1 );
param float4 backColor <ui = "color"> = float4( 41/255, 39/255, 21/255, 1 );
param float speedFactor = 1;

param float2 firstLayerScale = float2(5,9);
param float2 secondLayerScale = float2(3,7);
param float2 thirdLayerScale = float2(0.04,0.025);

sampler2D texture;
param TIME time;

technique main
{
    output sourceFactor = "sourceAlpha";
    output destFactor = "oneMinusSourceAlpha";
    output depthWrite = false;
        
    output vertex = transform();
    float4 tex1 = sampler2D( texture, iUV0*firstLayerScale+0.3+float2(0,-time.x/2)*speedFactor ) ;
    float4 tex2 = sampler2D( texture, iUV0*secondLayerScale+float2(0,-time.x)*speedFactor ) ;
    float4 tex3 = sampler2D( texture, iUV0*thirdLayerScale+0.1+float2(0,-time.z/20)*speedFactor ) ;

    float4 tex = overlay(tex1,tex2);
    
    float a = pow(overlay(tex,tex3).r,2)+0.2;
    
    tex *=waterColor;
    
    tex = screen(tex,backColor);
    
    output fragment = float4(tex.rgb,a);
}

4 Replies to “Waterfall Demo (UV Density)”

  1. greaet tutorial! Keep coming with Flare3D tuts 🙂 and thank you for your efforts! Can you make some tutorial for basics AGAL2 also ?

    1. thank you for your support, feedback is very important for me 🙂 can you specify if you want tutorial about agal in general or typical features of agal2?

Leave a Reply