Files
oops-plugin-framework/assets/core/utils/Vec3Util.ts
2025-12-13 23:32:56 +08:00

395 lines
9.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 进度[01]
*/
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;
}
}