Barrel / Distortion effect?

  • Hi, I am trying to find an effect that will remove (or add) barrel distortion along the Y axis.

    Does anyone know of an effect or know how to create/edit an effect to do this?

    Thanks

    Andy

  • There was such effect for C2, but download links are dead:

    construct.net/en/forum/extending-construct-2/effects-31/effect-barreldistort-98810

    newt, you commented in that post, do you still have the files? Should not be difficult to convert for C3.

  • Hi thanks, its sort of what I want but not.

    Ideally I want the shader to act on the sprite its self and not have to have another sprite act as a lens.

    Also i want it to only effect the X axis and not shift Y axis.

    I have attached the shape which I am trying to get back to as near rectangle as possible.

    I think actually what i am looking for is more a pincushion effect?

    I have found this but cannot get it to not not effect Y shift.

    https://thebookofshaders.com/edit.php?log=180726191628

    Hope this helps.

    Thanks

  • I tried that C2 Barrel effect, and it basically works like Bulge - distorts on both X and Y axes.

  • I have found this but cannot get it to not not effect Y shift.

    https://thebookofshaders.com/edit.php?log=180726191628

    Hope this helps.

    Thanks

    You mean like this?

    	// Author: Florian Morel
    // Title: glsl-barrel-pincushion example
    
    #ifdef GL_ES
    precision mediump float;
    #endif
    
    uniform vec2 u_resolution;
    uniform vec2 u_mouse;
    uniform float u_time;
    
    float rectangle(vec2 st, vec2 size, vec2 aastep) {
     size = vec2(0.5) - size * 0.5;
     vec2 uv = vec2(smoothstep(size.x - aastep.x, size.x, st.x), smoothstep(size.y - aastep.y, size.y, st.y));
     uv *= vec2(smoothstep(size.x - aastep.x, size.x, 1.0 - st.x), smoothstep(size.y - aastep.y, size.y, 1.0 - st.y));
    
     return uv.x * uv.y;
    }
    
    float lines(vec2 pos, vec2 axis, float gridSize, vec2 aastep) {
     float lineWidth = 1.0;
     vec2 gridPos = pos / gridSize;
     vec2 gridFrac = abs(fract(gridPos) - 0.5);
     vec2 g = clamp((gridFrac - aastep * (lineWidth - 1.0)) / aastep, 0.0, 1.0);
     float c = g.x * g.y;
     return 1.0 - c;
    }
    
    vec2 barrelPincushion(vec2 uv, float k) {
     vec2 st = uv - 0.5;
     float theta = atan(st.x, st.y);
     float radius = sqrt(dot(st, st));
     radius *= 1.0 + k * pow(radius, 2.0);
    
     // return 0.5 + vec2(sin(theta), cos(theta)) * radius;
     
     return vec2(
     0.5 + sin(theta) * radius,
     uv.y
     
     );
    }
    
    void main() {
     vec2 st = gl_FragCoord.xy/u_resolution.xy;
     st.x *= u_resolution.x/u_resolution.y;
    
     vec2 aastep = 2.0 / u_resolution;
     float k = sin(u_time);
     st = barrelPincushion(st, k);
     
     float shape = rectangle(st, vec2(0.5), aastep);
     shape -= rectangle(st, vec2(0.49), aastep);
    
     vec3 color = vec3(1.0);
     float mask = rectangle(st, vec2(0.5), aastep);
    	color += -mask * lines(st, vec2(0.0), 0.05, aastep * 10.0);
     
     gl_FragColor = vec4(color, 1.0 - shape);
    }
    

    The magic is in the barrelPincushion function, the rest is basically for generating and drawing the rectangle. Previously it was taking an input co-ord, transforming it and returning the result. I modified the output to return the new co-ordinate for the X position, and the old for the Y.

  • > I have found this but cannot get it to not not effect Y shift.

    >

    > thebookofshaders.com/edit.php

    >

    > Hope this helps.

    >

    > Thanks

    You mean like this?

    > 	// Author: Florian Morel
    // Title: glsl-barrel-pincushion example
    
    #ifdef GL_ES
    precision mediump float;
    #endif
    
    uniform vec2 u_resolution;
    uniform vec2 u_mouse;
    uniform float u_time;
    
    float rectangle(vec2 st, vec2 size, vec2 aastep) {
    size = vec2(0.5) - size * 0.5;
    vec2 uv = vec2(smoothstep(size.x - aastep.x, size.x, st.x), smoothstep(size.y - aastep.y, size.y, st.y));
    uv *= vec2(smoothstep(size.x - aastep.x, size.x, 1.0 - st.x), smoothstep(size.y - aastep.y, size.y, 1.0 - st.y));
    
    return uv.x * uv.y;
    }
    
    float lines(vec2 pos, vec2 axis, float gridSize, vec2 aastep) {
    float lineWidth = 1.0;
    vec2 gridPos = pos / gridSize;
    vec2 gridFrac = abs(fract(gridPos) - 0.5);
    vec2 g = clamp((gridFrac - aastep * (lineWidth - 1.0)) / aastep, 0.0, 1.0);
    float c = g.x * g.y;
    return 1.0 - c;
    }
    
    vec2 barrelPincushion(vec2 uv, float k) {
    vec2 st = uv - 0.5;
    float theta = atan(st.x, st.y);
    float radius = sqrt(dot(st, st));
    radius *= 1.0 + k * pow(radius, 2.0);
    
    // return 0.5 + vec2(sin(theta), cos(theta)) * radius;
    
    return vec2(
    0.5 + sin(theta) * radius,
    uv.y
    
    );
    }
    
    void main() {
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    st.x *= u_resolution.x/u_resolution.y;
    
    vec2 aastep = 2.0 / u_resolution;
    float k = sin(u_time);
    st = barrelPincushion(st, k);
    
    float shape = rectangle(st, vec2(0.5), aastep);
    shape -= rectangle(st, vec2(0.49), aastep);
    
    vec3 color = vec3(1.0);
    float mask = rectangle(st, vec2(0.5), aastep);
    	color += -mask * lines(st, vec2(0.0), 0.05, aastep * 10.0);
    
    gl_FragColor = vec4(color, 1.0 - shape);
    }
    

    The magic is in the barrelPincushion function, the rest is basically for generating and drawing the rectangle. Previously it was taking an input co-ord, transforming it and returning the result. I modified the output to return the new co-ordinate for the X position, and the old for the Y.

    Hi Nepeo, that is spot on, I will have to try and get this into a C3 effect now. Unless you can trim this down for me to make it easier to implement?

    Edit: Im not having much luck due to my lack of knoweldge with C3 and Shaders, anyone like to try and put the above magic function into something that will work with c3?

    Thanks

  • I haven't written any effects for Construct in the past so I'm probably not the one to ask. I just happen to know some GLSL so I thought I'd chime in.

    I pared the example down a bit further for you, I can't really do anymore on it without reading up on how to make effects for Construct!

    // Author: Florian Morel
    // Adapted by: Iain Shorter
    // Title: glsl-barrel-pincushion example
    
    #ifdef GL_ES
    precision mediump float;
    #endif
    
    uniform vec2 u_resolution;
    
    vec2 barrelPincushion(vec2 uv, float k) {
     vec2 st = uv - 0.5;
     float theta = atan(st.x, st.y);
     float radius = sqrt(dot(st, st));
     radius *= 1.0 + k * pow(radius, 2.0);
    
     return 0.5 + vec2(sin(theta), cos(theta)) * radius;
    }
    
    void main() {
     // constant value for level of distortion ( negative for "pincushion" )
     const float k = 1.;
     // the position of the input texture (0...1)
     vec2 uv = gl_FragCoord.xy/u_resolution.xy;
     // convert input position to distorted co-ordinate
     vec2 st = barrelPincushion(uv, k);
     // normally you would sample your texture here, but I'm just converting the position to a colour
     vec3 colour = vec3(uv, 0.0);
     
     // filter out any pixels that are outside the distortion ( set them to blue)
     if (st.x < 0. || st.x > 1. || st.y < 0. || st.y > 1.) {
     colour.r = colour.g = 0.0;
     colour.b = 1.;
     }
     
     // output colour
     gl_FragColor = vec4(colour, 1.0);
    }
  • Thanks Nepeo,

    I am in the same boat as you, its very frustrating as I just cannot get it to work in c3.

    Hoping someone comes along who can get it to work.

    I have managed to put it into shadertoy making it much simpler and using an image.

    however i still cant get it to work in C3??

    shadertoy.com/view/3d3SW4

    Andy

  • I am still battling this. The only issue I see is that i cannot workout how to bring through from construct the "resolution" or the sprite size in pixels.

    Based on the following simple method which works on shadertoy (https://www.shadertoy.com/view/3d3SW4)

    the following line:

    vec2 uv = gl_FragCoord.xy/iResolution.xy;

    using a uniform input called iResolution which according to shadertoy is the following:

    uniform vec3 iResolution; //viewport resolution (in pixels)

    How do i get that in C3?

    Thanks

    Andy

  • Maybe use the delta between the srcStart and srcEnd to calculate the position? Manual: Configuring Effects

    Something like:

    	vec2 srcDelta = srcEnd - srcStart;
    	vec2 position = (vTex - srcStart) / srcDelta;
    

    I'm not sure that's quite right, but I think they are all in the same texture space.

  • Thanks Nepeo,

    I have actually already tried that and although the "distorting" works there is some stange things happening when you scroll on layout or move the sprite.

    And the depending on the "amount" of distorting you set seems to effect the overall size/zoom of the sprite.

    //effect.fx
    precision mediump float;
    
    varying mediump vec2 vTex;
    uniform lowp sampler2D samplerFront;
    
    uniform mediump float scale;
    
    uniform mediump vec2 srcStart;
    uniform mediump vec2 srcEnd;
    
    void main(void)
    {
     mediump vec2 n = (vTex - srcStart) / (srcEnd - srcStart);
     	
     vec2 st = n - 0.5;
     float theta = atan(st.x, st.y);
     float rad = sqrt(dot(st, st));
     rad *= 1.0 + scale * pow(rad, 2.0);
    
     gl_FragColor = texture2D(samplerFront, vec2( 0.5 + sin(theta) * rad, n.y));
     
    }
    

    Andy

  • I'm not sure what would be happening with the scroll/ moving the sprite. One thing that occurs to me is your not clipping the space outside of the distortion, I'm not sure what sort of result you would be getting without the clip but it could be quite odd. I included the clipping test in my second example.

    The distortion mapping function reduces the size of the image when the value is positive, and increases it if the value is negative. I would expect this sort of behaviour, with a curved image you either have to lose part of the image or have blank space.

  • You are normalizing the u,v coords (n), you usually have to denormalize again before you sample the texture again (map it to the region of spritesheet your image resides in.)

    (e.g. sampler2D(sampleFront, mix(srcOriginStart, srcOriginEnd, nUpdated)) )

    If nUpdated.x or nUpdated.y is < 0 or > 1, you need decide how to deal with that, e.g. clamp or set color to a base color (transparent, white, etc.)

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Example of denorm and clamping.

    /////////////////////////////////////////////////////////
    // Barrel
    
    //The current foreground texture co-ordinate
    varying mediump vec2 vTex;
    //The foreground texture sampler, to be sampled at vTex
    uniform lowp sampler2D samplerFront;
    //The current foreground rectangle being rendered
    uniform mediump vec2 srcStart;
    uniform mediump vec2 srcEnd;
    //The current foreground source rectangle being rendered
    uniform mediump vec2 srcOriginStart;
    uniform mediump vec2 srcOriginEnd;
    //The current foreground source rectangle being rendered, in layout 
    uniform mediump vec2 layoutStart;
    uniform mediump vec2 layoutEnd;
    //The background texture sampler used for background - blending effects
    uniform lowp sampler2D samplerBack;
    //The current background rectangle being rendered to, in texture co-ordinates, for background-blending effects
    uniform mediump vec2 destStart;
    uniform mediump vec2 destEnd;
    //The time in seconds since the runtime started. This can be used for animated effects
    uniform mediump float seconds;
    //The size of a texel in the foreground texture in texture co-ordinates
    uniform mediump vec2 pixelSize;
    //The current layer scale as a factor (i.e. 1 is unscaled)
    uniform mediump float layerScale;
    //The current layer angle in radians.
    uniform mediump float layerAngle;
    
    //effect.fx
    precision mediump float;
    
    uniform mediump float scale;
    
    void main(void)
    {
     mediump vec2 n = (vTex - srcOriginStart) / (srcOriginEnd - srcOriginStart);
    
     vec2 st = n - 0.5;
     float theta = atan(st.x, st.y);
     float rad = sqrt(dot(st, st));
     rad *= 1.0 + scale * pow(rad, 2.0);
     
     n = clamp(vec2( 0.5 + sin(theta) * rad, n.y), vec2(0.), vec2(1.));
    
     gl_FragColor = texture2D(samplerFront, mix(srcOriginStart,srcOriginEnd,n));
    
    }
    
Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)