球面坐标系与三角函数 Spherical Coordinates and Trigonometric Functions

计算机图形学数学基础译自 ScratchaPixel 网站,数学基础部分共八篇,本篇为第七篇,感兴趣的同学可以参考我的 GitBook 镜像。

三角函数 Trigonometric Functions

通常用2D坐标中的 单位圆(unit circle) 表示三角函数的性质。在单位圆上绘制一点P,由原点和P点的连线与x轴的夹角为。P点的x坐标对应于 的余弦(cosine)值,同样,其y坐标对应 的正弦(sine)值。需要注意的是C++中计算使用的是 弧度(radians),需要将 角度(degrees) 转换为弧度(radians):

图形学中一个比较重要的函数是 反正切(arctangent),即正切(tangent)的反函数。假如有一点P坐标为(0.707, 0.707),可以得到 的值为 。假如P的坐标为(-0.707, -0.707), 的值应为 。但是tan函数计算-0.707/-0.707的值为1,因此得到的角度仍为 。解决方法是采用C/C++中的atan2函数。下面是我们讨论的公式:

atan2函数计算的结果为正表示 是逆时针角度(y>0的象限),结果为负表示 是顺时针角度(y<0的象限),结果的范围在 之间。

在球面坐标表示向量 Representing Vectors with Spherical Coordinates

目前我们知道在 笛卡尔坐标系(Cartesian Coordinates) 表示向量(三个值,每个值表示一个轴)。同样,在 球面坐标系(Spherical Coordinates) 可以用两个值表示与笛卡尔坐标系相同的向量。如图所示:

向量与球面垂直的平面所成的角称为 。向量的投影与球面横切面所成的角称为 。图形学中 的范围为 , 的范围为 , 如下图:

球面坐标系的正式定义还包括一些专业术语,如r表示径向距离(radial distance)。

和 分别被称为 极角(polar angle)方位角(azimuth angle)。 如果不需要考虑向量的长度,球面坐标系是表示向量的另一种方式,这点在 着色(shading) 时非常重要。

z轴向上 Z is up

在数学和物理学中,坐标轴的表示通常采用左手定则,z轴向上,y轴向右,x轴指向自己。如图所示:

笛卡尔坐标系与球面坐标系的转换 Converting Cartesian to Spherical Coordinates

如图所示

单位圆内向量与z轴的夹角为: ,向量在z轴上的坐标为Vz。这里可以容易得到公式:

在C++中可以写为:

float theta = acos(Vz);

对于 角的计算。

根据图中所示,可以方便得到公式:

在C++中可以写为:

float phi = atan2(Vy, Vx);

球面坐标系与笛卡尔坐标系的转换 Spherical Coordinates to Cartesian Coordinates

根据球面坐标系的图,以下公式容易得到:

以下是C++的转换代码:

template<typename T>
Vec3 sphericalToCartesian(const T &theta, const T &phi) {
  return Vec3(cos(phi) * sin(theta), sin(phi) * sin(theta),cos(theta));
}

更多三角函数的技巧 More Tricks with Trigonometric Functions

  • 计算 值,虽然仅需要z轴坐标就可以计算,但是为了安全,使用clamp函数限制z的值在 [-1,1] 之间。
template<typename T>
inline T sphericalTheta(const Vec3 &v) {
  return acos(clamp(v[2], -1, 1));
}
  • 计算 值,C++的atan2函数的返回值在 之间,我们需要将其转换至 之间:
template<typename T>
inline T sphericalPhi(const Vec3 &v) {
  T p = atan2(v[1],v[0]);
  return (p < 0) ? p + 2 * M_PI : p;
}
  • 大部分场景我们并不需要计算出 或 的值。我们只需计算出 ,, , 的值。计算 的值比较直接:
template<typename T>
inline T cosTheta(const Vec3 &w) {
  return w[2];
}

根据 勾股定理(Pythagorean theorem),我们可以得到: 。假如 ,且 。则可以得到:

因此有如下代码:

template<typename T>
inline T sinTheta(const Vec3 &w) {
  return std::max(T(0), 1- cosTheta(w) * cosTheta(w));
}

template<typename T>
inline T sinTheta(const Vec3 &w) {
  return sqrt(sinTheta2(w));
}

对于 的计算:

templateT>
inline T cosPhi(const Vec3<T> &w) {
  T sintheta = sinTheta(w);
  if (sintheta == 0) return 1;
  return clamp<T>(w[0] / sintheta, -1, 1);
}
templateT>
inline T shiPhi(const Vec3<T> &w) {
  T sintheta = sinTheta(w);
  if (sintheta) return 0;
  return clamp<T>(w[1] / sintheta, -1, 1);
}

你可能感兴趣的:(Computer,Graphics,Math)