目录

叉乘结果向量几何含义 

叉积的坐标表示

 右手螺旋定则

a叉乘b

b叉乘a

几何应用 

叉乘判断物体在人的左右

叉乘计算三角形法线

叉乘计算三角形面积

注意点

Threejs源码实现叉乘 crossVectors、cross

crossVectors

cross


叉乘结果向量几何含义 

在几何学中,叉乘的应用涉及到三维空间中的向量、平面和体积等概念,是解决许多几何问题的重要工具。

一方面是向量方向,向量a叉乘向量b,得到一个新的向量c,向量c垂直于向量a和b构成的平面,或者说向量c同时垂直于向量a、向量b。

另一方面是向量长度,假设向量a和b的夹角是θ,a和b叉乘结果是c,c的长度c.length()是a长度a.length()乘b长度b.length()乘夹角0的正弦值sin(θ)

叉积的坐标表示

用三阶行列式表示 

行列式的任意两行或两列成比例,则行列式为0 

 右手螺旋定则

叉乘不满足交换律,结果向量有垂直于ab向量所共面的正负之分

c = a叉乘b

180度内的参考意义,先把向量c想象成一根筷子,尝试用手去握住它。具体过程就是,把右手手掌展平,四指并拢,大拇指与四指垂直,假设向量a和b处于水平平面上,向量c就是竖直方向,让大拇指沿着c,大拇指朝上还是朝下,随便先选个方向,让四指沿着向量a的方向,去开始握住向量c,这时候如果四指旋转的方向靠近向量b,那么说明大拇指的指向方向是向量c的真内,否则反之

a叉乘b

const a = new THREE.Vector3(50, 0, 0);
const b = new THREE.Vector3(30, 0, 30);
// 箭头可视化向量a、向量b
const O = new THREE.Vector3(0, 0, 0);//给箭头设置一个起点
const arrowA = new THREE.ArrowHelper(a.clone().normalize(), O, a.length(),0xff0000);
const arrowB = new THREE.ArrowHelper(b.clone().normalize(), O, b.length(),0x00ff00);

const c = new THREE.Vector3();// 创建一个向量c保存叉乘结果
c.crossVectors(a,b); // 向量a叉乘b

// 可视化向量a和b叉乘结果:向量c
const arrowC = new THREE.ArrowHelper(c.clone().normalize(), O, c.length()/30,0x0000ff);

b叉乘a

const a = new THREE.Vector3(50, 0, 0);
const b = new THREE.Vector3(30, 0, 30);
// 箭头可视化向量a、向量b
const O = new THREE.Vector3(0, 0, 0);//给箭头设置一个起点
const arrowA = new THREE.ArrowHelper(a.clone().normalize(), O, a.length(),0xff0000);
const arrowB = new THREE.ArrowHelper(b.clone().normalize(), O, b.length(),0x00ff00);

const c = new THREE.Vector3();// 创建一个向量c保存叉乘结果
c.crossVectors(b,a);//向量b叉乘a

// 可视化向量a和b叉乘结果:向量c
const arrowC = new THREE.ArrowHelper(c.clone().normalize(), O, c.length()/30,0x0000ff);

可见,都满足于右手螺旋定则  

几何应用 

叉乘判断物体在人的左右

向量a:人的正前方沿着z轴负半轴的向量

向量b:物体坐标减去人坐标,创建一个人指向物体的向量

用a叉乘b,得到结果向量c,判断c.y的正负,小于0,物体在右侧;大于0,物体在右侧(参考右手定理)

// 已知条件
person.position.set(0, 0, 2);//人位置
// a向量:人的正前方沿着z轴负半轴
const a = new THREE.Vector3(0, 0, -5);
// 箭头可视化向量a
const arrowA = new THREE.ArrowHelper(a.clone().normalize(), person.position, a.length(),0xff0000);


mesh.position.set(2, 0, -3);//物体位置在人右边 向量c朝下    
// 物体坐标减去人坐标,创建一个人指向物体的向量
const b = mesh.position.clone().sub(person.position);
const arrowB = new THREE.ArrowHelper(b.clone().normalize(), person.position, b.length(),0x00ff00);


// a叉乘b  可判断b在a的左右侧
const c = a.clone().cross(b);
c.normalize()
const arrowC = new THREE.ArrowHelper(c, person.position, 2.5 ,0x0000ff); // 可视化向量c方向


// 根据向量c方向,判断物体在人的左侧还是右侧。
if(c.y < 0){
    console.log('物体在人右侧'); // 物体在人右侧
}else if(c.y > 0){
    console.log('物体在人左侧');
}

叉乘计算三角形法线

法向量是空间解析几何的一个概念,垂直于平面的直线所表示的向量为该平面的法向量。由于空间内有无数个直线垂直于已知平面,因此一个平面都存在无数个法向量(包括两个单位法向量)

可以把通过三角形的三个顶点构建两个向量,两个向量叉乘,就会得到一个垂直三角形的向量c。不过注意一点,如果两个向量,随意构建,,实际计算结果向量c虽然都垂直a和b但是方向可能有两种情况。所以,三个顶点构建两个向量,按照三角形顶点的顺序,构建1指向2的向量,2指向3的向量,这样可以向量叉乘结果可以反应三角形三个点位置顺序关系,

const geometry = new THREE.BufferGeometry(); 
const vertices = new Float32Array([
    0, 0, 0, //顶点1坐标
    50, 0, 0, //顶点2坐标
    0, 100, 0, //顶点3坐标
    0, 0, 10, //顶点4坐标
    0, 0, 100, //顶点5坐标
    50, 0, 10, //顶点6坐标
]);
const attribue = new THREE.BufferAttribute(vertices, 3); // 3个为一组,表示一个顶点的xyz坐标
geometry.attributes.position = attribue;
const material = new THREE.MeshBasicMaterial({
    color: 0x00ffff, //材质颜色
    side: THREE.FrontSide, //默认只有正面可见
});
const mesh = new THREE.Mesh(geometry, material); 



// 已知三角形三个顶点的坐标,计算三角形法线方向
const p1 = new THREE.Vector3(0, 0, 0);
const p2 = new THREE.Vector3(50, 0, 0);
const p3 = new THREE.Vector3(0, 100, 0);

const p4 = new THREE.Vector3(0, 0, 10);
const p5 = new THREE.Vector3(0, 0, 100);
const p6 = new THREE.Vector3(50, 0, 10);


// 按照三角形顶点的顺序,构建1指向2的向量,2指向3的向量
const a = p2.clone().sub(p1);
const b = p3.clone().sub(p2);
const c = a.clone().cross(b);
c.normalize();//向量c归一化表示三角形法线方向
// 可视化向量a和b叉乘结果:向量c
const _arrow = new THREE.ArrowHelper(c, p3, 50, 0xff0000);
mesh.add(_arrow);


// 按照三角形顶点的顺序,构建1指向2的向量,2指向3的向量
const e = p5.clone().sub(p4);
const f = p6.clone().sub(p5);
const g = e.clone().cross(f);
g.normalize();//向量h归一化表示三角形法线方向
// 可视化向量a和b叉乘结果:向量c
const arrow_ = new THREE.ArrowHelper(g, p5, 50, 0xffff00);
mesh.add(arrow_);

叉乘计算三角形面积

正弦函数 

 

 

// 已知三角形三个顶点的坐标,计算三角形面积
const p1 = new THREE.Vector3(0, 0, 0);
const p2 = new THREE.Vector3(10, 0, 0);
const p3 = new THREE.Vector3(0, 10, 0);


// 三角形两条边构建两个向量
const a = p2.clone().sub(p1);
const b = p3.clone().sub(p1);
// 两个向量叉乘结果c的几何含义:a.length()*b.length()*sin(θ)
const c = a.clone().cross(b);

// 三角形面积计算
const S = 0.5*c.length();


console.log('S',S); // 50

注意点

  1. 叉乘得到的向量的大小等于两个向量所张成平行四边形的面积的大小,而不是三角形的面积。所以直接求两条边的叉乘并不能得到三角形的面积。

  2. 若要使用叉乘求解三角形的面积,需要先确定两条边构成的向量,然后进行叉乘运算,再将结果除以2才能得到三角形的面积。通常情况下,选取两条边的起点作为原点,得到的叉乘结果再除以2即可得到三角形的面积。

  3. 可以选择任意两条边进行叉乘,但是计算得到的结果可能是一个负值。在几何意义上,负值表示所得的向量方向与正常方向相反,但面积的绝对值是一样的。所以最后要取绝对值。

任意两条边的叉乘都可以用来求解三角形的面积,但需要考虑向量的方向以及取绝对值。 

Threejs源码实现叉乘 crossVectors、cross

crossVectors

向量a叉乘b,结果保存当前向量c

	crossVectors( a, b ) {

		const ax = a.x, ay = a.y, az = a.z;
		const bx = b.x, by = b.y, bz = b.z;

		this.x = ay * bz - az * by;
		this.y = az * bx - ax * bz;
		this.z = ax * by - ay * bx;

		return this;

	}

cross

当前向量a叉乘入参向量v,结果保存当前向量a

	cross: function ( v, w ) {

		if ( w !== undefined ) {

			console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
			return this.crossVectors( v, w );

		}

		var x = this.x, y = this.y, z = this.z;

		this.x = y * v.z - z * v.y;
		this.y = z * v.x - x * v.z;
		this.z = x * v.y - y * v.x;

		return this;

	},

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐