GLSL ES - mapping texture from rectangular to polar coordinates with repetition

I need to convert a rectangle texture to a polar coordinates texture. To spread the light to my problem, I'm going to illustrate this:

I have an image: original image

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

then I'm going to match it to an airplane. How can i do this? Any help would be appreciated!


source to share

3 answers

It's not particularly difficult. You just need to convert the texture coordinates to polar coordinates and use the radius to guide the texture s

and the azimuth angle to the direction t


Assuming you want to texture the square this way, and also assuming you are using standard texcoords for this, so the bottom left vertex will have (0,0), the top right (1,1) as texture coordinates.

So, in the fragment shader, you just need to convert the interpolated texcoords (using tc

this) to polar coordinates. The SInce center will be at (0.5, 0.5), we must first compensate for this.

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


Now you only need to map the range back to [0,1] texture space. The maximum radius here will be 0.5, so you can just use it 2*radius

as a coordinate s

and the angle will be in [-pi, pi], so you have to map that value to [0.1] for the t



There are a few details that I have forgotten so far. It's clear from your image that you don't want the inner circle to map onto the texture. But this can easily be reversed. I'm just assuming two radii here: r_inner

which is the radius of the inner circle, and r_outer, which is the radius that you want to map the outer part to. Let me sketch out a simple fragment shader for this:

#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. The generated display generates texcords that are out of range [0,1] for any position where you have balck in your image. But sampling the texture won't automatically give black here. The simplest solution is that you add a black pixel to both the left and right ends of the texture and set the GL_TEXTURE_WRAP_S

texture mode to GL_CLAMP_TO_EDGE

. This way you get black for almost free. Another way would be to add a shoulder to the shader and check what tc_polar.s

is below 0 or above 1.



I found an extended version of the shader above: polarpixellate glsl . This article is for those who want a more flexible shader.



For those looking for 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 .



All Articles