Cocos Creator 3D 必懂知识(点乘、叉乘)

向量的点乘(内积)

定义

概括地说,向量的点乘(内积/数量积)。对两个向量执行点乘运算,就是对这两个向量对应位一一相乘之后求和的操作,如下所示,对于向量a和向量b:

img img

a和b的点乘公式为:

img

这里要求一维向量a和向量b的行列数相同。注意:点乘的结果是一个标量(数量而不是向量)

定义:两个向量ab的点乘为 a·b = |a||b|cos∠(a, b),特别地,0·a =a·0 = 0;若ab是非零向量,则ab****正交的充要条件是a·b = 0。

向量点乘的性质

  1. a^2 ≥ 0;当a^2 = 0时,必有a = 0. (正定性)
  2. a·b = b·a. (对称性)
  3. a + μbc = λa·c + μb·c,对任意实数λ, μ成立. (线性)
  4. cos∠(a,b) =a·b/(|a||b|).
  5. |a·b| ≤ |a||b|,等号只在ab共线时成立.

向量点乘的几何意义

  1. 表征或计算两个向量之间的夹角;
  2. b向量在a向量方向上的投影;

有公式:

img

推导过程如下,首先看一下向量组成:

img

定义向量c

img

根据三角形余弦定理(这里a、b、c均为向量,下同)有:

img

根据关系c=a-b有:

img

即:

a∙b=|a||b|cos⁡(θ)

向量a,b的长度都是可以计算的已知量,从而有a和b间的夹角θ:

θ=arccos⁡(a∙b|a||b|)

进而可以进一步判断两个向量是否同一方向或正交(即垂直)等方向关系,具体对应关系为:

a∙b>0→方向基本相同,夹角在0°到90°之间
a∙b=0→ 正交,相互垂直
a∙b<0→ 方向基本相反,夹角在90°到180°之间

向量的叉乘(外积)

定义

概括地说,两个向量的叉乘,又叫外积、叉积向量积,其运算结果是一个向量而不是一个标量。并且两个向量的叉乘与这两个向量组成的坐标平面垂直。

定义:向量ab的外积a×b是一个向量,其长度等于|a×b| = |a||b|sin∠(a,b),其方向正交于ab。并且,(a,b,a×b)构成右手系。
特别地,0×a = a×0 = 0.此外,对任意向量aa×a=0

对于向量a和向量b:

img

a和b的叉乘公式为:

img

其中:

img

根据i、j、k间关系,有:

img

向量叉乘的性质

  1. a × b = -b × a. (反称性)
  2. a + μb) × c = λ(a ×c) + μ(b ×c). (线性)

向量叉乘的几何意义

在三维几何中,向量a和向量b的外积结果是一个向量,有个更通俗易懂的叫法是法向量,该向量垂直于a和b向量构成的平面。

在3D图像学中,外积的概念非常有用,可以通过两个向量的叉乘,生成第三个垂直于a,b的法向量,从而构建X、Y、Z坐标系。如下图所示:

img

在二维空间中,叉乘还有另外一个几何意义就是:|a×b|在数值上等于由向量a和向量b构成的平行四边形的面积。

总结

点乘作用:

  1. 表征或计算两个向量之间的夹角;
  2. b向量在a向量方向上的投影;

叉乘作用:

  1. 二维空间中,|a×b|在数值上等于由向量a和向量b构成的平行四边形的面积;
  2. 三维空间中,可以通过两个向量的叉乘,生成第三个垂直于a,b的法向量,从而构建X、Y、Z坐标系;

重点 - 上代码

import { Vec3 } from 'cc';

export class Vector3 {
	/**
	 * 获得两个三维向量的和
	 * @param pos1
	 * @param pos2
	 */
	public static add(pos1: Vec3, pos2: Vec3): Vec3 {
		var outPos: Vec3 = new Vec3();
		Vec3.add(outPos, pos1, pos2);
		return outPos;
	}

	/**
	 * 获得两个三维向量的差
	 * @param pos1
	 * @param pos2
	 */
	public static sub(pos1: Vec3, pos2: Vec3): Vec3 {
		var outPos: Vec3 = new Vec3();
		Vec3.subtract(outPos, pos1, pos2);
		return outPos;
	}

	/**
	 * 三维向量乘以常量
	 * @param pos1 b
	 * @param pos2
	 */
	public static mul(pos: Vec3, scalar: number): Vec3 {
		var outPos: Vec3 = new Vec3();
		Vec3.multiplyScalar(outPos, pos, scalar);
		return outPos;
	}

	/**
	 * 三维向量除常量
	 * @param pos1 b
	 * @param pos2
	 */
	public static div(pos: Vec3, scalar: number): Vec3 {
		var outPos: Vec3 = new Vec3();

		outPos.x = pos.x / scalar;
		outPos.y = pos.y / scalar;
		outPos.z = pos.z / scalar;

		return outPos;
	}

	/**
	 * 判断两个三维向量的值是否相等
	 * @param pos1
	 * @param pos2
	 */
	public static equals(pos1: Vec3, pos2: Vec3): boolean {
		if (pos1.x == pos2.x && pos1.y == pos2.y && pos1.z == pos2.z) {
			return true;
		}

		return false;
	}

	/**
	 * 三维向量的模
	 */
	public static magnitude(pos: Vec3): number {
		return pos.length();
	}

	/**
	 * 三维向量归一化(标准化、统一化)
	 */
	public static normalize(pos: Vec3): Vec3 {
		var outPos: Vec3 = new Vec3(pos.x, pos.y, pos.z);
		return outPos.normalize();
	}

	/**
	 * 获得位置pos1,到位置 pos2 的方向;pos1=>pos2
	 */
	public static direction(pos1: Vec3, pos2: Vec3): Vec3 {
		var outPos: Vec3 = new Vec3();
		Vec3.subtract(outPos, pos2, pos1);
		return outPos.normalize();
	}

	/**
	 * 获得两点间的距离
	 * @param pos1
	 * @param pos2
	 */
	public static distance(pos1: Vec3, pos2: Vec3): number {
		return Vec3.distance(pos1, pos2);
	}

	/**
	 * 点乘 
	 * @param dir1
	 * @param dir2
	 */
	public static dot(dir1: Vec3, dir2: Vec3): number {
		var tempDir1: Vec3 = dir1;
		var tempDir2: Vec3 = dir2;

		return tempDir1.x * tempDir2.x + tempDir1.y * tempDir2.y + tempDir1.z * tempDir2.z;
	}

	/**
	 * 叉乘
	 * @param dir1
	 * @param dir2
	 */
	public static cross(dir1: Vec3, dir2: Vec3): Vec3 {
		var i: Vec3 = new Vec3(1, 0, 0);
		var j: Vec3 = new Vec3(0, 1, 0);
		var k: Vec3 = new Vec3(0, 0, 1);

		var tempDir1: Vec3 = new Vec3(dir1.x, dir1.y, dir1.z);
		var tempDir2: Vec3 = new Vec3(dir2.x, dir2.y, dir2.z);

		var iv: Vec3 = i.multiplyScalar(tempDir1.y * tempDir2.z - tempDir2.y * tempDir1.z);
		var jv: Vec3 = j.multiplyScalar(tempDir2.x * tempDir1.z - tempDir1.x * tempDir2.z);
		var kv: Vec3 = k.multiplyScalar(tempDir1.x * tempDir2.y - tempDir2.x * tempDir1.y);

		return iv.add(jv).add(kv);
	}

	/**
	 * 获得两个方向向量的角度
	 * @param dir1
	 * @param dir2
	 */
	public static angle(dir1: Vec3, dir2: Vec3): number {
		// a、b的点乘
		var dotValue = this.dot(dir1.clone().normalize(), dir2.clone().normalize());
		// θ = arccos⁡(a∙b|a||b|)
		// 因为a、b都标准化,a、b的模都为 1 ; 故 θ = arccos⁡(a∙b)
		return (Math.acos(dotValue) / Math.PI) * 180 * Math.sign(dotValue);
	}

	/**
	 * 获得方向a到方向b的角度(带有方向的角度)
	 * @param a
	 * @param b
	 */
	public static dirAngle(a: Vec3, b: Vec3): number {
		// a、b的叉乘
		var c: Vec3 = Vector3.cross(a, b);
		// a、b的夹角
		var angle: number = Vector3.angle(a, b);
		// a到b夹角的符号
		var sign = Math.sign(Vector3.dot(c.normalize(), Vector3.cross(b.normalize(), a.normalize())));

		return angle * sign;
	}
}

Reference

  • http://blog.csdn.net/dcrmg/article/details/52416832
  • http://blog.csdn.net/baimafujinji/article/details/50237081
  • http://blog.csdn.net/hunter_wwq/article/details/41248537
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值