GLSL ES - 通过重复将纹理从矩形到极坐标映射

时间:2014-09-19 10:47:28

标签: libgdx glsl opengl-es-2.0 shader glsles

我需要将矩形纹理变形为具有极坐标的纹理。为了解释我的问题,我将说明一下:

我有图像: original image

我必须使用着色器将其变形为: result

然后我要把它映射到一架飞机上。 我怎样才能做到这一点?任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:4)

这不是特别难。您只需将纹理坐标转换为极坐标,并使用半径作为纹理的s方向,使用方位角指向t方向。

假设您想要以这种方式纹理四边形,并且还假设您使用标准texcoords,那么左下顶点将具有(0,0),右上一个(1,1)作为纹理坐标。 / p>

因此,在片段着色器中,您只需要将插值的texcoords(使用tc)转换为极坐标。如果中心位于(0.5,0.5),我们必须首先抵消这个。

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

现在您需要做的就是将范围映射回[0,1]纹理空间。此处的最大半径为0.5,因此您只需使用2*radius作为s坐标,角度将在[-pi,pi]中,因此您应将其映射到[0,1]对于t坐标。

<强> UPDATE1

到目前为止我遗漏了一些细节。从您的图像可以清楚地看出,您不希望将内圆映射到纹理。但这很容易被合并。我假设这里有两个半径:r_inner,它是内圆的半径,和r_outer,它是你想要映射外部的半径。让我勾勒出一个简单的片段着色器:

#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);
}

现在仍然缺少一个细节。上面生成的映射会生成在[0,1]范围之外的texcoords,用于图像中有黑色的任何位置。但纹理采样不会自动在这里给出黑色。最简单的解决方案是在纹理的左端和右端添加黑色像素,并将纹理的GL_TEXTURE_WRAP_S模式设置为GL_CLAMP_TO_EDGE。这样,你几乎可以免费获得黑色。另一种方法是在着色器中添加brach并检查tc_polar.s是否低于0或高于1.

答案 1 :(得分:0)

我找到了上面着色器的扩展版本:polarpixellate glsl。本文适合那些想要更灵活的着色器的人。

答案 2 :(得分:0)

对于那些想要具有相同功能的更灵活的着色器的人:

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);
}

来源:polarpixellate glsl