基于牛顿引力的物理模拟器:正质量互斥、负质量互吸问题求助
牛顿引力模拟器异常:正质量排斥、负质量吸引问题排查
我基于牛顿引力方程开发了一款物理模拟器,用于模拟物体间的引力作用。目前遇到异常:仅当物体设置负质量(如mass: -10000000)时才会互相吸引,设置正质量时反而互相排斥。已排除引力常数G过小的可能,以下是物理引擎physicsStepper类、物理对象particle类的代码,Vector2类取自three.js,请求排查问题原因。
physicsStepper类代码
class physicsStepper { /** * Create a physicsStepper class * @param {Object} configs - Configs for the physics stepper. (Optional) * @param {number} configs.G - The Gravitational Constant. * @param {boolean} configs.collisions - Whether or not to detect collisions. * @param {number} configs.simulationBounds - The size of the simulation used to create a Quadtree. * @param {number} configs.subdivisions - number of nodes for the Quadtree. */ constructor(configs = {}) { //default configs Object.assign(this, { G: 6.6743 * Math.pow(10, -11), collisions: false, dimensions: 2, useGrid: false, simSize: { height: 1600, width: 1600, }, }); //apply changes Object.assign(this, configs); //setup Grid if (this.useGrid) this.grid = new grid(); } /** * Circle vs circle collider * @param {Object} a - A particle object with radius * @param {Object} b - A particle object with radius * @param {number} r - The distance between the two objects * @returns {boolean} - Whether a collision happened or not */ collider(a, b, r) { if (r < a.radius + b.radius) return true; else return false; } /** * Apply force to an entity * @param {Object} entity - a physics object * @param {Object} force - a force vector2 */ applyForce(entity, force) { force.divideScalar(entity.mass); entity.acceleration.add(force); } /** * Calculate the attraction between two objects * @param {Object} a - A particle object with radius * @param {Object} b - A particle object with radius * @returns {Object} data.r - the distance between the two entities * @returns {Object} data.force - the force of attraction between the two entities */ calcAttraction(a, b) { const { G } = this; const force = new Vector2(); force.subVectors(a.position, b.position); const r = $.distance(a, b); force.normalize(); const strength = ((G * a.mass * b.mass) / r) * r; force.multiplyScalar(strength); return { r, force }; } /** * Translate the entity to its new position by using it's velocity vector2 * @param {Object} entity - A physics object */ translatePositions(entity) { entity.velocity.add(entity.acceleration); entity.position.add(entity.velocity); entity.acceleration.multiplyScalar(0); } /** * Calculates and updates all physics objects * @param {Object[]} scene - The scene containing the physics objects (required) * @param {Number} delta - The delta time (required) */ step(scene, dt) { for (let [i, a] of scene.children.entries()) { if (!a.physics) continue; for (let b of scene.children) { if (!b.physics) continue; if (a.sn === b.sn) continue; const { r, force } = this.calcAttraction(a, b); if (this.collisions && this.collider(a, b, r)) { a.velocity.multiplyScalar(0.999); b.velocity.multiplyScalar(0.999); } force.multiplyScalar(dt); this.applyForce(a, force); } this.translatePositions(a); } } }
particle类代码
/** * Create a particle object with rendering and physics properties * @param {Object} configs - configs for the particle * */ export class particle { constructor(configs = {}) { //default configs Object.assign(this, { type: "particle", // physics physics: true, position: new Vector2(), velocity: new Vector2(), acceleration: new Vector2(), force: new Vector2(), mass: 10, //visual radius: 10, color: "#ffffff", }); //apply changes Object.assign(this, configs); //used by the grid iterator this.size = new Vector2(this.radius, this.radius); } dispose() { this.isWaste = true; } }
问题根源及修复方案
1. 力的方向完全错误
calcAttraction方法中,force.subVectors(a.position, b.position)计算的是从b指向a的向量,这会让a受到远离b的力(排斥)。而引力的正确方向应该是从a指向b(让a向b移动)。
2. 引力强度公式错误
牛顿引力公式为 F = G*(m1*m2)/r²,但代码中写成了 ((G * a.mass * b.mass) / r) * r,这等价于 G*m1*m2,完全丢失了距离平方的衰减特性,导致力的大小异常。
修复后的关键代码修改
修正calcAttraction方法
calcAttraction(a, b) { const { G } = this; const force = new Vector2(); // 修正方向:计算从a指向b的向量,实现引力吸引 force.subVectors(b.position, a.position); const r = $.distance(a, b); // 避免物体重合时除以0 if (r === 0) return { r: 0, force: new Vector2(0, 0) }; force.normalize(); // 修正引力强度:使用距离的平方 const strength = (G * a.mass * b.mass) / (r * r); force.multiplyScalar(strength); return { r, force }; }
补充牛顿第三定律的双向力(可选但重要)
当前代码只对a施加力,不符合物理规律,需给b施加大小相等、方向相反的力:
// 在step方法的力应用部分修改 const { r, force } = this.calcAttraction(a, b); if (this.collisions && this.collider(a, b, r)) { a.velocity.multiplyScalar(0.999); b.velocity.multiplyScalar(0.999); } const forceForB = force.clone().negate(); // 生成反向力 force.multiplyScalar(dt); forceForB.multiplyScalar(dt); this.applyForce(a, force); this.applyForce(b, forceForB); // 给b施加反向力
额外说明
- 负质量时表现正常的原因:质量符号反转会抵消方向错误,把排斥力变成吸引力。
- 修复平方反比定律后,力的大小会随距离正常衰减,避免物体因受力过大瞬间飞出。
内容的提问来源于stack exchange,提问作者Kiron Dey
相关产品推荐
相关产品推荐

