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.