坐标转换的一个比较成熟的想法 ///
我大概说一下怎么坐标转换 因为是用在我的3D渲染器里的 所以会结合一点
把一个三维点的坐标转化为另一个空间直角坐标系里的坐标
已知一个空间直角坐标系中一点A 我们想把它转化为一个经过任意旋转的空间直角坐标系中的坐标(p2 中由两两垂直的绿色和橙色向量为坐标轴的坐标系)
这里中目标坐标系的z轴正方向是确定的 即视线方向
这里坐标系y轴都表示高 x和z是平面 (你问我为什么? 8年mc你说为什么)

明确一下已知量然后开始:
A点在原坐标系中的坐标
新坐标系的z轴正方向在原坐标系中的向量坐标, 记该向量为n
新坐标系的另一根坐标轴与z轴的关系(当然 你知道它坐标也行 目的是确定新坐标系)
首先,我们先确定新坐标系。
在这个例子中,平面法向量就是目标坐标系的z轴正方向(p2中的绿色向量),坐标轴两两垂直,且因为最终看到的2D画面的的高就是高(自己根据结论理解下 不知道怎么说),所以目标坐标系中新x轴的必然在原坐标系的xz平面上,即新坐标系的x轴正方向在原坐标系中y=0。那么根据它与z轴正方向
确立了新坐标系的两条坐标轴,第三条坐标轴的位置就确定了,方向的话怎么发现怎么来就好了。
在3D渲染器里我是用2个角度表示视线向量的,α和β,分别表示视线向量n和原坐标系的xy面与xz面的夹角。 定义域的话 α∈[-180°, 180°], β∈[-90°, 90°]

为了计算方便,我们让n为单位向量,即 |n| = 1
设 vec(n) = (x,y,z) vec()表示是向量

那么我们就可以得到 |ON| = 1
=> |MN| = y = sinβ · |ON| = sinβ
|OM| = cosβ · |ON| = cosβ
=> |OC| = x = cosα · |OM| = cosα cosβ
|MC| = z = sinα · |OM| = sinα cosβ
=> vec(n) = (cosα cosβ, sinβ, sinα cosβ), |n| = 1
del x,y,z
记p1橙色向量和cyan向量分别为nh(horizontal)和nv(vertical)
设 vec(nh) = (x,0,z)
由nh⊥n 易得 x = cos(α-90°)cosβ, y = sin(α-90°)cosβ => vec(nh) = (cos(α-90°) cosβ, 0, sin(α-90°) cosβ) = (sinα cosβ, 0, -cosα cosβ)
del x,z
同理, vec(nv) = (cosα cos(β-90°), sin(β-90°), sinα cos(β-90°)) = (cosα sinβ, -cosβ, sinα sinβ)
但是这里有个小问题 |n|和|nv|都为1 但是|nh|因为y轴坐标被固定了 所以长度不总是1 那么我们需要变换一下 方法也很简单:
vec(nh0) = (sinα cosβ, 0, -cosα cosβ)
nh_len = sin²α·cos²β+cos²α·cos²β
vec(nh) = vec(nh0)/nh_len
表达式如下:
vec(nh) = (sinα cosβ / (sin²α·cos²β+cos²α·cos²β), 0 ,-cosα cosβ / (sin²α·cos²β+cos²α·cos²β))
值得注意的是它的定义域是不包含β=±90°的 所以可以在程序里加一个分类讨论 如果为|β|=90°时直接把原坐标系里的y和z换一下就是新坐标系了 记得考虑一下正负
综上我们就得到了得到新坐标轴的单位向量在原坐标系中的坐标:
vec(n) = (cosα cosβ, sinβ, sinα cosβ)
vec(nh) = (sinα cosβ / (sin²α·cos²β+cos²α·cos²β), 0 ,-cosα cosβ / (sin²α·cos²β+cos²α·cos²β)), |β| ≠ ±90°
vec(nv) = (cosα sinβ, -cosβ, sinα sinβ)
那么接下来的事情就很简单了 记得向量投影吗
A' = (vec(OA)·vec(nh), vec(OA)·vec(nv), vec(OA)·vec(n))
因为是单位向量,所以直接点乘就好了,不用再除模了,毕竟是1