Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/pages/Simulation/components/PlanetMesh.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type React from "react";
import { useEffect, useMemo, useRef } from "react";
import * as THREE from "three";
import type { Planet } from "@/types/planet";
import { calc_gravity_force } from "../utils/gravityUtils";
import { calcGravityForce } from "../utils/gravityUtils";

type PlanetMeshProps = {
planet: Planet;
Expand Down Expand Up @@ -89,6 +89,7 @@ export function PlanetMesh({
}, [planet.id, planetRegistry, planet.mass, planet.radius, ref]);

// 計算用ベクトルをメモリに保持しておく(毎フレームnewしないため)
const force = useMemo(() => new THREE.Vector3(), []);
const forceAccumulator = useMemo(() => new THREE.Vector3(), []);
const myPosVec = useMemo(() => new THREE.Vector3(), []);
const otherPosVec = useMemo(() => new THREE.Vector3(), []);
Expand All @@ -113,13 +114,14 @@ export function PlanetMesh({
const otherMass = otherMesh.userData.mass || 1;
const otherRadius = otherMesh.userData.radius || 0.1;

const force = calc_gravity_force(
calcGravityForce(
myPosVec,
planet.mass,
planet.radius,
otherPosVec,
otherMass,
otherRadius,
force,
);
forceAccumulator.add(force);
}
Expand Down
24 changes: 14 additions & 10 deletions src/pages/Simulation/utils/gravityUtils.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
import * as THREE from "three";
import type * as THREE from "three";

const G = 1;
const softeningFactor = 0.01;

export function calc_gravity_force(
export function calcGravityForce(
targetPos: THREE.Vector3,
targetMass: number,
targetRadius: number,
sourcePos: THREE.Vector3,
sourceMass: number,
sourceRadius: number,
): THREE.Vector3 {
const direction = new THREE.Vector3().subVectors(sourcePos, targetPos);
const distanceSq = direction.lengthSq();
resultVec: THREE.Vector3,
): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

パフォーマンス上の理由(アロケーションを避ける)であれば納得できるのですが、そうでない場合は Vector3 を返す純粋な関数として定義した方が読みやすいかと思います。関数を純粋に保つことで、後々テストも書きやすくなります。React でもその思想が取り入れられてますね。

const EPS = ((targetRadius + sourceRadius) / 2) * softeningFactor;

resultVec.subVectors(sourcePos, targetPos);
const distanceSq = resultVec.lengthSq() + EPS ** 2;
const distance = Math.sqrt(distanceSq);

// 2つの惑星が接触または重なっている場合は、引力を0にする
const minDistance = targetRadius + sourceRadius;
if (distance < minDistance) {
return new THREE.Vector3(0, 0, 0);
// 距離が0の場合、力は0として扱う(ゼロ除算を避ける)
if (distance === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EPS ** 2 を足しているため、distanceSq が0になることはなく、distance が0になることもないと思うので、このチェックは削除して、EPS の計算箇所に「ゼロ除算を避ける」という意図をコメントで説明するのがいいかと思います。

resultVec.set(0, 0, 0);
return;
}

const forceScalar = (G * targetMass * sourceMass) / (distanceSq * distance);
return direction.multiplyScalar(forceScalar);
resultVec.multiplyScalar(forceScalar);
}