Shader—极坐标纹理采样

Shader—极坐标纹理采样

如下是我对极坐标纹理采样的一些理解。


极坐标纹理采样示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 直角坐标转极坐标
float2 RectToPolar(float2 uv, float2 centerUV) {
uv = uv - centerUV; // 移动坐标中心到中间(以前的原点在左下角)
float theta = atan2(uv.y, uv.x); // atan()值域[-π/2, π/2]一般不用; atan2()值域[-π, π](输入的是y坐标,x坐标)
float r = length(uv);
return float2(theta, r);
}

// 直角坐标转极坐标(极坐标的转换只能在顶点着色器中做,因为极坐标不是笛卡尔坐标系,像往常那样去插值会出错)
float2 thetaR = RectToPolar(i.uv, float2(0.5, 0.5));
// 极坐标转纹理采样UV
float2 polarUV = float2(
thetaR.x / 3.141593 * 0.5 + 0.5, // θ从[-π, π]映射到[0, 1]
thetaR.y + frac(_Time.x * 3.0) // r随时间流动
);
// 采样MainTex
half4 var_MainTex = tex2D(_MainTex, polarUV);

如上只给出了和极坐标纹理采样有关的shader代码,这并不是完整的shader解构。

以采样上面的纹理贴图为例,我来说明一下示例代码是如何运作的。

RectToPolar()函数不在此过多描述,其代码就是对直角坐标转换为极坐标的常规思路的实现。其得到的结果theta是纹理上一点uv和纹理原点centerUV确定的向量和水平方向的夹角,r是该向量的长度。算出角度等于theta的纹理坐标不止一个,这些坐标显然都位于一条射线上(例如下图左边蓝色的线),它们之间的差异就由到纹理原点centerUV的距离r来确定。

那么直接用thetar对纹理采样会得到什么呢?
上述代码13行将theta从 [-\(\pi\), \(\pi\)]映射到了[0, 1],相当于把一个圆展开成一条线段,原本从-\(\pi\)开始的每一个角度现在都映射到了u轴上,从0开始一直到1。

如上面左边的图所示,蓝色的线代表的是原始直角坐标系下相同角度theta的纹理,右边的图中蓝色的框对应着用它们的坐标计算出的thetar直接对纹理采样得到的结果。

如上图所示,蓝色的一圈同心圆对应的是右边纹理上的蓝色的线。

综上所述,如果对所有纹理坐标采样(也就是对所有的同心圆采样)的结果,应该得到的是形如下面圆锥形的俯视图的样子:

评论