读一读

利用点乘可以很好的实现这一点,已知 a·b = |a||b|cosβ,我们可以点乘主角到NPC的向量和主角面向的forward方向。然后根据cosβ的正负值来判断在前还是在后。因为cosβ数学函数在(-90°,90°)刚好是大于0的,刚好在前时,两向量的夹角也是这个范围。

blob.png

Transform targetNpc;
void Start () {
    targetNpc = GameObject.Find("Npc").transform;
    //计算在前还是在后  cos [-90,90] 为 [0,1]
    float res = Vector3.Dot(transform.forward, targetNpc.position - transform.position);
    if (res > 0)
    {
        Debug.Log("在前面");
    }
    else if (res < 0)
    {
        Debug.Log("在后面");
    }
    else
    {
        Debug.Log("在正左或右");
    }
}


如果说主角的视野范围有限,在一个角度之内,那么也很简单。例如视野范围为60°,那么临界值就是cos(60/2),比这个值大的就是可以看见的,因为cos角度越靠近0(越靠近forward)就越大。


利用叉乘可以很好的实现这个目的,利用叉乘出来的方向的正负就可以很好的判断在左还是在右。"左手法则",利用左手的四指延NPC方向(叉乘的第一个参数)弯曲指向forward取弯曲得比较少的一边,拇指指向的方向就是叉乘方向。

void Start () {
    Vector3 v = Vector3.Cross(target.position - transform.position,transform.forward);
    Debug.Log(v.y);//正在左,负在右
}


已知Unity是左手坐标系,所以模型物体在xz平面上的叉乘出来相关指标就是y轴的正负了,当目标在右方,由目标方向旋转到forward方向,怎么都是逆时针旋转的路程短吧,所以左手抓出个逆时针,拇指向下对准了y轴负方向吧!所以正就在左咯,反之就右咯。


照我们的理解,两个轴的旋转就可以包含所有的旋转角度了。万向锁,其实就是一种旋转的特殊情况,再y轴旋转为90或-90度的时候,旋转x和z轴的效果是一样的,从而少了一种旋转轴,没有两个轴就不能表达出所有的旋转角度了。

using UnityEngine;
public class TestWXS : MonoBehaviour {

    float x = 0;
    float z = 0;
	
	void Update () {
        Resetpos();
        //x++;
        z++;
        transform.Rotate(0, 0, z);
        transform.Rotate(0, 90, 0);
        transform.Rotate(x, 0, 0);
    }

    private void Resetpos()
    {
        transform.position = Vector3.zero;
        transform.rotation = Quaternion.identity;
    }
}


代码中,无论是x++还是z++都是一样的固定在xy平面上旋转,不同只是方向不一样。缺失了对z轴的旋转。

在变换的矩阵中,y轴旋转变换固定为90或-90,那么矩阵就是一个固定的值,将对x,y,z的旋转矩阵进行左乘,得到:

blob.png

可以发现,这里缺失了对z顶点坐标旋转的变换影响。


利用叉乘判断旋转方向从而比较快的旋转到目标朝向。在一个平面上的两个向量进行叉乘可以得到平面的法向量,但同时这个法向量是有方向的。在左手坐标系中利用“左手定则”,左手四指由a(a表示为叉乘时的第一个参数)朝向b并且运运动最少(不超过180°),拇指指向的方向就是叉乘计算出来的法线方向。反利用这一点,通过判断计算出法线的方向,我们就可以知道顺时针旋转还是逆时针旋转路程比较短。(右手坐标系同理,使用右手定则,得到的结果是一样的)

如果说,平面是xy面,那么法线的z的正负就是法线的方向了。当z<0时,证明左手拇指向屏幕外面指,那么四指朝向为顺时针。当z>0时,相反的,逆时针旋转。

例子,赛车的方向盘就可以使用这种方式进行旋转,往转向小的地方去,因为你的操作是按住方向盘,然后转圈,转圈的时候不停的提取历史方向和当前方向(方向盘中心点到新触摸点),计算叉乘,根据法线方向,然后进行相应的旋转。

image.png

右手坐标系相应的使用右手,变换的其实就是z轴和结果方向调换了,只是显示上的改变,数值上z还是小于0


在一个圆内,规定一个起点的半径,圆周上有很多个点,假如这个圆所在的平面是一个xz平面。

QQ图片20180122111420.png

则圆的每个点都可以用cos和sin对的形式表示出来,β的范围为一个圆周2π


pythagorean-theorem.png

计算一个点距离原点的距离,同样的在三维中也是一样的

distance = sqrt(x2 + y2 + z2)


128.png


188.png


屏幕空间是一个二维空间,因此,我们必须把顶点从裁剪空间投影到屏幕空间,来生成对应的2D坐标,最终形成像素型的图像,我们能看到的。

因为在上一步的剪切矩阵处理过后,能看见的x,y,z都在w范围内,这样就可以进行齐次除法(透视除法),将他们的坐标范围全部变到一个单位化的范围中,这就是归一化的设备坐标(NDC)。


裁剪空间也叫齐次裁剪空间,从观察空间到裁剪空间的矩阵叫做剪裁矩阵,也称为投影矩阵。剪裁空间的目标是能够方便地对渲染图元进行裁剪:完全位于这块空间内部的图元将会保留,完全位于这块空间外部的图元将会被剔除,而于这块空间边界相交的图元就会被裁剪。这块空间由一个视椎体决定的,由六个平面包围而成,称为裁剪平面。

一般来说这一步是不剔除先关东西的,只是为了这个而做准备,经过投影矩阵,使x,y,z不被剔除的部分在w的值范围内,也方便后面的屏幕坐标的投影。


观察空间也被称为摄像机空间。在观察空间中,摄像机位于原点,同样,其坐标轴的选择可以是任意的,在Unity中,+x指向右方,+y指向上方,而+z指向的却是摄像机的后方。与模型空间和世界坐标不同用的是右手坐标系。

可以将摄像机在世界坐标系的位置信息,变换到世界原点中,再将z轴取反从而得到世界空间到观察空间的变换矩阵。例如,一个相机先旋转了30度,再平移(0,0,-10),那么我们就反向的先平移(0,0,10),再旋转-30度,将这些数据转化为矩阵,再乘以一个-z的缩放矩阵,这就可以得到变换矩阵了。