【发布时间】:2016-10-21 17:53:33
【问题描述】:
在我的 WebGL 着色器中,我想根据范围为 [0,2*PI) 的函数 (atan) 的输出来映射纹理的 U 值。但是 U 的范围(正如 texture2D 所期望的)是 [0,1]。所以我试图将一个开放区间映射到一个封闭区间。
这说明了问题: 水平红色渐变是 U 轴,当我的 atan 从 0 变为 2*PI 时,从 Red=1 变为 Red=0。但是 atan 将 2*PI 视为零,因此在渐变变黑后右侧有一条红色带。 (顶部和底部也有红色带,但这是与 V 值有关的类似问题,出于本问题的目的,我将忽略它)。
您可以看到最右边的顶点 (U=1) 是如何再次对应于 atan=0 而不是 2*PI 的红色。
关于如何完成此任务的任何建议?我不能强迫 atan 返回 2*PI。我不想平铺纹理。我可以以某种方式将 U 值映射到开区间吗?
我一直认为一定有一个简单的解决方案,但我已经尝试了所有我能想到的解决方案。
这是我的顶点着色器:
void main()
{
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
// convert from uv to polar coords
vec2 tempuv = uv;
theta = (1.0-tempuv[1]) * PI;
phi = PI * 2.0 * tempuv[0];
// convert polar to cartesian. Theta is polar, phi is azimuth.
x = sin(theta)*cos(phi);
y = sin(theta)*sin(phi);
z = cos(theta);
// and convert back again to demonstrate problem.
// problem: the phi above is [0,2*PI]. this phi is [0,2*PI)
phi = atan2(y, x);
if (phi < 0.0) {
phi = phi + PI*2.0;
}
if (phi > (2.0 * PI)) { // allow 2PI since we gen uv over [0,1]
phi = phi - 2.0 * PI;
}
theta = acos(z);
// now get uv in new chart.
float newv = 1.0 - theta/PI;
float newu = phi/(2.0 * PI);
vec2 newuv = vec2(newu, newv);
vUv = newuv;
}
这是我的片段着色器:
void main() {
vec2 uv = vUv;
gl_FragColor = vec4(1.0- uv[0],0.,0.,1.);
}
【问题讨论】:
-
除以 2 * PI,并编写一个调用 atan 的函数,当 atan(x) >
2PI - precision时,返回 1。 -
这行不通,因为下一个小于 1.0 的 'u' 对应于下一个顶点,我们不想弄乱那个颜色。
-
将
phi = PI * 2.0 * tempuv[0]替换为phi = PI * 2.0 * tempuv[0] *0.9999999;,这样您将无法访问2*PI。