Brownian behavior add limit by range
This commit is contained in:
parent
4ade5d4bc3
commit
904de02140
@ -7,7 +7,9 @@ type IBrownianBehaviorParameter = {
|
||||
maxFrequency: "number",
|
||||
minFrequency: "number",
|
||||
maxStrength: "number",
|
||||
minStrength: "number"
|
||||
minStrength: "number",
|
||||
dirLimit: "boolean",
|
||||
angle: "number"
|
||||
}
|
||||
|
||||
type IBrownianBehaviorEvent = {}
|
||||
@ -28,9 +30,88 @@ class Brownian extends Behavior<IBrownianBehaviorParameter, IBrownianBehaviorEve
|
||||
maxFrequency: { type: "number", name: "$Max.Frequency", defaultValue: 5, numberStep: .1, numberMin: 0 },
|
||||
minFrequency: { type: "number", name: "$Min.Frequency", defaultValue: 0, numberStep: .1, numberMin: 0 },
|
||||
maxStrength: { type: "number", name: "$Max.Strength", defaultValue: 10, numberStep: .01, numberMin: 0 },
|
||||
minStrength: { type: "number", name: "$Min.Strength", defaultValue: 0, numberStep: .01, numberMin: 0 }
|
||||
minStrength: { type: "number", name: "$Min.Strength", defaultValue: 0, numberStep: .01, numberMin: 0 },
|
||||
dirLimit: { type: "boolean", name: "$Direction.Limit", defaultValue: false },
|
||||
angle: {
|
||||
type: "number", name: "$Angle", defaultValue: 180, numberStep: 5,
|
||||
numberMin: 0, numberMax: 360, condition: { key: "dirLimit", value: true }
|
||||
}
|
||||
};
|
||||
|
||||
private randomFocus360(): number[] {
|
||||
let randomVec = [
|
||||
Math.random() * 2 - 1,
|
||||
Math.random() * 2 - 1,
|
||||
Math.random() * 2 - 1
|
||||
];
|
||||
|
||||
let randomVecLen = (randomVec[0] ** 2 + randomVec[1] ** 2 + randomVec[2] ** 2) ** 0.5;
|
||||
return [randomVec[0] / randomVecLen, randomVec[1] / randomVecLen, randomVec[2] / randomVecLen];
|
||||
}
|
||||
|
||||
private rotateWithVec(vec: number[], r: number[], ang: number) {
|
||||
|
||||
const cos = Math.cos(ang); const sin = Math.sin(ang);
|
||||
const a1 = r[0] ?? 0; const a2 = r[1] ?? 0; const a3 = r[2] ?? 0;
|
||||
|
||||
return [
|
||||
(cos + (1 - cos) * a1 * a1) * (vec[0] ?? 0) +
|
||||
((1 - cos) * a1 * a2 - sin * a3) * (vec[1] ?? 0) +
|
||||
((1 - cos) * a1 * a3 + sin * a2) * (vec[2] ?? 0),
|
||||
|
||||
((1 - cos) * a1 * a2 + sin * a3) * (vec[0] ?? 0) +
|
||||
(cos + (1 - cos) * a2 * a2) * (vec[1] ?? 0) +
|
||||
((1 - cos) * a2 * a3 - sin * a1) * (vec[2] ?? 0),
|
||||
|
||||
((1 - cos) * a1 * a3 - sin * a2) * (vec[0] ?? 0) +
|
||||
((1 - cos) * a2 * a3 + sin * a1) * (vec[1] ?? 0) +
|
||||
(cos + (1 - cos) * a3 * a3) * (vec[2] ?? 0)
|
||||
]
|
||||
}
|
||||
private angle2Vector(v1: number[], v2: number[]): number {
|
||||
return Math.acos(
|
||||
(v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]) /
|
||||
(
|
||||
(v1[0] ** 2 + v1[1] ** 2 + v1[2] ** 2) ** 0.5 *
|
||||
(v2[0] ** 2 + v2[1] ** 2 + v2[2] ** 2) ** 0.5
|
||||
)
|
||||
) * 180 / Math.PI;
|
||||
}
|
||||
|
||||
private randomFocusRange(dir: number[], angle: number): number[] {
|
||||
|
||||
// 计算 X-Z 投影
|
||||
let pxz = [dir[0] ?? 0, 0, dir[2] ?? 0];
|
||||
|
||||
// 通过叉乘计算垂直向量
|
||||
let dxz: number[];
|
||||
|
||||
// 如果投影向量没有长度,使用单位向量
|
||||
if (pxz[0] ** 2 + pxz[2] ** 2 === 0) {
|
||||
dxz = [0, 0, 1];
|
||||
}
|
||||
|
||||
// 通过叉乘计算垂直轴线
|
||||
else {
|
||||
dxz = [
|
||||
dir[1] * pxz[2] - pxz[1] * dir[2],
|
||||
dir[2] * pxz[0] - pxz[2] * dir[0],
|
||||
dir[0] * pxz[1] - pxz[0] * dir[1]
|
||||
];
|
||||
|
||||
let lenDxz = (dxz[0] ** 2 + dxz[1] ** 2 + dxz[2] ** 2) ** 0.5;
|
||||
dxz = [dxz[0] / lenDxz, dxz[1] / lenDxz, dxz[2] / lenDxz];
|
||||
}
|
||||
|
||||
// 航偏角 360 随机旋转
|
||||
let randomH = this.rotateWithVec(dxz, dir, Math.random() * Math.PI * 2);
|
||||
|
||||
// 俯仰角 180 * R 随机旋转
|
||||
let randomP = this.rotateWithVec(dir, randomH, (Math.random() - 0.5) * 2 * angle * Math.PI / 180);
|
||||
|
||||
return randomP;
|
||||
}
|
||||
|
||||
public effect = (individual: Individual, group: Group, model: Model, t: number): void => {
|
||||
|
||||
const {maxFrequency, minFrequency, maxStrength, minStrength} = this.parameter;
|
||||
@ -41,11 +122,43 @@ class Brownian extends Behavior<IBrownianBehaviorParameter, IBrownianBehaviorEve
|
||||
|
||||
currentTime += t;
|
||||
if (currentTime > nextTime) {
|
||||
|
||||
let randomDir: number[];
|
||||
|
||||
// 开启角度限制
|
||||
if (this.parameter.dirLimit) {
|
||||
|
||||
// 计算当前速度大小
|
||||
const vLen = individual.vectorLength(individual.velocity);
|
||||
|
||||
// 随机旋转算法
|
||||
if (vLen !== 0) {
|
||||
randomDir = this.randomFocusRange(
|
||||
[
|
||||
individual.velocity[0] / vLen,
|
||||
individual.velocity[1] / vLen,
|
||||
individual.velocity[2] / vLen
|
||||
],
|
||||
this.parameter.angle / 2
|
||||
);
|
||||
}
|
||||
|
||||
else {
|
||||
randomDir = this.randomFocus360()
|
||||
}
|
||||
}
|
||||
|
||||
// 随机生成算法
|
||||
else {
|
||||
randomDir = this.randomFocus360()
|
||||
}
|
||||
|
||||
individual.applyForce(
|
||||
minStrength + (Math.random() * 2 - 1) * (maxStrength - minStrength),
|
||||
minStrength + (Math.random() * 2 - 1) * (maxStrength - minStrength),
|
||||
minStrength + (Math.random() * 2 - 1) * (maxStrength - minStrength)
|
||||
minStrength + randomDir[0] * (maxStrength - minStrength),
|
||||
minStrength + randomDir[1] * (maxStrength - minStrength),
|
||||
minStrength + randomDir[2] * (maxStrength - minStrength)
|
||||
);
|
||||
|
||||
nextTime = minFrequency + Math.random() * (maxFrequency - minFrequency);
|
||||
currentTime = 0;
|
||||
}
|
||||
@ -78,7 +191,15 @@ class Brownian extends Behavior<IBrownianBehaviorParameter, IBrownianBehaviorEve
|
||||
"$Min.Strength": {
|
||||
"ZH_CN": "最小强度",
|
||||
"EN_US": "Minimum strength"
|
||||
}
|
||||
},
|
||||
"$Direction.Limit": {
|
||||
"ZH_CN": "开启角度限制",
|
||||
"EN_US": "Enable limit angle"
|
||||
},
|
||||
"$Angle": {
|
||||
"ZH_CN": "限制立体角 (deg)",
|
||||
"EN_US": "Restricted solid angle (deg)"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user