tilt-shift.how
krumza

Hi all. My question - in title. I have scrolable and zooming world, but need tilt-shift effect (ui layer hide from this)

I need to make tilt-shift effect but dont know how it make with very low cost.

I know 2 variants -

1. create iframe with this page from bottom and top, than blur it  - but it be good for promopage or single player game - not for multipayer game

2. on update function save canvas as image, then insert it as sprite on top layer and blur  - but it very expensive i think

I know that Gio work in webgl - may be exist a shader for me?)

 

All 7 Comments
Gio

Hi

You are right, neither of those options would be fast enough in practice.

We plan to add a blur effect to WADE in version 3.8, but that's some time away.  The plan is that in WADE 3.8 you'll be able to do wade.setLayerBlur(layerId, blurAmount)

If you need it sooner, it is possible but not very easy.

If you want to make it really fast, it's pretty complicated in fact. You'd need several passes. This involves setting the layer to use an offscreen render target, getting the render target and using it in a custom draw function for a sprite with a blur shader. So pretty complex.

But you can get something that looks ok just by using a post process shader for your layer. This is limited to a single pass. While much faster than the 2 options you mentioned, single-pass gaussian blur is still slow. But maybe you can get a nice effect even if it's not exactly gaussian blur.

For example you could try something like this

// change the value of res to change the look of the effect
const vec2 res = vec2(200., 200.);

vec2 uv = uvAlphaTime.xy;
vec2 uvDelta = vec2(1.) / res;
vec4 color = texture2D(uDiffuseSampler, uvAlphaTime.xy);
vec4 c = vec4(0.);
for (float i=-2.; i<=2.; i++)
{
    for (float j=-2.; j<=2.; j++)
    {
        float weight = 1. - pow((abs(i) + abs(j)) / 4., 5.);
        c += texture2D(uDiffuseSampler, uv + uvDelta * vec2(i, j)) * weight / 20.;
    }
}

float r = length(uv - 0.5);

gl_FragColor = mix(color, c, r * 2.);
gl_FragColor.w *= uvAlphaTime.z;

 

krumza

Gio thanks you are always very helpful.

I tried your Shader - it works, but the shaders are hard for me

I am quite dumb as alas

I certainly try by trial and error to understand the odds to get what you want, similarly can do the same vertical Shader - together they give almost Gaussian blur.

But the peculiarity of what else is - I have two layers - a layer for roads and buildings on each layer to hang up the post-Shader?

Can you figure out this Shader as the picture - so that the object S has received data from the fact that under it and distorted it

is it possible to apply to the object's Shader that would catch pixels from lower layers?

Gio

In WADE 3.6.x, sadly no this is not possible (or rather, it may be possible but very very slow), because each layer has got its own separate webgl context.

From version 3.7 yes, you can technically do that, because those layers will share the same context. We still won't have a nice API to do it, but using some raw webgl, you should be able to get that working. I can post some code here once we've released 3.7.

 

krumza

will wait )

krumza

Gio v 3.7 is avaliable ^)

Please show how can i make tilt-shift for different layers

Gio

This is now possible. However, I would NOT recommend it - the way to do it involves using undocumented functions and private variables. This is very bad practice.

In other words, do it this way only if you MUST do it now and cannot wait for wade 3.8. Because in wade 3.8 there will be a much nicer (and much easier) way of doing this.

Having said that, here's how you can read the pixels from other layers without slowing things down. For this example, let's say that you have a sprite on Layer 1 that wants to read the pixels of Layer 2 and Layer 3.

First of all, you need to set Layer 2 and Layer 3 to use off-screen render targets. You do this by calling wade.setLayerRenderMode after loading your scene. It is important to do it after loading the scene, because the scene loading code sets the layer render mode and may override what you're doing manually

wade.setLayerRenderMode(2, 'webgl', {offScreenTarget: true});
wade.setLayerRenderMode(3, 'webgl', {offScreenTarget: true});

Now if you create an object on layer 1, when it is added to the scene you can do this to bind the layer 2 and layer 3 textures to pixel shader uniforms called t2 and t3 (for example you can do this in the object's onAddToScene):

// first draw all layers at least once
wade.draw();

// then change the draw function of the sprite
var sprite = this.getSprite();
sprite.setDrawFunction(function(gl)
{
    // get layers directly - wade.getLayer is undocumented, so this is BAD
    var l2 = wade.getLayer(2);
    var l3 = wade.getLayer(3);
    
    // get the main render target textures - private variables == BAD
    var t2 = l2._mainRenderTarget.texture;
    var t3 = l3._mainRenderTarget.texture;
    
    // bind layer textures to the gl context and set them up
    gl.activeTexture(gl.TEXTURE1);
    gl.bindTexture(gl.TEXTURE_2D, t2);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.textures.t2 = t2;
    
    gl.activeTexture(gl.TEXTURE2);
    gl.bindTexture(gl.TEXTURE_2D, t3);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.textures.t3 = t3;
    
    gl.activeTexture(gl.TEXTURE0);

    // call the default draw function
    this.drawStatic_gl(gl);
});    

Then edit your object's sprite and add 2 shader uniforms called t2 and t3, both of type sampler2D.

Finally, edit the sprite pixel shader to use textures t2 and t3 to do whatever you like. For example:

vec2 uv = uvAlphaTime.xy;
uv.y = 1. - uv.y;  // flip Y axis
vec4 c2 = texture2D(t2, uv);
vec4 c3 = texture2D(t3, uv);
gl_FragColor = c2 + c3;

 

krumza

well, i try it and will wait new wade)

Post a reply
Add Attachment
Submit Reply
Login to Reply