I have created a class to determine the angle of a point on the earth, relative to the earths center and the sun, given a tilt, and time. Time is a float number of days - the fraction is the time of day from 0 to 1.
import { Object3D, MathUtils, Scene, Vector3 } from 'three';
import { SimTimeCursor } from '../../classes/types.sim';
import { angle } from '../angle';
export class SunlightCalculator {
private readonly daysInYear: number;
private readonly minutesInDay: number;
private readonly maxDeclination: number; // in radians
private readonly earth: Object3D;
private readonly earthRotationFrame: Object3D;
private readonly earthTiltFrame: Object3D;
private readonly sun: Object3D;
private readonly scene: Scene;
private readonly pointObject: Object3D;
constructor(
public name: string,
cursor: SimTimeCursor,
maxDeclinationDeg: number,
private earthOrbitDistance: number = 1.496e8
) {
this.daysInYear = cursor.cal.daysInYear;
this.minutesInDay = cursor.cal.hoursInDay * 60;
this.maxDeclination = MathUtils.degToRad(maxDeclinationDeg);
this.scene = new Scene();
this.sun = new Object3D();
this.earth = new Object3D();
this.earthRotationFrame = new Object3D();
this.earthTiltFrame = new Object3D();
this.earthTiltFrame.rotation.x = this.maxDeclination;
this.pointObject = new Object3D();
this.earth.add(this.pointObject);
this.earthTiltFrame.add(this.earth);
this.earthRotationFrame.add(this.earthTiltFrame);
this.earth.position.set(this.earthOrbitDistance, 0, 0);
this.sun.add(this.earthRotationFrame);
this.scene.add(this.sun);
[
this.earth,
this.sun,
this.earthTiltFrame,
this.earthRotationFrame,
this.pointObject,
].forEach((o) => (o.matrixAutoUpdate = true));
}
public updateCelestialPositions(time: number): void {
const minuteOfDay = this.minutesInDay * (time % 1);
const yrot = (time * (2 * Math.PI)) / this.daysInYear;
this.sun.rotation.y = yrot;
this.earthRotationFrame.rotation.y = -this.sun.rotation.y;
this.scene.updateMatrixWorld(true);
this.earth.rotation.y = (minuteOfDay / this.minutesInDay) * (2 * Math.PI);
}
public computeSunAngle(time: number, point: Vector3): number {
this.updateCelestialPositions(time);
this.pointObject.position.copy(point);
const earthCenter = new Vector3();
this.earth.getWorldPosition(earthCenter);
const pointWorld = new Vector3();
this.pointObject.getWorldPosition(pointWorld);
const sunVector = new Vector3();
this.sun.getWorldPosition(sunVector);
const vectorToSun = new Vector3()
.subVectors(sunVector, earthCenter)
.normalize();
const vectorToPoint = new Vector3()
.subVectors(pointWorld, earthCenter)
.normalize();
return vectorToSun.angleTo(vectorToPoint);
}
}
The problem is that it just doesn't seem to be responsive to the tilt of the earth; tests reflect the same result regardless of the construtors' tilt angle. Is there a flaw in how I am chaining three js objects?
I have created a class to determine the angle of a point on the earth, relative to the earths center and the sun, given a tilt, and time. Time is a float number of days - the fraction is the time of day from 0 to 1.
import { Object3D, MathUtils, Scene, Vector3 } from 'three';
import { SimTimeCursor } from '../../classes/types.sim';
import { angle } from '../angle';
export class SunlightCalculator {
private readonly daysInYear: number;
private readonly minutesInDay: number;
private readonly maxDeclination: number; // in radians
private readonly earth: Object3D;
private readonly earthRotationFrame: Object3D;
private readonly earthTiltFrame: Object3D;
private readonly sun: Object3D;
private readonly scene: Scene;
private readonly pointObject: Object3D;
constructor(
public name: string,
cursor: SimTimeCursor,
maxDeclinationDeg: number,
private earthOrbitDistance: number = 1.496e8
) {
this.daysInYear = cursor.cal.daysInYear;
this.minutesInDay = cursor.cal.hoursInDay * 60;
this.maxDeclination = MathUtils.degToRad(maxDeclinationDeg);
this.scene = new Scene();
this.sun = new Object3D();
this.earth = new Object3D();
this.earthRotationFrame = new Object3D();
this.earthTiltFrame = new Object3D();
this.earthTiltFrame.rotation.x = this.maxDeclination;
this.pointObject = new Object3D();
this.earth.add(this.pointObject);
this.earthTiltFrame.add(this.earth);
this.earthRotationFrame.add(this.earthTiltFrame);
this.earth.position.set(this.earthOrbitDistance, 0, 0);
this.sun.add(this.earthRotationFrame);
this.scene.add(this.sun);
[
this.earth,
this.sun,
this.earthTiltFrame,
this.earthRotationFrame,
this.pointObject,
].forEach((o) => (o.matrixAutoUpdate = true));
}
public updateCelestialPositions(time: number): void {
const minuteOfDay = this.minutesInDay * (time % 1);
const yrot = (time * (2 * Math.PI)) / this.daysInYear;
this.sun.rotation.y = yrot;
this.earthRotationFrame.rotation.y = -this.sun.rotation.y;
this.scene.updateMatrixWorld(true);
this.earth.rotation.y = (minuteOfDay / this.minutesInDay) * (2 * Math.PI);
}
public computeSunAngle(time: number, point: Vector3): number {
this.updateCelestialPositions(time);
this.pointObject.position.copy(point);
const earthCenter = new Vector3();
this.earth.getWorldPosition(earthCenter);
const pointWorld = new Vector3();
this.pointObject.getWorldPosition(pointWorld);
const sunVector = new Vector3();
this.sun.getWorldPosition(sunVector);
const vectorToSun = new Vector3()
.subVectors(sunVector, earthCenter)
.normalize();
const vectorToPoint = new Vector3()
.subVectors(pointWorld, earthCenter)
.normalize();
return vectorToSun.angleTo(vectorToPoint);
}
}
The problem is that it just doesn't seem to be responsive to the tilt of the earth; tests reflect the same result regardless of the construtors' tilt angle. Is there a flaw in how I am chaining three js objects?
Share Improve this question asked Mar 14 at 23:46 Dave EdelhartDave Edelhart 1,1011 gold badge9 silver badges14 bronze badges1 Answer
Reset to default 0Looks that time calculation of minuteOfDay isn't correct
time % 1 always = 0;
Probably should be:
// const minuteOfDay = this.minutesInDay * (time % 1);
const minuteOfDay = time % this.minutesInDay;
Code sandbox:
https://codesandbox.io/p/sandbox/yxmnd7