资源描述
Unity3D类解析之Vector3
By张鑫
Vector3这词最早是谁发明的无从考证了,但是Unity3D里出现了这个名词的时候,我才意识到这个不是D3D和openGL才有的变量名,D3D里叫做 D3DXVECTOR3继承自_D3DVECTOR结构体,其中_D3DVECTOR结构体只有3个单精度数X,Y,Z。用于表示向量。
Vector3向量既可以用来表示位置,也可以用来表示方向。在数学与物理中,既有大小又有方向的量叫做向量(亦称矢量),与标量相对。
在立体三维坐标系中,分别取与x轴、y轴,z轴方向相同的3个单位向量i,j, k作为一组基底。若a为该坐标系内的任意向量,以坐标原点O为起点作向量OP=a。由空间基本定理知,有且只有一组实数(x,y, z),使得 a=向量OP=xi+yj+zk,因此把实数对(x,y, k)叫做向量a的坐标,记作a=(x,y, z)。这就是向量a的坐标表示。其中(x,y, k),也就是点P的坐标。向量OP称为点P的位置向量。
Unity3D中Vector3类定义(只写有用的):
属性:
x,y,z
表示一个空间向量。
this
用于访问x,y,z三个数据使用数组的方式访问,比如:
position = new Vector3(1.5f, 3.0f, 6.7f);
position[0]; // 获得1.5
position[1]; // 获取3.0
position[2]; // 获取6.7
normalized
返回从坐标轴原点(0,0,0)到点P(x,y,z)的方向,向量的长度为 1。 也就是说返回的向量的点P(x,y,z)到原点(0,0,0)的距离为1。 这个很多时候被用来指示一个方向,然后再乘以想要的距离就可以得到我们想要的位置坐标。只能读取。
公式如下:
1=x2+y2+ z2
magnitude
返回向量的长度,也就是点P(x,y,z)到原点(0,0,0)的距离。
就是向量的模运算,得到向量的长度。公式如下:
x2+y2+ z2
最常用的是用来返回物体的移动速度
speed=rigidbody.velocity.magnitude;
只能读取。如果想自行规定距离可以先normalized然后乘以距离
speed=speed.normalized*objSpeed;
sqrmagnitude
返回向量长度的平方(只读)。上面那个不开根号就是了,公式如下:
x2+ y2+ z2
大家知道向量的长度是用勾股定理计算出来的,计算机计算两次方和开跟的运算量比加减法要费时的多。所以如果是想比较两个向量的长度的话,用sqrMagnitude可以快很多。
方法:
vertor3 Scale(vector3 scale)
所有的轴向都乘以scale,既(x * xscale, y * yscale, z * zscale)如:
Vector3 position = new Vector3(2.0f, 3.0f, 4.0f);
position.Scale(new Vector3(2.5f, 1.5f, 5.0f));
//此时Position为(5.0f, 4.5f, 20.0f)
a,b ∈Vector3
a.Scale(b);
a.x=a.x * b.x a.y=a.y*b.y a.z=a.z*b.z
vertor3 Scale(vector3 a, vector3 b)
缩放,返回a的每个坐标乘以b的相对应的每个坐标。注意他是静态函数。公式如下:
(xa * xb, ya * yb, za * zb)
a,b,c ∈Vector3
a=Vector3.Scale(b,c);
a.x=b.x * c.x a.y=b.y*c.y a.z=b.z*c.z
Vector3 Cross (Vector3 lhs, Vector3 rhs)
两个向量的叉积,具体关于叉积的解释大家可以自己去网上搜搜,或点击传送门。
http://zh.wikipedia.org/zh/向量积
a = a1i + a2j + a3k = [a1, a2, a3]
b = b1i + b2j + b3k = [b1, b2, b3]
则
a × b = [a2b3 − a3b2, a3b1 − a1b3, a1b2 − a2b1]
Vector3 Reflect (Vector3 inDirection, Vector3 inNormal)
又一个很常用的函数,返回一个向量,让这个向量与另一个向量inDirection以坐标轴inNormal为准镜像。
脚本:
var obj1: Transform;
var obj2: Transform;
var a: Vector3;
var d: Vector3;
var e: Vector3;
var f: Vector3;
a=obj1.position;
b=obj2.position;
e=Vector3.Reflect(a,Vector3.right);//以y轴,z轴组成的面为分割线,让a和e在x轴上镜像。
f=Vector3.Reflect(b,Vector3.right);
Debug.DrawLine(Vector3.zero,f,Color.black);
Debug.DrawLine(Vector3.zero,e,Color.blue);
Debug.DrawLine(Vector3.zero,a,Color.red);
Debug.DrawLine(Vector3.zero,b,Color.green);
float Dot (Vector3 lhs, Vector3 rhs)
点积,跟quaternion里的用法一样。对于normalized后的lhs和rhs,如果指向相同的方向,返回1。返回-1如果他们指向完全相反的方向。其他情况下根据角度返回两者之间的小数。如果两个向量互相垂直,返回0;
点积
两个向量u,v的点积是一个标量,用u · v表示。通用公式:|u||v|cos<u,v>。在三维空间中代数公式:uxvx + uyvy + uzvz。(该公式可以先由二维证明,再推广到多维。二维中的证明:利用点线距公式和勾股定理推出|u|*cos<u,v>的表达式,再根据定义化简即可。)
点积的值由以下三个值确定:
u的大小v的大小u,v夹角的余弦。在u,v非零的前提下,点积如果为负,则u,v形成的角大于90度;如果为零,那么u,v垂直;如果为正,那么u,v形成的角为锐角。
点积得到两个向量的夹角的cos值,通过它可以知道两个向量的相似性,利用点积可判断一个多边形是否面向摄像机还是背向摄像机
一般情况下还是Vector3.Angle()这个函数用的比较多,两者的功能基本是一样的。
Vector3 Project (Vector3 vector, Vector3 onNormal)
投射一个向量到另一个。
返回一个向量,这个向量由vector投射到onNormal。 返回0如果onNormal几乎等于或等于0;
具体工作原理可以通过这个脚本了解到
脚本:
var obj1: Transform;
var obj2: Transform;
var a: Vector3;
var b: Vector3;
var c: Vector3;
a=obj1.position;
b=obj2.position;
c=Vector3.Project(a,b);
Debug.DrawLine(Vector3.zero,c,Color.yellow);
Debug.DrawLine(a,c,Color.white);
Debug.DrawLine(Vector3.zero,a,Color.red);
Debug.DrawLine(Vector3.zero,b,Color.green);
当把obj2的位置设定为(0,1,0)的时候,大家就很容易看出这个函数是如何工作的了
float Angle (Vector3 from, Vector3 to)
这个基本上是我用的非常多的一个函数,用来确定两个向量指向的位置间的夹角
返回从from到to的夹角,单位为度。
我一般用这个来测量坦克之类的车辆的y轴和空间坐标y轴之间的夹角,阻止其登上大于固定角度的斜坡。或者ai只会看见正前方多少度内的敌人,因为他不应该拥有360度的视野。
float Distance (Vector3 a, Vector3 b)
返回从a到b的距离
使用这个函数Vector3.Distance(a,b)的结果跟直接在两个向量间作减法(a-b)后求出的向量的长度是一样的。
也是非常非常常用到的一个函数。
Normalize()
向量化,向量保持相同的方向,注意向量的magnitude(长度)为1。
如果这个向量太小而不能被规范化,一个零向量将会被返回。
Vector3 normalized()
向量保持同样的方向,返回向量的magnitude(长度)为1(只读)。
注意,当前向量是不改变的并且返回一个新的规范化的向量。如果你想规范化当前向量,使用Normalize函数。
如果这个向量太小而不能被规范化,一个零向量将会被返回。
string ToString ()
返回x,y,z的值,一般到小数点后一位。(0.0, 0.0, 0.0)
Vector3 Lerp (Vector3 from, Vector3 to, float t)
跟Quaternion里的lerp一样,返回from和to之间的一个Vector3点p, p=form+(to-form)*t;t的取值范围是[0,1]
Vector3 Slerp (Vector3 from, Vector3 to, float t)
作用跟lerp差不多,但是不是呈直线靠近。
脚本:
var obj1: Transform;
var obj2: Transform;
var a: Vector3;
var b: Vector3;
var c=0.0;
a=Vector3.Lerp(obj1.position,obj2.position,c);
b=Vector3.Slerp(obj1.position,obj2.position,c);
if(Input.GetKeyDown("w"))
c+=0.1;
if(Input.GetKeyDown("s"))
c-=0.1;
输入:
obj1.position=(0,0,0) obj2.position=(0,0,10)
输出:
c=0, a=(0,0,0), b=(0,0,0)
c=0.1 a=(0,0,1), b=(0,0,1)
c=0.5, a=(0,0,5), b=(0,0,5)
c=1, a=(0,0,10), b=(0,0,10)
当from在(0,0,0)的时候,两个函数的效果差不多。但是当from和to都不在原点的时候
输入:
obj1.position=(0,10,0) obj2.position=(0,10,10)
输出:
c=0, a=(0,10,0), b=(0,10,0)
c=0.1 a=(0,10,1), b=(0,10.4,0.8)
c=0.5, a=(0,10,5), b=(0,11.2,4.6)
c=1, a=(0,10,10), b=(0,10,10)
我们可以看到两者之间出现了差异。
右图是两者移动轨迹的区别。
Vector3 RotateTowards (Vector3 from, Vector3 to, float maxRadiansDelta, float maxMagnitudeDelta)
产生一个向量从from旋转并移动到 to,跟Vector3.Slerp类似,但是可以用maxRadiansDelta和max MagnitudeDelta分别控制向量的旋转方向和长度。当maxRadiansDelta=0时,向量指向from, 1则指向to。 当maxMagnitudeDelta=0时,向量的长度=from.magnitude,1则=to.magnitude。 向量的最大有效取值范围为1, 但是最小取值范围可以小于0
maxMagnitudeDelta, maxRadiansDelta [0,-∞]
当maxRadiansDelta和maxMagnitudeDelta为负时,向量会向相反方向旋转和延长。
OrthoNormalize (Vector3 normal, Vector3 tangent)
这个函数读入两个向量normal和tangent, 使tangent 在由tangent 和normal构成的平面上,并与normal垂直。两个向量都被Normalize,也就是长度为1。大家可以用这个脚本在编辑器中看出这个函数是如何工作的。
脚本:
var obj1: Transform;
var obj2: Transform;
var a: Vector3;
var b: Vector3;
var c:Vector3;
var d: Vector3;
a=obj1.position;
b=obj2.position;
c=a;
d=b;
Vector3.OrthoNormalize(a,b);
Debug.DrawLine(Vector3.zero,c,Color.blue);
Debug.DrawLine(Vector3.zero,d,Color.white);
Debug.DrawLine(Vector3.zero,a,Color.red);
Debug.DrawLine(Vector3.zero,b,Color.green);
OrthoNormalize (Vector3 normal, Vector3 tangent, Vector3 binormal)
这个用法多了一个向量binormal,这个向量同时垂直于normal和tangent,三者关系类似三维的直角坐标轴。其中binormal的方向决定binormal在那边垂直于normal和tangent。
脚本:
var obj1: Transform;
var obj2: Transform;
var a: Vector3;
var b: Vector3;
var c:Vector3;
var d: Vector3;
a=obj1.position;
b=obj2.position;
e=transform.position;
c=a;
d=b;
f=e;
Vector3.OrthoNormalize(a,b,e);
Debug.DrawLine(Vector3.zero,c,Color.yellow);
Debug.DrawLine(Vector3.zero,d,Color.white);
Debug.DrawLine(Vector3.zero,f,Color.black);
Debug.DrawLine(Vector3.zero,a,Color.red);
Debug.DrawLine(Vector3.zero,b,Color.green);
Debug.DrawLine(Vector3.zero,e,Color.blue);
Vector3 Min (Vector3 lhs, Vector3 rhs)
返回lhs和rhs中最小的那个向量
Vector3 Max (Vector3 lhs, Vector3 rhs)
返回lhs和rhs中最大的那个向量
这两个也是很常用的。
类特有的一些属性(直接粘help的了):
zero
就是Vector3(0, 0, 0)的宏
one
就是Vector3(1, 1, 1)的宏
forward
就是Vector3(0, 0, 1)的宏
Back
就是Vector3(0, 0, -1)的宏
up
就是Vector3(0, 1, 0)的宏
Down
就是Vector3(0, -1, 0)的宏
Right
就是Vector3(1, 0, 0)的宏
left
就是Vector3(-1, 0, 0)的宏
operators
+ 和 -
两个向量相加和相减
* 和 /
一个向量的所有轴乘以或除以一个float或int, 得到一个新的向量
== 和 !=
判断两向量是否相等
张鑫于北航
2013-02-01
展开阅读全文