GLSL ES - Mapping texture from rectangular to polar coordinates with repeating
Asked Answered
C

2

8

I need to warp a rectangular texture to texture with polar coordinates. To spread the light on my problem, I am going to illustrate it:

I have the image: original image

and I have to deform it using shader to something like this: result

then I'm going to map it to a plane. How can I do this? Any help will be appreciated!

Cantara answered 19/9, 2014 at 10:47 Comment(0)
A
8

That is not particularly hard. You just need to convert your texture coordinates to polar coordinates, and use the radius for the texture's s direction, and the azimuth angle to the t direction.

Assuming you want to texture a quad that way, and also assuming you use standard texcoords for this, so the lower left vertex will have (0,0), the upper right one (1,1) as texture coords.

So in the fragment shader, you just need to convert the interpolated texcoords (using tc for this) to polar coordinates. SInce the center will be at (0.5, 0.5), we have to offset this first.

 vec2 x=tc - vec2(0.5,0.5);
 float radius=length(x);
 float angle=atan(x.y, x.x);

Now all you need to do is to map the range back to the [0,1] texture space. The maximum radius here will be 0.5, so you simply can use 2*radius as the s coordinate, and angle will be in [-pi,pi], so you should map that to [0,1] for the t coordinate.

UPDATE1

There are a few details I left out so far. From your image it is clear that you do not want the inner circle to be mapped to the texture. But this can easily be incorparated. I just assume two radii here: r_inner, which is the radius of the inner circle, and r_outer, which is the radius onto which you want to map the outer part. Let me sketch out a simple fragment shader for that:

#version ...
precision ...

varying vec2 tc; // texcoords from vertex shader
uniform sampler2D tex;

#define PI 3.14159265358979323844

void main ()
{
    const float r_inner=0.25; 
    const float t_outer=0.5; 

    vec2 x = v_tex - vec2(0.5);
    float radius = length(x);
    float angle = atan(x.y, x.x);

    vec2 tc_polar; // the new polar texcoords
    // map radius so that for r=r_inner -> 0 and r=r_outer -> 1
    tc_polar.s = ( radius - r_inner) / (r_outer - r_inner);

    // map angle from [-PI,PI] to [0,1]
    tc_polar.t = angle * 0.5 / PI + 0.5;

    // texture mapping
    gl_FragColor = texture2D(tex, tc_polar);
}

Now there is still one detail missing. The mapping generated above generates texcoords which are outside of the [0,1] range for any position where you have black in your image. But the texture sampling will not automatically give black here. The easiest solution would be to just use the GL_CLAMP_TO_BORDER mode for GL_TEXTURE_WRAP_S (the default border color will be (0,0,0,0) so you might not need to specify it or you can set GL_TEXTURE_BORDER_COLOR explicitly to (0,0,0,1) if you work with alpha blending and don't want any transparency that way). That way, you will get the black color for free. Other options would be using GL_CLAMP_TO_EDGE and adding a black pixel column both the left and right end of the texture. Another way would be to add a brach to the shader and check for tc_polar.s being below 0 or above 1, but I wouldn't recommend that for this use case.

Apocryphal answered 20/9, 2014 at 13:24 Comment(5)
Do you know how to change this shader to make result from segments? So, I need to repeat given texture, not to stretch.Cantara
@Nolesh: can you elaborate on that? What exactly do you want to repeat?Apocryphal
I need to add count of segments from which circle will be consist. For instance, I assign 180 to this count. So, whole texture stretches on each 2 degrees. This process repeats 180 times whilst entire circle is not filled. By this action, I expect increase resolution along t.Cantara
@Nolesh: So if I got this right, you just want to repeat the texture along the t dimension 180 times for the full circle. So all you have to do is setting the GL_TEXTURE_WRAP_T mode to GL_REPEAT and multiply the t texture coord (which is now in [0,1]) by 180.Apocryphal
That's exactly what I wanted! Thank you very much!Cantara
C
1

For those who want a more flexible shader that does the same:

uniform float Angle; // range 2pi / 100000.0 to 1.0 (rounded down), exponential
uniform float AngleMin; // range -3.2 to 3.2
uniform float AngleWidth; // range 0.0 to 6.4
uniform float Radius; // range -10000.0 to 1.0
uniform float RadiusMin; // range 0.0 to 2.0
uniform float RadiusWidth; // range 0.0 to 2.0
uniform vec2 Center; // range: -1.0 to 3.0

uniform sampler2D Texture;

void main()
{
    // Normalised texture coords
    vec2 texCoord = gl_TexCoord[0].xy;
    // Shift origin to texture centre (with offset)
    vec2 normCoord;
    normCoord.x = 2.0 * texCoord.x – Center.x;
    normCoord.y = 2.0 * texCoord.y – Center.y;
    // Convert Cartesian to Polar coords
    float r = length(normCoord);
    float theta = atan(normCoord.y, normCoord.x);

    // The actual effect
    r = (r < RadiusMin) ? r : (r > RadiusMin + RadiusWidth) ? r : ceil(r / Radius) * Radius;
    theta = (theta < AngleMin) ? theta : (theta > AngleMin + AngleWidth) ? theta : floor(theta / Angle) * Angle;

    // Convert Polar back to Cartesian coords
    normCoord.x = r * cos(theta);
    normCoord.y = r * sin(theta);
    // Shift origin back to bottom-left (taking offset into account)
    texCoord.x = normCoord.x / 2.0 + (Center.x / 2.0);
    texCoord.y = normCoord.y / 2.0 + (Center.y / 2.0);

    // Output
    gl_FragColor = texture2D(Texture, texCoord);
}

Source: polarpixellate glsl.

Shadertoy example

Cantara answered 24/7, 2019 at 5:21 Comment(6)
could you please show the full code here on stackoverflow using the snippet? or on codepen?Yount
@Zibri, you could see the full code on the polarpixellate websiteCantara
I tried and nothing so far works.. can you make an example here on stackoverflow than I can check with "run script" ? or edit this codepen because I can't make it work.codepen.io/zibri-the-sans/pen/wvxgpMX (change the code with the one you posted)Yount
@Zibri, Once upon a time I worked with this shader and already forgot a lot. I would recommend you to play around with the shader in shadertoy.com first, rather than implementing it directly in WebGL. Take a look at https://www.shadertoy.com/view/Dt23DWCantara
I know shadertoy, but I was wondering how to use that shader on an image, in a canvas and without using three.js or any other library.Yount
@Zibri, I've used this shader in the LibGDX library, but I'm sure you can use it anywhere you want with a few changes depending on the environment.Cantara

© 2022 - 2024 — McMap. All rights reserved.