mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-05-09 22:02:45 +08:00
395 lines
9.9 KiB
TypeScript
395 lines
9.9 KiB
TypeScript
import { Mat4, Vec3 } from 'cc';
|
||
import { MathUtil } from './MathUtil';
|
||
|
||
/** 向量工具 */
|
||
export class Vec3Util {
|
||
/**
|
||
* X轴
|
||
*/
|
||
static get x(): Readonly<Vec3> {
|
||
return new Vec3(1, 0, 0);
|
||
}
|
||
|
||
/**
|
||
* Y轴
|
||
*/
|
||
static get y(): Readonly<Vec3> {
|
||
return new Vec3(0, 1, 0);
|
||
}
|
||
|
||
/**
|
||
* Z轴
|
||
*/
|
||
static get z(): Readonly<Vec3> {
|
||
return new Vec3(0, 0, 1);
|
||
}
|
||
|
||
/**
|
||
* 左向量
|
||
*/
|
||
static get left(): Readonly<Vec3> {
|
||
return new Vec3(-1, 0, 0);
|
||
}
|
||
|
||
/**
|
||
* 右向量
|
||
*/
|
||
static get right(): Readonly<Vec3> {
|
||
return new Vec3(1, 0, 0);
|
||
}
|
||
|
||
/**
|
||
* 上向量
|
||
*/
|
||
static get up(): Readonly<Vec3> {
|
||
return new Vec3(0, 1, 0);
|
||
}
|
||
|
||
/**
|
||
* 下向量
|
||
*/
|
||
static get down(): Readonly<Vec3> {
|
||
return new Vec3(0, -1, 0);
|
||
}
|
||
|
||
/**
|
||
* 前向量
|
||
*/
|
||
static get forward(): Readonly<Vec3> {
|
||
return new Vec3(0, 0, 1);
|
||
}
|
||
|
||
/**
|
||
* 后向量
|
||
*/
|
||
static get back(): Readonly<Vec3> {
|
||
return new Vec3(0, 0, -1);
|
||
}
|
||
|
||
/**
|
||
* 1向量
|
||
*/
|
||
static get one(): Readonly<Vec3> {
|
||
return new Vec3(1, 1, 1);
|
||
}
|
||
|
||
/**
|
||
* 0向量
|
||
*/
|
||
static get zero(): Readonly<Vec3> {
|
||
return new Vec3(0, 0, 0);
|
||
}
|
||
|
||
/**
|
||
* 随时间变化进度值
|
||
* @param start 起始位置
|
||
* @param end 结束位置
|
||
* @param t 进度[0,1]
|
||
*/
|
||
static progress(start: Vec3, end: Vec3, t: number): Vec3 {
|
||
const current = new Vec3();
|
||
current.x = MathUtil.progress(start.x, end.x, t);
|
||
current.y = MathUtil.progress(start.y, end.y, t);
|
||
current.z = MathUtil.progress(start.z, end.z, t);
|
||
return current;
|
||
}
|
||
|
||
/**
|
||
* 求两个三维向量的和
|
||
* @param pos1 向量1
|
||
* @param pos2 向量2
|
||
*/
|
||
static add(pos1: Vec3, pos2: Vec3): Vec3 {
|
||
const outPos: Vec3 = new Vec3();
|
||
Vec3.add(outPos, pos1, pos2);
|
||
return outPos;
|
||
}
|
||
|
||
/**
|
||
* 求两个三维向量的差
|
||
* @param pos1 向量1
|
||
* @param pos2 向量2
|
||
*/
|
||
static sub(pos1: Vec3, pos2: Vec3): Vec3 {
|
||
const outPos: Vec3 = new Vec3();
|
||
Vec3.subtract(outPos, pos1, pos2);
|
||
return outPos;
|
||
}
|
||
|
||
/**
|
||
* 三维向量乘以常量
|
||
* @param pos 向量
|
||
* @param scalar 常量
|
||
*/
|
||
static mul(pos: Vec3, scalar: number): Vec3 {
|
||
const outPos: Vec3 = new Vec3();
|
||
Vec3.multiplyScalar(outPos, pos, scalar);
|
||
return outPos;
|
||
}
|
||
|
||
/**
|
||
* 三维向量除常量
|
||
* @param pos 向量
|
||
* @param scalar 常量
|
||
*/
|
||
static div(pos: Vec3, scalar: number): Vec3 {
|
||
const outPos: Vec3 = new Vec3();
|
||
|
||
outPos.x = pos.x / scalar;
|
||
outPos.y = pos.y / scalar;
|
||
outPos.z = pos.z / scalar;
|
||
|
||
return outPos;
|
||
}
|
||
|
||
/**
|
||
* 判断两个三维向量的值是否相等
|
||
* @param pos1 向量1
|
||
* @param pos2 向量2
|
||
*/
|
||
static equals(pos1: Vec3, pos2: Vec3): boolean {
|
||
return pos1.x == pos2.x && pos1.y == pos2.y && pos1.z == pos2.z;
|
||
}
|
||
|
||
/**
|
||
* 三维向量的模
|
||
* @param pos 向量
|
||
*/
|
||
static magnitude(pos: Vec3): number {
|
||
return pos.length();
|
||
}
|
||
|
||
/**
|
||
* 三维向量归一化
|
||
* @param pos 向量
|
||
*/
|
||
static normalize(pos: Vec3): Vec3 {
|
||
const outPos: Vec3 = new Vec3(pos.x, pos.y, pos.z);
|
||
return outPos.normalize();
|
||
}
|
||
|
||
/**
|
||
* 获得位置1,到位置2的方向
|
||
* @param pos1 向量1
|
||
* @param pos2 向量2
|
||
*/
|
||
static direction(pos1: Vec3, pos2: Vec3): Vec3 {
|
||
const outPos: Vec3 = new Vec3();
|
||
Vec3.subtract(outPos, pos2, pos1);
|
||
return outPos.normalize();
|
||
}
|
||
|
||
/**
|
||
* 获得两点间的距离
|
||
* @param pos1 向量1
|
||
* @param pos2 向量2
|
||
*/
|
||
static distance(pos1: Vec3, pos2: Vec3): number {
|
||
return Vec3.distance(pos1, pos2);
|
||
}
|
||
|
||
/**
|
||
* 插值运算
|
||
* @param posStart 开始俏步
|
||
* @param posEnd 结束位置
|
||
* @param t 时间
|
||
*/
|
||
static lerp(posStart: Vec3, posEnd: Vec3, t: number): Vec3 {
|
||
return this.bezierOne(t, posStart, posEnd);
|
||
}
|
||
|
||
/**
|
||
* 球面插值
|
||
* @param from 起点
|
||
* @param to 终点
|
||
* @param t 时间
|
||
*/
|
||
static slerp(from: Vec3, to: Vec3, t: number): Vec3 {
|
||
if (t <= 0) {
|
||
return from;
|
||
}
|
||
else if (t >= 1) {
|
||
return to;
|
||
}
|
||
|
||
const dir: Vec3 = this.rotateTo(from, to, (Vec3.angle(from, to) / Math.PI * 180) * t);
|
||
const lenght: number = to.length() * t + from.length() * (1 - t);
|
||
|
||
return (dir.normalize()).multiplyScalar(lenght);
|
||
}
|
||
|
||
/**
|
||
* 向量旋转一个角度
|
||
* @param from 起点
|
||
* @param to 终点
|
||
* @param angle 角并
|
||
*/
|
||
static rotateTo(from: Vec3, to: Vec3, angle: number): Vec3 {
|
||
//如果两个方向角度为0,则返回目标
|
||
if (Vec3.angle(from, to) == 0) {
|
||
return to;
|
||
}
|
||
|
||
const axis: Vec3 = new Vec3(); // 获得旋转轴
|
||
Vec3.cross(axis, from, to);
|
||
axis.normalize();
|
||
|
||
const radian: number = angle * Math.PI / 180; // 获得弧度
|
||
const rotateMatrix: Mat4 = new Mat4();
|
||
rotateMatrix.rotate(radian, axis);
|
||
|
||
return new Vec3(
|
||
from.x * rotateMatrix.m00 + from.y * rotateMatrix.m04 + from.z * rotateMatrix.m08,
|
||
from.x * rotateMatrix.m01 + from.y * rotateMatrix.m05 + from.z * rotateMatrix.m09,
|
||
from.x * rotateMatrix.m02 + from.y * rotateMatrix.m06 + from.z * rotateMatrix.m10
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 一次贝塞尔即为线性插值函数
|
||
* @param t
|
||
* @param posStart
|
||
* @param posEnd
|
||
* @returns
|
||
*/
|
||
static bezierOne(t: number, posStart: Vec3, posEnd: Vec3): Vec3 {
|
||
if (t > 1) {
|
||
t = 1;
|
||
}
|
||
else if (t < 0) {
|
||
t = 0;
|
||
}
|
||
|
||
const pStart: Vec3 = posStart.clone();
|
||
const pEnd: Vec3 = posEnd.clone();
|
||
|
||
return pStart.multiplyScalar(1 - t).add(pEnd.multiplyScalar(t));
|
||
}
|
||
|
||
/**
|
||
* 二次贝塞尔曲线
|
||
* @param t
|
||
* @param posStart
|
||
* @param posCon
|
||
* @param posEnd
|
||
* @returns
|
||
*/
|
||
static bezierTwo(t: number, posStart: Vec3, posCon: Vec3, posEnd: Vec3): Vec3 {
|
||
if (t > 1) {
|
||
t = 1;
|
||
}
|
||
else if (t < 0) {
|
||
t = 0;
|
||
}
|
||
|
||
const n = (1 - t);
|
||
const tt = t * t;
|
||
|
||
const pStart: Vec3 = posStart.clone();
|
||
const pos = new Vec3();
|
||
|
||
const pCon: Vec3 = posCon.clone();
|
||
const pEnd: Vec3 = posEnd.clone();
|
||
|
||
pos.add(pStart.multiplyScalar(n * n));
|
||
pos.add(pCon.multiplyScalar(2 * n * t));
|
||
pos.add(pEnd.multiplyScalar(tt));
|
||
|
||
return pos;
|
||
}
|
||
|
||
/**
|
||
* 三次贝塞尔
|
||
* @param t
|
||
* @param posStart
|
||
* @param posCon1
|
||
* @param posCon2
|
||
* @param posEnd
|
||
* @returns
|
||
*/
|
||
static bezierThree(t: number, posStart: Vec3, posCon1: Vec3, posCon2: Vec3, posEnd: Vec3): Vec3 {
|
||
if (t > 1) {
|
||
t = 1;
|
||
}
|
||
else if (t < 0) {
|
||
t = 0;
|
||
}
|
||
|
||
const n = (1 - t);
|
||
const nn = n * n;
|
||
const nnn = nn * n;
|
||
const tt = t * t;
|
||
const ttt = tt * t;
|
||
|
||
const pStart: Vec3 = posStart.clone();
|
||
const pos = posStart.clone();
|
||
|
||
const pCon1: Vec3 = posCon1.clone();
|
||
const pCon2: Vec3 = posCon2.clone();
|
||
const pEnd: Vec3 = posEnd.clone();
|
||
|
||
pos.add(pStart.multiplyScalar(nnn));
|
||
pos.add(pCon1.multiplyScalar(3 * nn * t));
|
||
pos.add(pCon2.multiplyScalar(3 * n * tt));
|
||
pos.add(pEnd.multiplyScalar(ttt));
|
||
|
||
return pos;
|
||
}
|
||
|
||
/**
|
||
* 点乘
|
||
* @param dir1 方向量1
|
||
* @param dir2 方向量2
|
||
*/
|
||
static dot(dir1: Vec3, dir2: Vec3): number {
|
||
const tempDir1: Vec3 = dir1;
|
||
const tempDir2: Vec3 = dir2;
|
||
|
||
return tempDir1.x * tempDir2.x + tempDir1.y * tempDir2.y + tempDir1.z * tempDir2.z;
|
||
}
|
||
|
||
/**
|
||
* 叉乘
|
||
* @param dir1 方向量1
|
||
* @param dir2 方向量2
|
||
*/
|
||
static cross(dir1: Vec3, dir2: Vec3): Vec3 {
|
||
const i: Vec3 = new Vec3(1, 0, 0);
|
||
const j: Vec3 = new Vec3(0, 1, 0);
|
||
const k: Vec3 = new Vec3(0, 0, 1);
|
||
|
||
const tempDir1: Vec3 = new Vec3(dir1.x, dir1.y, dir1.z);
|
||
const tempDir2: Vec3 = new Vec3(dir2.x, dir2.y, dir2.z);
|
||
|
||
const iv: Vec3 = i.multiplyScalar(tempDir1.y * tempDir2.z - tempDir2.y * tempDir1.z);
|
||
const jv: Vec3 = j.multiplyScalar(tempDir2.x * tempDir1.z - tempDir1.x * tempDir2.z);
|
||
const kv: Vec3 = k.multiplyScalar(tempDir1.x * tempDir2.y - tempDir2.x * tempDir1.y);
|
||
|
||
return iv.add(jv).add(kv);
|
||
}
|
||
|
||
/**
|
||
* 获得两个方向向量的角度
|
||
* @param dir1 方向量1
|
||
* @param dir2 方向量2
|
||
*/
|
||
static angle(dir1: Vec3, dir2: Vec3): number {
|
||
const dotValue = this.dot(dir1.clone().normalize(), dir2.clone().normalize());
|
||
return Math.acos(dotValue) / Math.PI * 180 * Math.sign(dotValue);
|
||
}
|
||
|
||
/**
|
||
* 获得方向a到方向b的角度(带有方向的角度)
|
||
* @param a 角度a
|
||
* @param b 角度b
|
||
*/
|
||
static dirAngle(a: Vec3, b: Vec3): number {
|
||
const c: Vec3 = Vec3Util.cross(a, b);
|
||
const angle: number = Vec3Util.angle(a, b);
|
||
// a 到 b 的夹角
|
||
const sign = Math.sign(Vec3Util.dot(c.normalize(), Vec3Util.cross(b.normalize(), a.normalize())));
|
||
|
||
return angle * sign;
|
||
}
|
||
}
|