# 【向量】
# 定义
把方向和大小构成一个值,称其为向量,若其向量的大小为1,则称其为单位向量。
# 运算
不同的向量运算,需要确保是同一个空间里的向量。
# 向量长度
public float magnitude { get { return (float)Math.Sqrt(x * x + y * y); } }
# 向量归一
让向量长度变为1。 也成为模向量。 x和y分别进行除以向量长度。
公式:
# 向量加法
- 空间里坐标点A和B, 那么 A+B的向量 = A与B 夹角中间的向量。
new Vector2(a.x + b.x, a.y + b.y);
# 向量减法
- 空间里坐标点A和B, 那么 A->B的向量 = B - A。
- 比如地图上,存在玩家和怪物两个单位。 两个单位的坐标都知道了,那么角色与怪物在世界空间里构成的方向向量怎么求呢?这里就可以用到向量的减法了。 玩家 -> 怪物 的向量 = 怪物的坐标 - 玩家的坐标
- 查看实战案例
new Vector2(a.x - b.x, a.y - b.y);
# 向量加减法公式和示意图
# 向量点乘
- 结果为所形成投影长度。
- 经典应用场合:计算兰伯特光照模型,使用模型法线与光方向的反方向进行点乘,重合为1反向为-1,形成一个有一半球的面积有光渐变的效果,类似于被光照亮的光照模型。
- 查看动画
公式1:
公式2:
public static float Dot(Vector2 lhs, Vector2 rhs) { return lhs.x * rhs.x + lhs.y * rhs.y; }
# 向量叉乘
- 获取与两个向量交叉且垂直的第三个向量。
- 计算面积,向量a与向量b进行叉乘,结果为a和b所构成平行四边形的面积。
- 计算点是否在三角形内部。
- 判断向量的左右关系(比如导弹自动跟踪怪物的功能)。
- 查看动画
公式:
public static Vector3 Cross(Vector3 lhs, Vector3 rhs)
{
return new Vector3(
lhs.y * rhs.z - lhs.z * rhs.y,
lhs.z * rhs.x - lhs.x * rhs.z,
lhs.x * rhs.y - lhs.y * rhs.x);
}
使用叉乘获取网格表面积
public static float GetMeshArea(mesh)
{
Vector3[] verts = mesh.vertices;
int[] tris = mesh.triangles;
float area = 0f;
for(int i = 0; i < tris.Length;i+=3)
{
int aIndex = tris[i];
int bIndex = tris[i+1];
int cIndex = tris[i+2];
Vector3 a = verts[aIndex];
Vector3 b = verts[bIndex];
Vector3 c = verts[cIndex];
area += Vector3.Cross(b-a,c-a).magnitude;
}
area /= 2;
return area;
}
计算点是否在三角形内部:
static bool is_point_in_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c)
{
Vector2 an = a - s;
Vector2 bn = b - s;
Vector2 cn = c - s;
bool orientation = an.cross(bn) > 0;
if ((bn.cross(cn) > 0) != orientation) {
return false;
}
return (cn.cross(an) > 0) == orientation;
}
# 向量与标量运算
- 乘以一个大于1的标量时,延长。
- 乘以一个大于0小于1的标量时,缩短。
- 乘以-1时,向量反向。
公式:
# 3D向量旋转
// 把target向量绕X轴旋转degress值的角度
float3 RotateAroundX(float degress,float3 target)
{
float rad = degress * UNITY_PI / 180;
float2x2 m_rotate = float2x2(cos(rad),-sin(rad),sin(rad),cos(rad));
float2 dir_rotate = mul(m_rotate,target.yz);
target = float3(target.x,dir_rotate.x,dir_rotate.y);
return target;
}
// 把target向量绕Y轴旋转degress值的角度
float3 RotateAroundY(float degress,float3 target)
{
float rad = degress * UNITY_PI / 180;
float2x2 m_rotate = float2x2(cos(rad),-sin(rad),sin(rad),cos(rad));
float2 dir_rotate = mul(m_rotate,target.xz);
target = float3(dir_rotate.x,target.y,dir_rotate.y);
return target;
}
// 把target向量绕Z轴旋转degress值的角度
float3 RotateAroundZ(float degress,float3 target)
{
float rad = degress * UNITY_PI / 180;
float2x2 m_rotate = float2x2(cos(rad),-sin(rad),sin(rad),cos(rad));
float2 dir_rotate = mul(m_rotate,target.xy);
target = float3(dir_rotate.x,dir_rotate.y,target.z);
return target;
}
# Projection And Rejection
// Projection
float3 projection(float3 A,float3 B)
{
return B * dot(A,B) / dot(B,B);
}
// Rejection
float3 rejection(float3 A,float3 B)
{
return A - (B * dot(A,B) / dot(B,B));
}
← 【声音插值】 【向量叉乘动画示意】 →