镜面变换在游戏中并不少见,相关资料网上也俯拾即是,不过自己总是感觉略显生疏,在此简单一记,算作是加深印象吧~
问题很简单,假设存在点P(x, y, z)以及平面(n, D)(不太清楚为何平面如此表示的朋友可以参考这里),求解P相对与平面的镜像变换矩阵~
为了方便推导,画张图先:
简单解释一下图中内容:设点P(x, y, z)为平面正方向上的一点,点O是P(x, y, z)在平面上的投影,点A(xa, ya, za)是平面上任取的一点,而P’(x’, y’, z’)则是点P(x, y, z)相对与平面的镜像点,另外的,我们还假设由点A到点P的向量为a(x - xa, y - ya, z - za),由点O到点P的向量为b,平面法向量为n(xn, yn, zn),平面到原点的带符号距离为D
准备就绪,开始~
由图易知:
P’ = P - 2 * b
接着往下,如何求解b呢?其实很简单,只要求解a在平面法向量n上的投影即可:
b = a * n * n
OK,此处我们稍停,由于a * n是一个标量,我们先简单求解一下:
a * n = (x - xa, y - ya, z - za) * (xn, yn, zn) = (x - xa) * xn + (y - ya) * yn + (z - za) * zn
= x * xn + y * yn + z * zn - xa * xn - ya * yn - za * zn
因为点A(xa, ya, za)为处于平面上的点,自然满足(再次提醒,不清楚的朋友可以参考这里):
xa * xn + ya * yn + za * zn + D = 0 即
D = - xa * xn - ya * yn - za * zn
基于此,上面的a * n可以简化为:
a * n = x * xn + y * yn + z * zn + D
好了,我们计算出了 a * n,接着就可以用它来表示b了:
b = a * n * n = (x * xn + y * yn + z * zn + D) * n
考虑最之前P’点的表达式,我们将上式代入,得到:
P’ = P - 2 * b = P - 2 * (x * xn + y * yn + z * zn + D) * n
OK,到此,我们使用点P和平面n和D表示出了点P’,接着就可以推导变换矩阵了:
首先尝试计算点P’的x分量,我们有:
P’x = x - 2 * (x * xn + y * yn + z * zn + D) * xn
= (1 - 2 * xn * xn) * x - 2 * xn * yn * y - 2 * xn * zn * z - 2 * xn * D
根据这个表达式,并根据矩阵乘法规则,我们便可以得到变换矩阵的第一行元素:
m11 = 1 - 2 * xn * xn
m12 = -2 * xn * yn
m13 = -2 * xn * zn
m14 = -2 * xn * D
同样的方法,点P’的y,z分量分别为:
P’y = y - 2 * (x * xn + y * yn + z * zn + D) * yn
= - 2 * xn * yn * x + (1 - 2 * yn * yn) * y - 2 * yn * zn * z - 2 * yn * D
P’z = z - 2 * (x * xn + y * yn + z * zn + D) * zn
= - 2 * xn * zn * x - 2 * yn * zn * y + (1 - 2 * zn * zn) * z - 2 * zn * D
对应的,矩阵的第二行元素和第三行元素分别为:
m21 = -2 * xn * yn
m22 = 1 - 2 * yn * yn
m23 = -2 * yn * zn
m24 = -2 * yn * D
m31 = -2 * xn * zn
m32 = -2 * yn * zn
m33 = 1 - 2 * zn * zn
m34 = -2 * zn * D
至于矩阵的最后一行,在此我们暂不关心,简单设置:
m41 = 0
m42 = 0
m43 = 0
m44 = 1
至此,我们推导出了镜面变换的矩阵,为了演示简单搞了个Demo,有兴趣自取~
就这样了~