一、Unity的4种坐标系
1, World Space(世界坐标):
我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在场景中的。transform.position可以获得该位置坐标。
2, Screen Space(屏幕坐标):
以像素来定义的,以屏幕的左下角为(0,0)点,右上角为(Screen.width,Screen.height),Z的位置是以相机的世界单位来衡量的。
注:鼠标位置坐标属于屏幕坐标,Input.mousePosition可以获得该位置坐标,手指触摸屏幕也为屏幕坐标,Input.GetTouch(0).position可以获得单个手指触摸屏幕坐标。
3.ViewPort Space(视口坐标):
视口坐标是标准的和相对于相机的。相机的左下角为(0,0)点,右上角为(1,1)点,Z的位置是以相机的世界单位来衡量的。
4, 绘制GUI界面的坐标系:
这个坐标系与屏幕坐标系相似,不同的是该坐标系以屏幕的左上角为(0,0)点,右下角为(Screen.width,Screen.height)。
【四种坐标系的转换】
1、世界坐标→屏幕坐标:camera.WorldToScreenPoint(transform.position);这样可以将世界坐标转换为屏幕坐标。其中camera为场景中的camera对象。
2、屏幕坐标→视口坐标:camera.ScreenToViewportPoint(Input.GetTouch(0).position);这样可以将屏幕坐标转换为视口坐标。其中camera为场景中的camera对象。
3、视口坐标→屏幕坐标:camera.ViewportToScreenPoint();
4、视口坐标→世界坐标:camera.ViewportToWorldPoint();
二、Unity坐标系间的相互转换
全局坐标和局部坐标
点的坐标转换
Transform.TransformPoint(Vector3 position); 将一个坐标点从相对transform的局部坐标系转换为全局坐标系
Transform.InverseTransformPoint(Vector3 position); 将坐标点从全局坐标系转换到相对transform的局部坐标系
方向的坐标转换
Transform.TransformDirection(Vector3 direction); 将一个方向从局部坐标系转换到全局坐标系
Transform.InverseTransformDirection(Vector3 direction); 将一个方向从全局坐标系转换到局部坐标系
Transform.TransformVector(Vector3 vector); 将一个向量从局部坐标系转换到全局坐标系
Transform.InverseTransformVector(Vector3 vector); 将一个向量从全局坐标系转换到局部坐标系
屏幕坐标系和全局坐标系
Camera.ScreenToWorldPoint(Vector3 position); 将屏幕坐标系转换为全局坐标系
Camera.WorldToScreenPoint(Vector3 position); 将全局坐标转换为屏幕坐标
Input.mousePosition; 获取鼠标在屏幕中的坐标
例子: 屏幕坐标转为世界坐标
Vector3 mousePos = Input.mousePosition;
Vector3 SToW = Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x,mousePos.y,1));
视口坐标(屏幕坐标的单位化,最大值是1)和屏幕坐标的转换
Camera.ScreenToViewportPoint(Vector3 position); 将屏幕坐标转为视口坐标
Camera.ViewPortToScreenPoint(Vector3 position); 将视口坐标转为屏幕坐标
世界坐标与视口坐标 转换
Camera.WorldToViewportPoint(Vector3 position); 将全局坐标转换为视口坐标
Camera.ViewportWorldPoint(Vector3 position); 将视口坐标转换为全局坐标
三、Unity判断相对于自身的方位和角度
[csharp] view plain copy
//求角度 及前后左右方位
public void checkTargetDirForMe(Transform target)
{
//xuqiTest: target.position = new Vector3(3, 0, 5);
Vector3 dir = target.position - transform.position; //位置差,方向
//方式1 点乘
//点积的计算方式为: a·b =| a |·| b | cos < a,b > 其中 | a | 和 | b | 表示向量的模 。
float dot = Vector3.Dot(transform.forward, dir.normalized);//点乘判断前后:dot >0在前,<0在后
float dot1 = Vector3.Dot(transform.right, dir.normalized);//点乘判断左右: dot1>0在右,<0在左
float angle = Mathf.Acos(Vector3.Dot(transform.forward.normalized, dir.normalized)) * Mathf.Rad2Deg;//通过点乘求出夹角
//方式2 叉乘
//叉乘满足右手准则 公式:模长|c|=|a||b|sin
Vector3 cross = Vector3.Cross(transform.forward, dir.normalized);//叉乘判断左右:cross.y>0在左,<0在右
Vector3 cross1 = Vector3.Cross(transform.right, dir.normalized); //叉乘判断前后:cross.y>0在前,<0在后
angle = Mathf.Asin(Vector3.Distance(Vector3.zero, Vector3.Cross(transform.forward.normalized, dir.normalized))) * Mathf.Rad2Deg;
}
// 判断物体是否在眼前 和 背后 fangxiang>0在眼前 , <0在背后
Vector3 dir = target.transform.position - fpsPlayer.transform.position;
fangxiang = Vector3.Dot(fpsPlayer.transform.forward, dir.normalized);
1.判断目标在自己的前后方位可以使用下面的方法:
Vector3.Dot(transform.forward, target.position)
返回值为正时,目标在自己的前方,反之在自己的后方
2.判断目标在机子的左右方位可以使用下面的方法:
Vector3.Cross(transform.forward, target.position).y
返回值为正时,目标在自己的右方,反之在自己的左方
3.在这里顺便解说下关于空间向量的点积和叉积:
A.点积
点积的计算方式为: a·b=|a|·|b|cos 其中|a|和|b|表示向量的模,
表示两个向量的夹角。另外在 点积 中,和 夹角是不分顺序的。
所以通过点积,我们其实是可以计算两个向量的夹角的。
另外通过点积的计算我们可以简单粗略的判断当前物体是否朝向另外一个物体: 只需要计算当前物体的transform.forward向量与 otherObj.transform.position 的点积即可, 大于0则在前方,否则在后方。
B.叉积
叉积的定义: c =a x b 其中a,b,c均为向量。即两个向量的叉积得到的还是向量! 性质1: c⊥a,c⊥b,即向量c垂直与向量a,b所在的平面 。 性质2: 模长|c|=|a||b|sin 性质3: 满足右手法则 。从这点我们有axb ≠ bxa,而axb = – bxa。所以我们可以使用叉积的正负值来判断向量a,b的相对位置,即向量b是处于向量a的顺时针方向还是逆时针方向
4.配合使用
在Unity中,一般的rpg基本可以满足了,但是在一些特定定制功能中,要求比较苛刻,配合Unity相机视野范围使用。(比如要求,要在视野范围内,而且目标物体不是npc,不能转身,方向是固定的,要判断是否在物体正面还是背面的需求)。
案例:
void OnBecameVisible()
{
//Debug.LogError(this.name + "摄像机视野内");
isVisib = true;
}
void OnBecameInvisible()
{
//Debug.LogError(this.name + "在摄像机视野外");
isVisib = false;
}
private void Update()
{
if (isVisib)
{
Vector3 cross = this.transform.InverseTransformPoint(GFGlobal.Instance.FPSPlayerObj.transform.position);
if (cross.x > 0)
{
if (_mediaPlayer)
{
dist = Vector3.Distance(GFGlobal.Instance.FPSPlayerObj.transform.position, this.transform.position);
if(dist <= maxPauseDis)
{
mPlayerPlay();
}else
{
mPlayerPause();
}
if (dist <= minDis)
{
volume = maxvol;
}
else if (dist > maxDis)
{
volume = 0f;
}
else
{
volume = (dist - b) / p;
}
_mediaPlayer.Control.SetVolume(volume);
}
}
else
{
mPlayerPause();
}
}
// 判断物体是否在眼前 和 背后 fangxiang>0在眼前 , <0在背后
//Vector3 dir = this.transform.position - fpsPlayer.transform.position;
//fangxiang = Vector3.Dot(fpsPlayer.transform.forward, dir.normalized);
}