对于球体,纹理坐标通常基于某种形式的经度和纬度,即球面坐标。【译注:球面坐标三要素θ,φ,r】我们要映射 θ 和φ 到纹理坐标 u 和 v,其中u, v∈ [0, 1]
要计算 θ 和φ, 对于以原点为中心的单位球面上的给定点,我们从相应笛卡尔坐标的方程开始:
我们根据以上三个式子反解出 θ 和φ。<cmath>提供了函数 atan2()。atan2有两个形参,两个参数之比为待反解的正切值。并且,atan2()是四象限反正切。我们可以传入-x/z,就可以得到φ。
【译注:四象限反正切vs反正切
反正切atan只有两个象限,f = anctan(a/b),若a/b为正,答案为0~π/2,若a/b为负,答案为-π/2~0 相当于只考虑单位圆的右半部分
而四象限反正切,见下图
相当于扩充了答案的范围,考虑整个单位圆。译注结束】
atan2() 返回 −π~π,但它们从 0 变为 π,然后翻转到 −π 并返回到零。虽然这在数学上是正确的,但我们希望u的范围是从 0 到 1,而不是从 0 至 1/2 然后从 −1/2 到 0。
很巧的是,atan2有如下关系:
第二个公式产生的值从 0 连续至2π .因此,我们可以计算φ 如
θ 的推导更直接:
所以对于一个球体,(u,v)计算由以下函数函数完成,该函数取以原点为中心的单位球面上的点,并计算 u 和 v
// Listing 22: [sphere.h] get_sphere_uv function
class sphere : public hittable {
...
private:
static void get_sphere_uv(const point3& p, double& u, double& v) {
// p: a given point on the sphere of radius one, centered at the origin.
// u: returned value [0,1] of angle around the Y axis from X=-1.
// v: returned value [0,1] of angle from Y=-1 to Y=+1.
// <1 0 0> yields <0.50 0.50> <-1 0 0> yields <0.00 0.50>
// <0 1 0> yields <0.50 1.00> < 0 -1 0> yields <0.50 0.00>
// <0 0 1> yields <0.25 0.50> < 0 0 -1> yields <0.75 0.50>
auto theta = acos(-p.y());
auto phi = atan2(-p.z(), p.x()) + pi;
u = phi / (2*pi);
v = theta / pi;
}
};