Planetary distances are difficult to accurately render in Blender because the distances are so great. One way to get around this is to scale the planet using its apparent size.
The following code provides an example of how to:
- Scale a planet using its angular diameter.
- Render an animation using Python code.
- Change text during an animation.
The number of frames between the planets is calculated based on the speed of a fast solar sail (80 km/s) and then reduced by a constant factor to make the journeys between the gas giants take minutes, rather than months.
It is presumed that the sphere is located exactly 2 Blender Units from the camera and has been scaled in Edit mode by 0.5 Blender Units. The result is that the sphere should exactly fill from the top to the bottom of the camera’s view port.
The result:
See also:
######################################################
#
# Importing modules
#
######################################################
import bpy
import datetime
import math
######################################################
#
# Constants
#
######################################################
RADIUS_SUN = 695630.00
RADIUS_MERCURY = 2439.70
RADIUS_VENUS = 6051.80
RADIUS_EARTH = 6378.10
RADIUS_MARS = 3396.20
RADIUS_JUPITER = 71492.00
RADIUS_SATURN = 60268.00
RADIUS_URANUS = 25559.00
RADIUS_NEPTUNE = 24764.00
DISTANCE_MERCURY = 44607842
DISTANCE_VENUS = 60388451
DISTANCE_EARTH = 41123114
DISTANCE_MARS = 101374519
DISTANCE_JUPITER = 526211061
DISTANCE_SATURN = 648678232
DISTANCE_URANUS = 1512317091
DISTANCE_NEPTUNE = 1594769151
# Scale Z = (scale - (scale * oblate))
OBLATE_MERCURY = 0.0000
OBLATE_VENUS = 0.0000
OBLATE_MARS = 0.0065
OBLATE_EARTH = 0.0034
OBLATE_JUPITER = 0.0649
OBLATE_SATURN = 0.0980
OBLATE_URANUS = 0.0229
OBLATE_NEPTUNE = 0.0171
TRAVEL_FRAMES_MERCURY = 155
TRAVEL_FRAMES_VENUS = 262
TRAVEL_FRAMES_EARTH = 178
TRAVEL_FRAMES_MARS = 440
TRAVEL_FRAMES_JUPITER = 2284
TRAVEL_FRAMES_SATURN = 2815
TRAVEL_FRAMES_URANUS = 6564
TRAVEL_FRAMES_NEPTUNE = 6922
TRAVEL_DURATION_DAYS_MERCURY = 5.163
TRAVEL_DURATION_DAYS_VENUS = 8.737
TRAVEL_DURATION_DAYS_EARTH = 5.950
TRAVEL_DURATION_DAYS_MARS = 14.666
TRAVEL_DURATION_DAYS_JUPITER = 76.130
TRAVEL_DURATION_DAYS_SATURN = 93.848
TRAVEL_DURATION_DAYS_URANUS = 218.796
TRAVEL_DURATION_DAYS_NEPTUNE = 230.725
PLANET_NAME = "Saturn"
PLANET_RADIUS = RADIUS_SATURN
PLANET_DISTANCE = DISTANCE_SATURN
PLANET_OBLATE = OBLATE_SATURN
CAMERA_DISTANCE = PLANET_RADIUS * 2
TRAVEL_FRAMES = TRAVEL_FRAMES_SATURN
TRAVEL_DURATION_DAYS = TRAVEL_DURATION_DAYS_SATURN
RENDER = False
WARP = True
# TRAVEL to Saturn (1 - 2815)
BEGIN_DATETIME = datetime.datetime( 2153, 1, 24, 1, 17, 39, 767000 )
# Calculation used to set the seconds when at a planet, not travelling.
#
TRAVEL_DURATION_SECS = TRAVEL_DURATION_DAYS * 24 * 60 * 60
SECONDS_PER_FRAME = round( TRAVEL_DURATION_SECS / TRAVEL_FRAMES )
# Calculation used when travelling between planets.
#
DISTANCE_PER_FRAME = PLANET_DISTANCE / TRAVEL_FRAMES
# Increases by SECONDS_PER_FRAME every frame.
#
current_datetime = BEGIN_DATETIME
current_frame = bpy.context.scene.frame_start
# Calculates the apparent distances and diameters to obtain a scaling
# factor for the sphere.
#
def scale_factor( radius, distance ):
rs = math.pow( radius, 2 )
blender_distance = radius * 4
simulated_apparent_diameter = 2 * radius * math.sqrt( 1 - rs / math.pow( distance, 2 ) )
simulated_apparent_distance = distance - rs / distance
blender_apparent_diameter = 2 * radius * math.sqrt( 1 - rs / math.pow( blender_distance, 2 ) )
blender_apparent_distance = blender_distance - rs / blender_distance
simulated_ratio = simulated_apparent_diameter / simulated_apparent_distance
blender_ratio = blender_apparent_diameter / blender_apparent_distance
return simulated_ratio / blender_ratio
def set_text( text_object, text_value ):
bpy.ops.object.select_name( name=text_object, extend=False )
bpy.ops.object.editmode_toggle()
bpy.ops.font.delete()
bpy.ops.font.text_insert( text=text_value )
bpy.ops.object.editmode_toggle()
def update_text():
d = current_datetime.strftime( '%Y-%m-%d' )
t = current_datetime.strftime( '%H:%M:%S' )
set_text( "Date", d )
set_text( "Time", t )
def render_frame():
filename = "renders/sun/" + ("%04d" % current_frame) + ".png"
if RENDER:
bpy.ops.render.render()
bpy.data.images["Render Result"].save_render( filepath=filename )
#print( "Saved: ", filename )
def scale_planet( planet_object, scale ):
bpy.ops.object.select_name( name=planet_object, extend=False )
ob = bpy.data.objects[ planet_object ]
ob.scale = (scale, scale, scale - (scale * PLANET_OBLATE))
def render_animation():
global current_frame
global current_datetime
distance = PLANET_DISTANCE
scale = 0
# No planet in the initial frame for travelling.
#
if WARP: scale_planet( PLANET_NAME, scale )
while current_frame <= bpy.context.scene.frame_end:
bpy.ops.anim.change_frame( frame=current_frame )
print( current_frame, ' ', current_datetime )
update_text()
render_frame()
current_frame = current_frame + 1
distance -= DISTANCE_PER_FRAME
scale = scale_factor( PLANET_RADIUS, distance + CAMERA_DISTANCE * 2 )
print( "Distance: " , distance, " Scale: ", scale )
# Travel to the planet by scaling it up using its apparent size.
#
if WARP:
if distance > 0: scale_planet( PLANET_NAME, scale )
current_datetime = current_datetime + datetime.timedelta( seconds=SECONDS_PER_FRAME, microseconds=496000 )
else:
current_datetime = current_datetime + datetime.timedelta( milliseconds=round( 1000/30 ) )
update_text()
render_animation()
# render_frame()