Files
cocos-engine/cocos/core/math/vec3.jsb.ts
2022-05-17 11:56:06 +08:00

1103 lines
36 KiB
TypeScript

/*
Copyright (c) 2016 Chukong Technologies Inc.
Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
import { CCClass } from '../data/class';
import { Mat4 } from './mat4.jsb';
import { IVec3Like, FloatArray, IMat3, IMat4, IQuat, IVec3 } from './type-define';
import { clamp, enumerableProps, EPSILON, random } from './utils';
import { legacyCC } from '../global-exports';
import { MathBase } from './math-base';
declare interface IWritableArrayLike<T> {
readonly length: number;
[index: number]: T;
}
/**
* @en Representation of 3D vectors and points.
* @zh 三维向量。
*/
export class Vec3 extends MathBase {
public static UNIT_X = Object.freeze(new Vec3(1, 0, 0));
public static UNIT_Y = Object.freeze(new Vec3(0, 1, 0));
public static UNIT_Z = Object.freeze(new Vec3(0, 0, 1));
public static RIGHT = Object.freeze(new Vec3(1, 0, 0));
public static UP = Object.freeze(new Vec3(0, 1, 0));
public static FORWARD = Object.freeze(new Vec3(0, 0, -1)); // we use -z for view-dir
public static ZERO = Object.freeze(new Vec3(0, 0, 0));
public static ONE = Object.freeze(new Vec3(1, 1, 1));
public static NEG_ONE = Object.freeze(new Vec3(-1, -1, -1));
/**
* @en return a Vec3 object with x = 0, y = 0, z = 0.
* @zh 将目标赋值为零向量
*/
public static zero<Out extends IVec3Like> (out: Out) {
out.x = 0;
out.y = 0;
out.z = 0;
return out;
}
/**
* @en Obtains a clone of the given vector object
* @zh 获得指定向量的拷贝
*/
public static clone <Out extends IVec3Like> (a: IVec3) {
return new Vec3(a.x, a.y, a.z);
}
/**
* @en Copy the target vector and save the results to out vector object
* @zh 复制目标向量
*/
public static copy<Out extends IVec3Like> (out: Out, a: IVec3) {
out.x = a.x;
out.y = a.y;
out.z = a.z;
return out;
}
/**
* @en Sets the out vector with the given x, y and z values
* @zh 设置向量值
*/
public static set<Out extends IVec3Like> (out: Out, x: number, y: number, z: number) {
out.x = x;
out.y = y;
out.z = z;
return out;
}
/**
* @en Element-wise vector addition and save the results to out vector object
* @zh 逐元素向量加法
*/
public static add<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3) {
out.x = a.x + b.x;
out.y = a.y + b.y;
out.z = a.z + b.z;
return out;
}
/**
* @en Element-wise vector subtraction and save the results to out vector object
* @zh 逐元素向量减法
*/
public static subtract<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3) {
out.x = a.x - b.x;
out.y = a.y - b.y;
out.z = a.z - b.z;
return out;
}
/**
* @en Element-wise vector multiplication and save the results to out vector object
* @zh 逐元素向量乘法 (分量积)
*/
public static multiply<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3) {
out.x = a.x * b.x;
out.y = a.y * b.y;
out.z = a.z * b.z;
return out;
}
/**
* @en Element-wise vector division and save the results to out vector object
* @zh 逐元素向量除法
*/
public static divide<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3) {
out.x = a.x / b.x;
out.y = a.y / b.y;
out.z = a.z / b.z;
return out;
}
/**
* @en Rounds up by elements of the vector and save the results to out vector object
* @zh 逐元素向量向上取整
*/
public static ceil<Out extends IVec3Like> (out: Out, a: IVec3) {
out.x = Math.ceil(a.x);
out.y = Math.ceil(a.y);
out.z = Math.ceil(a.z);
return out;
}
/**
* @en Element-wise rounds down of the current vector and save the results to the out vector
* @zh 逐元素向量向下取整
*/
public static floor<Out extends IVec3Like> (out: Out, a: IVec3) {
out.x = Math.floor(a.x);
out.y = Math.floor(a.y);
out.z = Math.floor(a.z);
return out;
}
/**
* @en Calculates element-wise minimum values and save to the out vector
* @zh 逐元素向量最小值
*/
public static min<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3) {
out.x = Math.min(a.x, b.x);
out.y = Math.min(a.y, b.y);
out.z = Math.min(a.z, b.z);
return out;
}
/**
* @en Calculates element-wise maximum values and save to the out vector
* @zh 逐元素向量最大值
*/
public static max<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3) {
out.x = Math.max(a.x, b.x);
out.y = Math.max(a.y, b.y);
out.z = Math.max(a.z, b.z);
return out;
}
/**
* @en Calculates element-wise round results and save to the out vector
* @zh 逐元素向量四舍五入取整
*/
public static round<Out extends IVec3Like> (out: Out, a: IVec3) {
out.x = Math.round(a.x);
out.y = Math.round(a.y);
out.z = Math.round(a.z);
return out;
}
/**
* @en Vector scalar multiplication and save the results to out vector object
* @zh 向量标量乘法
*/
public static multiplyScalar<Out extends IVec3Like> (out: Out, a: IVec3, b: number) {
out.x = a.x * b;
out.y = a.y * b;
out.z = a.z * b;
return out;
}
/**
* @en Element-wise multiplication and addition with the equation: a + b * scale
* @zh 逐元素向量乘加: A + B * scale
*/
public static scaleAndAdd<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3, scale: number) {
out.x = a.x + b.x * scale;
out.y = a.y + b.y * scale;
out.z = a.z + b.z * scale;
return out;
}
/**
* @en Calculates the euclidean distance of two vectors
* @zh 求两向量的欧氏距离
*/
public static distance (a: IVec3, b: IVec3) {
const x = b.x - a.x;
const y = b.y - a.y;
const z = b.z - a.z;
return Math.sqrt(x * x + y * y + z * z);
}
/**
* @en Calculates the squared euclidean distance of two vectors
* @zh 求两向量的欧氏距离平方
*/
public static squaredDistance (a: IVec3, b: IVec3) {
const x = b.x - a.x;
const y = b.y - a.y;
const z = b.z - a.z;
return x * x + y * y + z * z;
}
/**
* @en Calculates the length of the vector
* @zh 求向量长度
*/
public static len (a: IVec3) {
const x = a.x;
const y = a.y;
const z = a.z;
return Math.sqrt(x * x + y * y + z * z);
}
/**
* @en Calculates the squared length of the vector
* @zh 求向量长度平方
*/
public static lengthSqr (a: IVec3) {
const x = a.x;
const y = a.y;
const z = a.z;
return x * x + y * y + z * z;
}
/**
* @en Sets each element to its negative value
* @zh 逐元素向量取负
*/
public static negate<Out extends IVec3Like> (out: Out, a: IVec3) {
out.x = -a.x;
out.y = -a.y;
out.z = -a.z;
return out;
}
/**
* @en Sets each element to its inverse value, zero value will become Infinity
* @zh 逐元素向量取倒数,接近 0 时返回 Infinity
*/
public static invert<Out extends IVec3Like> (out: Out, a: IVec3) {
out.x = 1.0 / a.x;
out.y = 1.0 / a.y;
out.z = 1.0 / a.z;
return out;
}
/**
* @en Sets each element to its inverse value, zero value will remain zero
* @zh 逐元素向量取倒数,接近 0 时返回 0
*/
public static invertSafe<Out extends IVec3Like> (out: Out, a: IVec3) {
const x = a.x;
const y = a.y;
const z = a.z;
if (Math.abs(x) < EPSILON) {
out.x = 0;
} else {
out.x = 1.0 / x;
}
if (Math.abs(y) < EPSILON) {
out.y = 0;
} else {
out.y = 1.0 / y;
}
if (Math.abs(z) < EPSILON) {
out.z = 0;
} else {
out.z = 1.0 / z;
}
return out;
}
/**
* @en Sets the normalized vector to the out vector
* @zh 归一化向量
*/
public static normalize<Out extends IVec3Like> (out: Out, a: IVec3) {
const x = a.x;
const y = a.y;
const z = a.z;
let len = x * x + y * y + z * z;
if (len > 0) {
len = 1 / Math.sqrt(len);
out.x = x * len;
out.y = y * len;
out.z = z * len;
}
return out;
}
/**
* @en Calculates the dot product of the vector
* @zh 向量点积(数量积)
*/
public static dot <Out extends IVec3Like> (a: IVec3, b: IVec3) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
/**
* @en Calculates the cross product of the vector
* @zh 向量叉积(向量积)
*/
public static cross<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3) {
const { x: ax, y: ay, z: az } = a;
const { x: bx, y: by, z: bz } = b;
out.x = ay * bz - az * by;
out.y = az * bx - ax * bz;
out.z = ax * by - ay * bx;
return out;
}
/**
* @en Calculates the linear interpolation between two vectors with a given ratio
* @zh 逐元素向量线性插值: A + t * (B - A)
*/
public static lerp<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3, t: number) {
out.x = a.x + t * (b.x - a.x);
out.y = a.y + t * (b.y - a.y);
out.z = a.z + t * (b.z - a.z);
return out;
}
/**
* @en Generates a uniformly distributed random vector points from center to the surface of the unit sphere
* @zh 生成一个在单位球体上均匀分布的随机向量
* @param scale vector length
*/
public static random<Out extends IVec3Like> (out: Out, scale?: number) {
scale = scale || 1.0;
const phi = random() * 2.0 * Math.PI;
const cosTheta = random() * 2 - 1;
const sinTheta = Math.sqrt(1 - cosTheta * cosTheta);
out.x = sinTheta * Math.cos(phi) * scale;
out.y = sinTheta * Math.sin(phi) * scale;
out.z = cosTheta * scale;
return out;
}
/**
* @en Vector and fourth order matrix multiplication, will complete the vector with a fourth value as one
* @zh 向量与四维矩阵乘法,默认向量第四位为 1。
*/
public static transformMat4 <Out extends IVec3Like> (out: Out, a: IVec3, m: IMat4) {
const x = a.x;
const y = a.y;
const z = a.z;
let rhw = m.m03 * x + m.m07 * y + m.m11 * z + m.m15;
rhw = rhw ? Math.abs(1 / rhw) : 1;
out.x = (m.m00 * x + m.m04 * y + m.m08 * z + m.m12) * rhw;
out.y = (m.m01 * x + m.m05 * y + m.m09 * z + m.m13) * rhw;
out.z = (m.m02 * x + m.m06 * y + m.m10 * z + m.m14) * rhw;
return out;
}
/**
* @en Vector and fourth order matrix multiplication, will complete the vector with a fourth element as one
* @zh 向量与四维矩阵乘法,默认向量第四位为 0。
*/
public static transformMat4Normal<Out extends IVec3Like> (out: Out, a: IVec3, m: IMat4) {
const x = a.x;
const y = a.y;
const z = a.z;
let rhw = m.m03 * x + m.m07 * y + m.m11 * z;
rhw = rhw ? Math.abs(1 / rhw) : 1;
out.x = (m.m00 * x + m.m04 * y + m.m08 * z) * rhw;
out.y = (m.m01 * x + m.m05 * y + m.m09 * z) * rhw;
out.z = (m.m02 * x + m.m06 * y + m.m10 * z) * rhw;
return out;
}
/**
* @en Vector and third order matrix multiplication
* @zh 向量与三维矩阵乘法
*/
public static transformMat3<Out extends IVec3Like> (out: Out, a: IVec3, m: IMat3) {
const x = a.x;
const y = a.y;
const z = a.z;
out.x = x * m.m00 + y * m.m03 + z * m.m06;
out.y = x * m.m01 + y * m.m04 + z * m.m07;
out.z = x * m.m02 + y * m.m05 + z * m.m08;
return out;
}
/**
* @en Affine transformation vector
* @zh 向量仿射变换
*/
public static transformAffine<Out extends IVec3Like> (out: Out, v: IVec3, m: IMat4) {
const x = v.x;
const y = v.y;
const z = v.z;
out.x = m.m00 * x + m.m04 * y + m.m08 * z + m.m12;
out.y = m.m01 * x + m.m05 * y + m.m09 * z + m.m13;
out.x = m.m02 * x + m.m06 * y + m.m10 * z + m.m14;
return out;
}
/**
* @en Vector quaternion multiplication
* @zh 向量四元数乘法
*/
public static transformQuat<Out extends IVec3Like> (out: Out, a: IVec3, q: IQuat) {
// benchmarks: http://jsperf.com/quaternion-transform-Vec3-implementations
// calculate quat * vec
const ix = q.w * a.x + q.y * a.z - q.z * a.y;
const iy = q.w * a.y + q.z * a.x - q.x * a.z;
const iz = q.w * a.z + q.x * a.y - q.y * a.x;
const iw = -q.x * a.x - q.y * a.y - q.z * a.z;
// calculate result * inverse quat
out.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;
out.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;
out.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;
return out;
}
/**
* @en Transforms the current vector with given scale, rotation and translation in order
* @zh 以缩放 -> 旋转 -> 平移顺序变换向量
*/
public static transformRTS<Out extends IVec3Like> (out: Out, a: IVec3, r: IQuat, t: IVec3, s: IVec3) {
const x = a.x * s.x;
const y = a.y * s.y;
const z = a.z * s.z;
const ix = r.w * x + r.y * z - r.z * y;
const iy = r.w * y + r.z * x - r.x * z;
const iz = r.w * z + r.x * y - r.y * x;
const iw = -r.x * x - r.y * y - r.z * z;
out.x = ix * r.w + iw * -r.x + iy * -r.z - iz * -r.y + t.x;
out.y = iy * r.w + iw * -r.y + iz * -r.x - ix * -r.z + t.y;
out.z = iz * r.w + iw * -r.z + ix * -r.y - iy * -r.x + t.z;
return out;
}
/**
* @en Transforms the current vector with given scale, rotation and translation in reverse order
* @zh 以平移 -> 旋转 -> 缩放顺序逆变换向量
*/
public static transformInverseRTS<Out extends IVec3Like> (out: Out, a: IVec3, r: IQuat, t: IVec3, s: IVec3) {
const x = a.x - t.x;
const y = a.y - t.y;
const z = a.z - t.z;
const ix = r.w * x - r.y * z + r.z * y;
const iy = r.w * y - r.z * x + r.x * z;
const iz = r.w * z - r.x * y + r.y * x;
const iw = r.x * x + r.y * y + r.z * z;
out.x = (ix * r.w + iw * r.x + iy * r.z - iz * r.y) / s.x;
out.y = (iy * r.w + iw * r.y + iz * r.x - ix * r.z) / s.y;
out.z = (iz * r.w + iw * r.z + ix * r.y - iy * r.x) / s.z;
return out;
}
/**
* @en Rotates the vector with specified angle around X axis
* @zh 绕 X 轴旋转向量指定弧度
* @param v rotation vector
* @param o center of rotation
* @param a radius of rotation
*/
public static rotateX<Out extends IVec3Like> (out: Out, v: IVec3, o: IVec3, a: number) {
// Translate point to the origin
const x = v.x - o.x;
const y = v.y - o.y;
const z = v.z - o.z;
// perform rotation
const cos = Math.cos(a);
const sin = Math.sin(a);
const rx = x;
const ry = y * cos - z * sin;
const rz = y * sin + z * cos;
// translate to correct position
out.x = rx + o.x;
out.y = ry + o.y;
out.z = rz + o.z;
return out;
}
/**
* @en Rotates the vector with specified angle around Y axis
* @zh 绕 Y 轴旋转向量指定弧度
* @param v rotation vector
* @param o center of rotation
* @param a radius of rotation
*/
public static rotateY<Out extends IVec3Like> (out: Out, v: IVec3, o: IVec3, a: number) {
// Translate point to the origin
const x = v.x - o.x;
const y = v.y - o.y;
const z = v.z - o.z;
// perform rotation
const cos = Math.cos(a);
const sin = Math.sin(a);
const rx = z * sin + x * cos;
const ry = y;
const rz = z * cos - x * sin;
// translate to correct position
out.x = rx + o.x;
out.y = ry + o.y;
out.z = rz + o.z;
return out;
}
/**
* @en Rotates the vector with specified angle around Z axis
* @zh 绕 Z 轴旋转向量指定弧度
* @param v rotation vector
* @param o center of rotation
* @param a radius of rotation
*/
public static rotateZ<Out extends IVec3Like> (out: Out, v: IVec3, o: IVec3, a: number) {
// Translate point to the origin
const x = v.x - o.x;
const y = v.y - o.y;
const z = v.z - o.z;
// perform rotation
const cos = Math.cos(a);
const sin = Math.sin(a);
const rx = x * cos - y * sin;
const ry = x * sin + y * cos;
const rz = z;
// translate to correct position
out.x = rx + o.x;
out.y = ry + o.y;
out.z = rz + o.z;
return out;
}
/**
* @en Converts the given vector to an array
* @zh 向量转数组
* @param ofs Array Start Offset
*/
public static toArray <Out extends IWritableArrayLike<number>> (out: Out, v: IVec3, ofs = 0) {
out[ofs + 0] = v.x;
out[ofs + 1] = v.y;
out[ofs + 2] = v.z;
return out;
}
/**
* @en Converts the given array to a vector
* @zh 数组转向量
* @param ofs Array Start Offset
*/
public static fromArray <Out extends IVec3Like> (out: Out, arr: IWritableArrayLike<number>, ofs = 0) {
out.x = arr[ofs + 0];
out.y = arr[ofs + 1];
out.z = arr[ofs + 2];
return out;
}
/**
* @en Check the equality of the two given vectors
* @zh 向量等价判断
*/
public static strictEquals (a: IVec3, b: IVec3) {
return a.x === b.x && a.y === b.y && a.z === b.z;
}
/**
* @en Check whether the two given vectors are approximately equivalent
* @zh 排除浮点数误差的向量近似等价判断
*/
public static equals (a: IVec3, b: IVec3, epsilon = EPSILON) {
const { x: a0, y: a1, z: a2 } = a;
const { x: b0, y: b1, z: b2 } = b;
return (
Math.abs(a0 - b0)
<= epsilon * Math.max(1.0, Math.abs(a0), Math.abs(b0))
&& Math.abs(a1 - b1)
<= epsilon * Math.max(1.0, Math.abs(a1), Math.abs(b1))
&& Math.abs(a2 - b2)
<= epsilon * Math.max(1.0, Math.abs(a2), Math.abs(b2))
);
}
/**
* @en Calculates the radian angle between two vectors
* @zh 求两向量夹角弧度
*/
public static angle (a: IVec3, b: IVec3) {
Vec3.normalize(v3_1, a);
Vec3.normalize(v3_2, b);
const cosine = Vec3.dot(v3_1, v3_2);
if (cosine > 1.0) {
return 0;
}
if (cosine < -1.0) {
return Math.PI;
}
return Math.acos(cosine);
}
/**
* @en Calculates the projection vector on the specified plane
* @zh 计算向量在指定平面上的投影
* @param a projection vector
* @param n the normal line of specified plane
*/
public static projectOnPlane<Out extends IVec3Like> (out: Out, a: IVec3, n: IVec3) {
return Vec3.subtract(out, a, Vec3.project(out, a, n));
}
/**
* @en Calculates the projection on the specified vector
* @zh 计算向量在指定向量上的投影
* @param a projection vector
* @param n target vector
*/
public static project<Out extends IVec3Like> (out: Out, a: IVec3, b: IVec3) {
const sqrLen = Vec3.lengthSqr(b);
if (sqrLen < 0.000001) {
return Vec3.set(out, 0, 0, 0);
} else {
return Vec3.multiplyScalar(out, b, Vec3.dot(a, b) / sqrLen);
}
}
/**
* @en x component.
* @zh x 分量。
*/
public get x (): number {
return this._array[0];
}
public set x (x: number) {
this._array[0] = x;
}
/**
* @en y component.
* @zh y 分量。
*/
public get y (): number {
return this._array[1];
}
public set y (y: number) {
this._array[1] = y;
}
/**
* @en z component.
* @zh z 分量。
*/
public get z (): number {
return this._array[2];
}
public set z (z: number) {
this._array[2] = z;
}
constructor (x: Vec3 | Readonly<Vec3> | FloatArray);
constructor (x?: number, y?: number, z?: number);
constructor (x?: number | Vec3 | Readonly<Vec3> | FloatArray, y?: number, z?: number) {
super();
if (x && typeof x === 'object') {
if (ArrayBuffer.isView(x)) {
this._array = x;
this._array.fill(0);
} else {
const v = x.array;
this._array = MathBase.createFloatArray(3);
this._array[0] = v[0];
this._array[1] = v[1];
this._array[2] = v[2];
}
} else {
this._array = MathBase.createFloatArray(3);
this._array[0] = x as number || 0;
this._array[1] = y || 0;
this._array[2] = z || 0;
}
}
/**
* @en clone a Vec3 value
* @zh 克隆当前向量。
*/
public clone () {
return new Vec3(this._array[0], this._array[1], this._array[2]);
}
/**
* @en Set the current vector value with the given vector.
* @zh 设置当前向量使其与指定向量相等。
* @param other Specified vector
* @returns `this`
*/
public set (other: Vec3 | Readonly<Vec3>);
/**
* @en Set the value of each component of the current vector.
* @zh 设置当前向量的具体分量值。
* @param x x value
* @param y y value
* @param z z value
* @returns `this`
*/
public set (x?: number, y?: number, z?: number);
public set (x?: number | Vec3 | Readonly<Vec3>, y?: number, z?: number) {
if (x && typeof x === 'object') {
this._array[0] = x.x;
this._array[1] = x.y;
this._array[2] = x.z;
} else {
this._array[0] = x as number || 0;
this._array[1] = y || 0;
this._array[2] = z || 0;
}
return this;
}
/**
* @en Check whether the vector approximately equals another one.
* @zh 判断当前向量是否在误差范围内与指定向量相等。
* @param other Specified vector
* @param epsilon The error allowed. It`s should be a non-negative number.
* @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`.
*/
public equals (other: Vec3 | Readonly<Vec3>, epsilon = EPSILON) {
const v = other.array;
return (
Math.abs(this._array[0] - v[0])
<= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(v[0]))
&& Math.abs(this._array[1] - v[1])
<= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(v[1]))
&& Math.abs(this._array[2] - v[2])
<= epsilon * Math.max(1.0, Math.abs(this._array[2]), Math.abs(v[2]))
);
}
/**
* @en Check whether the vector approximately equals another one.
* @zh 判断当前向量是否在误差范围内与指定分量的向量相等。
* @param x The x value of specified vector
* @param y The y value of specified vector
* @param z The z value of specified vector
* @param epsilon The error allowed. It`s should be a non-negative number.
* @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`.
*/
public equals3f (x: number, y: number, z: number, epsilon = EPSILON) {
return (
Math.abs(this._array[0] - x)
<= epsilon * Math.max(1.0, Math.abs(this._array[0]), Math.abs(x))
&& Math.abs(this._array[1] - y)
<= epsilon * Math.max(1.0, Math.abs(this._array[1]), Math.abs(y))
&& Math.abs(this._array[2] - z)
<= epsilon * Math.max(1.0, Math.abs(this._array[2]), Math.abs(z))
);
}
/**
* @en Check whether the current vector strictly equals another Vec3.
* @zh 判断当前向量是否与指定向量相等。
* @param other specified vector
* @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`.
*/
public strictEquals (other: Vec3 | Readonly<Vec3>) {
const v = other.array;
return this._array[0] === v[0] && this._array[1] === v[1] && this._array[2] === v[2];
}
/**
* @en Check whether the current vector strictly equals another Vec3.
* @zh 判断当前向量是否与指定分量的向量相等。
* @param x The x value of specified vector
* @param y The y value of specified vector
* @param z The z value of specified vector
* @returns Returns `true` when the components of both vectors are equal within the specified range of error; otherwise it returns `false`.
*/
public strictEquals3f (x: number, y: number, z: number) {
return this._array[0] === x && this._array[1] === y && this._array[2] === z;
}
/**
* @en Transform to string with vector information.
* @zh 返回当前向量的字符串表示。
* @returns The string with vector information
*/
public toString () {
return `(${this._array[0].toFixed(2)}, ${this._array[1].toFixed(2)}, ${this._array[2].toFixed(2)})`;
}
/**
* @en Calculate linear interpolation result between this vector and another one with given ratio.
* @zh 根据指定的插值比率,从当前向量到目标向量之间做插值。
* @param to Target vector
* @param ratio The interpolation coefficient.The range is [0,1].
*/
public lerp (to: Vec3 | Readonly<Vec3>, ratio: number) {
this._array[0] += ratio * (to.x - this._array[0]);
this._array[1] += ratio * (to.y - this._array[1]);
this._array[2] += ratio * (to.z - this._array[2]);
return this;
}
/**
* @en Adds the current vector with another one and return this
* @zh 向量加法。将当前向量与指定向量的相加
* @param other specified vector
*/
public add (other: Vec3 | Readonly<Vec3>) {
const v = other.array;
this._array[0] += v[0];
this._array[1] += v[1];
this._array[2] += v[2];
return this;
}
/**
* @en Adds the current vector with another one and return this
* @zh 向量加法。将当前向量与指定分量的向量相加
* @param x The x value of specified vector
* @param y The y value of specified vector
* @param z The z value of specified vector
*/
public add3f (x: number, y: number, z: number) {
this._array[0] += x;
this._array[1] += y;
this._array[2] += z;
return this;
}
/**
* @en Subtracts one vector from this, and returns this.
* @zh 向量减法。将当前向量减去指定向量的结果。
* @param other specified vector
*/
public subtract (other: Vec3 | Readonly<Vec3>) {
const v = other.array;
this._array[0] -= v[0];
this._array[1] -= v[1];
this._array[2] -= v[2];
return this;
}
/**
* @en Subtracts one vector from this, and returns this.
* @zh 向量减法。将当前向量减去指定分量的向量
* @param x The x value of specified vector
* @param y The y value of specified vector
* @param z The z value of specified vector
*/
public subtract3f (x: number, y: number, z: number) {
this._array[0] -= x;
this._array[1] -= y;
this._array[2] -= z;
return this;
}
/**
* @en Multiplies the current vector with a number, and returns this.
* @zh 向量数乘。将当前向量数乘指定标量
* @param scalar scalar number
*/
public multiplyScalar (scalar: number) {
if (typeof scalar === 'object') { console.warn('should use Vec3.multiply for vector * vector operation'); }
this._array[0] *= scalar;
this._array[1] *= scalar;
this._array[2] *= scalar;
return this;
}
/**
* @en Multiplies the current vector with another one and return this
* @zh 向量乘法。将当前向量乘以与指定向量的结果赋值给当前向量。
* @param other specified vector
*/
public multiply (other: Vec3 | Readonly<Vec3>) {
if (typeof other !== 'object') { console.warn('should use Vec3.scale for vector * scalar operation'); }
const v = other.array;
this._array[0] *= v[0];
this._array[1] *= v[1];
this._array[2] *= v[2];
return this;
}
/**
* @en Multiplies the current vector with another one and return this
* @zh 向量乘法。将当前向量与指定分量的向量相乘的结果赋值给当前向量。
* @param x The x value of specified vector
* @param y The y value of specified vector
* @param z The z value of specified vector
*/
public multiply3f (x: number, y: number, z: number) {
this._array[0] *= x;
this._array[1] *= y;
this._array[2] *= z;
return this;
}
/**
* @en Element-wisely divides this vector with another one, and return this.
* @zh 向量逐元素相除。将当前向量与指定分量的向量相除的结果赋值给当前向量。
* @param other specified vector
*/
public divide (other: Vec3 | Readonly<Vec3>) {
const v = other.array;
this._array[0] /= v[0];
this._array[1] /= v[1];
this._array[2] /= v[2];
return this;
}
/**
* @en Element-wisely divides this vector with another one, and return this.
* @zh 向量逐元素相除。将当前向量与指定分量的向量相除的结果赋值给当前向量。
* @param x The x value of specified vector
* @param y The y value of specified vector
* @param z The z value of specified vector
*/
public divide3f (x: number, y: number, z: number) {
this._array[0] /= x;
this._array[1] /= y;
this._array[2] /= z;
return this;
}
/**
* @en Sets each component of this vector with its negative value
* @zh 将当前向量的各个分量取反
*/
public negative () {
this._array[0] = -this._array[0];
this._array[1] = -this._array[1];
this._array[2] = -this._array[2];
return this;
}
/**
* @en Clamp the vector between minInclusive and maxInclusive.
* @zh 设置当前向量的值,使其各个分量都处于指定的范围内。
* @param minInclusive Minimum value allowed
* @param maxInclusive Maximum value allowed
* @returns `this`
*/
public clampf (minInclusive: Vec3 | Readonly<Vec3>, maxInclusive: Vec3 | Readonly<Vec3>) {
const min = minInclusive.array;
const max = maxInclusive.array;
this._array[0] = clamp(this._array[0], min[0], max[0]);
this._array[1] = clamp(this._array[1], min[1], max[1]);
this._array[2] = clamp(this._array[2], min[2], max[2]);
return this;
}
/**
* @en Calculates the dot product with another vector
* @zh 向量点乘。
* @param other specified vector
* @returns The result of calculates the dot product with another vector
*/
public dot (other: Vec3 | Readonly<Vec3>) {
const v = other.array;
return this._array[0] * v[0] + this._array[1] * v[1] + this._array[2] * v[2];
}
/**
* @en Calculates the cross product with another vector.
* @zh 向量叉乘。将当前向量左叉乘指定向量
* @param other specified vector
*/
public cross (other: Vec3 | Readonly<Vec3>) {
const ax = this._array[0];
const ay = this._array[1];
const az = this._array[2];
const bx = other.array[0];
const by = other.array[1];
const bz = other.array[2];
this._array[0] = ay * bz - az * by;
this._array[1] = az * bx - ax * bz;
this._array[2] = ax * by - ay * bx;
return this;
}
/**
* @en Returns the length of this vector.
* @zh 计算向量的长度(模)。
* @returns Length of vector
*/
public length () {
return Math.sqrt(this._array[0] * this._array[0] + this._array[1] * this._array[1] + this._array[2] * this._array[2]);
}
/**
* @en Returns the squared length of this vector.
* @zh 计算向量长度(模)的平方。
* @returns the squared length of this vector
*/
public lengthSqr () {
return this._array[0] * this._array[0] + this._array[1] * this._array[1] + this._array[2] * this._array[2];
}
/**
* @en Normalize the current vector.
* @zh 将当前向量归一化
*/
public normalize () {
const x = this._array[0];
const y = this._array[1];
const z = this._array[2];
let len = x * x + y * y + z * z;
if (len > 0) {
len = 1 / Math.sqrt(len);
this._array[0] = x * len;
this._array[1] = y * len;
this._array[2] = z * len;
}
return this;
}
/**
* @en Transforms the vec3 with a mat4. 4th vector component is implicitly '1'
* @zh 将当前向量视为 w 分量为 1 的四维向量,应用四维矩阵变换到当前矩阵
* @param matrix matrix to transform with
*/
public transformMat4 (matrix: Mat4 | Readonly<Mat4>) {
const x = this._array[0];
const y = this._array[1];
const z = this._array[2];
const v = matrix.array;
let rhw = v[3] * x + v[7] * y + v[11] * z + v[15];
rhw = rhw ? 1 / rhw : 1;
this._array[0] = (v[0] * x + v[4] * y + v[8] * z + v[12]) * rhw;
this._array[1] = (v[1] * x + v[5] * y + v[9] * z + v[13]) * rhw;
this._array[2] = (v[2] * x + v[6] * y + v[10] * z + v[14]) * rhw;
return this;
}
}
const v3_1 = new Vec3();
const v3_2 = new Vec3();
enumerableProps(Vec3.prototype, ['x', 'y', 'z']);
CCClass.fastDefine('cc.Vec3', Vec3, { x: 0, y: 0, z: 0 });
legacyCC.Vec3 = Vec3;
export function v3 (other: Vec3): Vec3;
export function v3 (x?: number, y?: number, z?: number): Vec3;
export function v3 (x?: number | Vec3, y?: number, z?: number) {
return new Vec3(x as any, y, z);
}
legacyCC.v3 = v3;