如果你还不是很理解矩阵的含义那么请转到 https://blog.csdn.net/qq_39426265/article/details/101373494
问题起源
在Unity自带的函数中并没有判断一个点在自身的左边还是右边的方法。但是有的时候我们在项目中又不得不去判断,Unity自带的有一个方法 Vector3.SignedAngle 这个方法也可以判断出目标在自身的哪一侧,因为用过这个方法的同学应该都知道,当物体在自身左侧或者右侧时,他所返回的角度值是带有符号的,所以也可以判断这个角度值是否大于0,来达到我们的目的,但是缺点就是,当我们只想判断出这个目标点位于自身的哪一侧时,再使用跟这个方法,就会造成性能的浪费,因为它用多余的计算,计算出了一个角度值,再返回给我们,我不清楚他的内部实现,因为Unity是不开源的,所以我只能判定,这个方法是一个比较耗时,浪费计算量的方法,当然我只限于在当前要解决的问题的基础上来说的。所以我才写了相应的算法,来解决这个问题,如果你想理解我的方法,那么你就要有一些3D数学的基础,否则你会很难理解我为什么这么做。
原理
下面让我们来分析下2D世界中位于世界西边或者东边的物体有什么特点(判断不需要竖直维度的值)
比如这就是我们Unity中的世界俯视视角:
我这里忽略Y轴,因为只是判断物体在自己的哪一侧,XZ平面就够了。
我们以Z轴为正方向,也就是分割线,规定Z轴以左为东侧(X正半轴),反之为西侧(X负半轴)。
下面我们在世界中随机创建一个物体:
如果把世界作为一个人物,Z轴为人物的朝向,那么很显然,我们所创建的物体就位于人物的右侧,也就是世界的东侧,此时,它位于X的正半轴上,反之就在X的负半轴上。
到这里就很明了了,就拿我们刚才的举例来说,如果世界就是一个人物,而Z轴就是人物的正方向,那么,如果某一物体在人物的右侧,则该物体处于该人物的相对坐标系下的X分量就为正值,否则就为负值。
解决方法
我们在上面已经了解了判断的原理是什么,接下来我们的工作就简单了,只需要把要判断物体的坐标系转化到自身的坐标系下就可以了,那么怎么做呢?
如果自身的朝向正好和世界坐标的朝向一致,也就是自身相对于世界坐标没有发生任何旋转,那么我们就直接可以判断目标物体的X分类的正负。但这毕竟是一种特殊情况,大多数情况下自身的坐标是不可能不发生旋转的。所以我们就要把这个个方法扩展到任意情况都成立!
我们假设,自身(任何你要控制的游戏物体)绕Y轴旋转了theta度:
self_Z代表当前自身的朝向,也就是Z轴方向;
然后在选取一个要判断的目标点:
比如说这个点是A。
接下来我们要做的就是把A点转化到世界坐标下去,就可以了。
那么我们怎么转换呢?
再次观察上图,self_Z旋转了Theta度才到达现在的方向,也就是说如果我们把self_Z和A点都反过来旋转theta度,那么我们就把这个任意的随机的情况转化为了一个特殊的情况,也就是自身相对于世界没有做任何的旋转,这个时候只需要判断A点的X的分量就可以了。
所以我们可以得到下图:
我用虚线来表示原本的状态,实线是经过上述操作得到的状态。
A`
是旋转后的A,也是我们需要计算的向量;
此时我们已经把任意情况转化为特殊情况,接下来我们要做的就是用数学计算,计算出A`
我们如果想要得到A`就必须得到一个旋转矩阵,这个旋转矩阵就是self_Z实际中的矩阵,也就是转化为特殊情况时的矩阵,构建该矩阵的方法我不必多说,读者可以看我在开头的链接里找到方法。
假设我们得到了矩阵B,我们就可以列得方程:
A` * B = A
当然,我们要用已知求未知,又因为矩阵不满足乘法的交换律,所以我们不能将B消掉,所以我们同时给两边乘上B^-1(表示-1在B的右上角,表示B的逆矩阵)
得
A` * B * B^-1 = A * B^-1
又因为B一定是一个单位正交阵,所以B*B^-1 == 1,T(B) == B^-1
所以我们可以得到
A * T(B) = A`
这样,我们就求出了特殊情况下的A`,然后只需要判断X分量即可判断出目标物到底在自身的哪一侧了。
下面我贴出实现代码(当然,你可以不使用unity自带的Matrix,用一个二维数组去替代它,但是你需要要对“*”运算符进行重载):
int GetTargetIsRightOrLeft(Transform self, Vector3 targetPos)
{
Matrix4x4 matrix =
new Matrix4x4(target.right, target.up, target.forward, new Vector4(0, 0, 0, 1));//构建一个旋转矩阵
targetPos = Vector3.Normalize(targetPos - self.position);
return matrix.inversion * targetPos ? -1 : 1
}
这里要知道矩阵乘法的原则:当乘号左边的矩阵的行数等于右边的矩阵的列数时两个矩阵才能相乘,由于在Unity中Vector3可以隐式转化为Vector3,所以这个乘法才成立。