I'm trying to build a to scale model of the solar system. I wanted to see if someone could explain to me how the rotation speed works. Here's the important piece:
objects[index].rotation.y += calculateRotationSpeed(value.radius,value.revolution) * delta;
How does the rotation speed relate to actual time? So if you have a speed of 1, is that a movement of 1 px per millisecond? Or if you have a speed of 0.1, is that less that a px a second?
Basically I'm trying to calculate the correct rotation speed for the planets given their radius and amount of hours in a day. So if you were on earth, it would complete 1 rotation in 24 hours. Here's the function that I wrote that's doing the calculation now:
/* In a day */
function calculateRotationSpeed(radius,hrs,delta) {
var cir = findCircumference(radius);
if(delta) {
var d = delta;
} else {
var d = 1;
}
var ms = hrs2ms(hrs) * d;
var pxPerMS = km2px(cir) / ms;
return pxPerMS;
}
I gave it a try and it still seems to be moving too fast. I also need something similar to calculate orbit speeds.
Rotation in Three.JS is measured in radians. For those that are completely unfamiliar with radians (a small excerpt from an old paper of mine):
Like the mathematical constant Pi, a radian (roughly 57.3 degrees) is derived from the relationship between a circle's radius (or diameter) and its circumference. One radian is the angle which will always span an arc on the circumference of a circle which is equal in length to the radius of that same circle (true for any circle, regardless of size). Similarly, Pi is the ratio of circumference over diameter, such that the circumference of the unit circle is precisely Pi. Radians and degrees are not actually true units, in fact angles are in general dimensionless (like percentages and fractions, we do not use actual units to describe them).
However, unlike the degree, the radian was not defined arbitrarily, making it the more natural choice in most cases; often times being much easier and much more elegant, clear, and concise than using degrees in mathematical formulae. The Babylonians probably gave us the degree, dividing their circle into 6 equal sections (using the angle of an equilateral triangle). each of these 6 sections were probably further subdivided into 60 equal parts given their sexagesimal (base 60) number system. This would also allow them to use such a system for astronomy because the estimated number of days in a year was much less accurate during their time and was often considered 360.
So now, knowing you're working in radians, if you increment using the first of the following statements once in your anim
function (callback to requestAnimFrame
), you will be incrementing the rotation of mesh
on the x-axis by one radian
mesh.rotation.x += 1; // Rotates 1 radian per frame
mesh.rotation.x += Math.PI / 180; // Rotates 1 degree per frame
mesh.rotation.x += 45 * Math.PI / 180 // Rotates 45 degrees per frame
As the last two of the above statements show we can use Math.PI / 180
to easily convert a value in degrees into radians before the assignment if we wish to use degrees instead.
In your case, you need to take into consideration how much time passes with each frame. This is your delta. You have to think of it like this: How many FPS are we running at? We'll declare a global clock
variable which will store a THREE.Clock
object which has an interface to the information we require. We need a global variable we'll call clock
(needs to be accessible in other functions, specifically anim
):
Within init
, create an instance of THREE.Clock
; storing it in the variable declared outside init
(with a greater scope):
clock = new THREE.Clock();
Then, in your anim
function, you'll make two calls that will update two variables associated with clock
:
time
(total elapsed time in milliseconds since the clock was instantiated)delta
(time in milliseconds between each frame) in two other global variables:time = clock.getElapsedTime(); delta = clock.getDelta();
Note that delta
is meant to return the amount of time between each frame; however, this will be true if and only if clock.getDelta
is consistently called within anim
/render
The above conditions are a result of the THREE.Clock
implementation. getDelta
initially returns the amount of time since the clock was instantiated, afterwards the time it returns is simply the time since it was last called). If it somehow gets called mistakenly or inconsistently it's going to screw things up.
Now if your scene doesn't bog down the processor or GPU, Three.JS and it's included requestAnimationFrame shim will try (working with the available resources) to keep things running at a smooth 60 frames per second. This means ideally we will have approximately 1/60 = .016666
seconds between each frame, this is your delta
value which you can read from the clock
each frame and use it to normalize your speed based on the framerate by multiplying as shown below. This way you can get a value in terms of seconds regardless of small variations in the framerate which you can multiply each time in order to get a value in terms of seconds.
So, based on what we had at the beginning in your anim
function you can use it like so:
mesh.rotation.x += delta * 1; // Rotates 1 radian per second
mesh.rotation.x += delta * Math.PI / 180; // Rotates 1 degree per second
mesh.rotation.x += delta * 45 * Math.PI / 180; // Rotates 45 degrees per second
Because our measures of angles, radians and degrees are not actually units then when we look at our units for angular velocity we will see that it is going to function of only time (rather than as a function of distance and time like you have in your code).
As for your specific case, you don't need the radius to calculate the rotational speed (angular velocity), instead you can use the number of hours in a day (the amount of time it takes for a complete revolution, ie. 2 * Math.PI
radians of rotation on it's axis). If you have a variable called revolutionTime
then you can calculate it like so.
secondsInAnHour = 3600;
rotationalSpeed = (2 * Math.PI) / revolutionTime;
If you assume Earth has 24 hours = 24 * 60 * 60 = 86,400
in a day (it doesn't). Then we will get rotationalSpeed = 2 * PI / 86,400
, or roughly 0.0000727
radians per second. You should be able to find textbook values which may be more accurate than this (taking into account a more accurate measurement than our 24 hour flat figure for the amount of time it takes for Earth to complete a revolution.
However, I wouldn't worry about making sure you have all of the angular velocities for the planets exactly correct. Instead, a better idea would be to work out what the ratios between each of the angular velocities (of the planets) are and use that. This will work better for a few reasons: You will likely want a faster rotational speed, this will allow you to use whatever rotational speed works well; the important thing, as with any model (especially when it comes to astronomical models), is that you keep it to scale.