【发布时间】:2014-09-19 10:47:27
【问题描述】:
我需要将矩形纹理扭曲为具有极坐标的纹理。为了阐明我的问题,我将对其进行说明:
我有图片:
我必须使用着色器将其变形为如下所示:
然后我要把它映射到飞机上。 我怎样才能做到这一点?任何帮助将不胜感激!
【问题讨论】:
标签: libgdx glsl opengl-es-2.0 shader glsles
我需要将矩形纹理扭曲为具有极坐标的纹理。为了阐明我的问题,我将对其进行说明:
我有图片:
我必须使用着色器将其变形为如下所示:
然后我要把它映射到飞机上。 我怎样才能做到这一点?任何帮助将不胜感激!
【问题讨论】:
标签: libgdx glsl opengl-es-2.0 shader glsles
这并不是特别难。您只需要将纹理坐标转换为极坐标,并使用纹理的s 方向的半径和t 方向的方位角。
假设您想以这种方式对四边形进行纹理化,并假设您为此使用标准 texcoords,因此左下角的顶点将具有 (0,0),右上角的顶点 (1,1) 作为纹理坐标。
所以在片段着色器中,您只需将插值的 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] 中,因此您应该将 @987654327 映射到 [0,1] @坐标。
更新1
到目前为止,我遗漏了一些细节。从您的图像中可以清楚地看出,您不希望将内圈映射到纹理。但这很容易被合并。我在这里只假设两个半径: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_BORDER 模式(默认边框颜色为(0,0,0,0),因此您可能不需要指定它,或者您可以将GL_TEXTURE_BORDER_COLOR 显式设置为(0,0,0,1),如果您工作使用 alpha 混合并且不想要任何透明度)。这样,您将免费获得黑色。其他选项是使用GL_CLAMP_TO_EDGE 并在纹理的左端和右端添加一个黑色像素列。另一种方法是在着色器中添加一个分支并检查 tc_polar.s 是否低于 0 或高于 1,但我不建议在这个用例中这样做。
【讨论】:
t。
GL_TEXTURE_WRAP_T模式设置为GL_REPEAT并将t纹理坐标(现在在[0,1]中)乘以180。
对于那些想要更灵活的着色器的人来说:
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);
}
【讨论】: