The celestial objects and the cosmos are fascinating phenomena. There are a few libraries that allow us to be able to render such objects and that too, in 3D. One of them is called PyVista. In this Answer, we will look at how to visualize 3D Earth and the surrounding planets using this library. Let's drive straight ahead!
PyVista is a pretty powerful Python library and is designed for data visualization specifically in three dimensions. It offers concise ways of creating both interactive and stunning 3D visuals. With PyVista, we can seamlessly render, analyze and manipulate 3D models, making it a great asset for a range of applications like research or engineering simulations.
In this exploration, we will delve into code snippets that showcase the creation of breathtaking visualizations encompassing planets like Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, and Neptune. We will render each planet separately first and then combine them together into a single visualization, all set against a backdrop of a high-resolution space-themed cube map.
Here are a few functions we will encounter in our visualizations, so let's go through them and understand them before starting with the code.
Function | Explanation |
| Creates a light source for illumination in the scene. |
| Sets the direction of the light source using angles. |
| Loads planet meshes and associated data from the |
| Downloads textures for planet surfaces from the |
| Loads a ring-shaped mesh (Saturn's rings) with specified parameters. |
| Downloads the texture for Saturn's rings. |
| Translates a celestial body to a specific position. |
| Initializes a Plotter object with specified lighting settings. |
| Downloads a high-resolution space-themed cubemap. |
| Adds a skybox using the downloaded cubemap. |
| Sets the environment texture of the plot using the cubemap. |
| Adds the created light source to the plot for realistic illumination. |
| Adds a celestial body mesh to the plot with texture and shading settings. |
| Displays the interactive 3D visualization in a browser. |
Let's go through each planet one by one first and understand the rendering mechanism.
import pyvista from pyvista import examples light = pyvista.Light() light.set_direction_angle(30, -20) mercury = examples.planets.load_mercury(radius=2439.0) mercury_texture = examples.planets.download_mercury_surface(texture=True) mercury.translate((0.0, 0.0, 0.0), inplace=True) pl = pyvista.Plotter(lighting="none") cubemap = examples.download_cubemap_space_16k() _ = pl.add_actor(cubemap.to_skybox()) pl.set_environment_texture(cubemap, True) pl.add_light(light) pl.add_mesh(mercury, texture=mercury_texture, smooth_shading=True) pl.show()
Lines 1–2: First, we import the modules we need. We specifically import the pyvista
module and its example dataset using examples
.
Lines 4–5: Next, we create a new Light
object named light
and set its direction angle to (30, -20) degrees. This is the light direction for our scene.
Lines 7–8: We then load the Mercury planet mesh using load_mercury
from the example planets
module. For the planet's surface, we'll have to download the Mercury surface texture using download_mercury_surface
.
Line 10: We translate the Mercury mesh to a specific position in the scene i.e. placing the planet using the translate
method with an (0.0, 0.0, 0.0)
displacement.
Line 12: Moving forward, we create a Plotter
object named pl
for visualization. We specify that the lighting should be turned off for this plot.
Lines 14–16: To create a proper background, we download a space-themed cube map using download_cubemap_space_16k
and add it as a skybox to our plot using the add_actor
method.
Line 18: We set the environment texture of the plot to the previously downloaded cube map using set_environment_texture
.
Line 20: Now, we add the light
object to the plot using the add_light
method. This provides a really realistic illumination of the scene.
Line 21: To show our planet, we add our Mercury mesh to the plot as a mesh with a texture applied to it. The smooth_shading
parameter is set to True
for a nicer display.
Line 22: Finally, we call the show
method on our Plotter
object pl
to display the interactive plot in a browser. This will render the 3D scene with the Mercury planet and the specified lighting and environment setup.
We can follow the above explanation and render the rest of the planets too. You can get the code for each planet below.
This code visualizes the planet Venus along with appropriate space lighting and a realistic space-themed background.
import pyvista from pyvista import examples light = pyvista.Light() light.set_direction_angle(30, -20) venus = examples.planets.load_venus(radius=6052.0) venus_texture = examples.planets.download_venus_surface(texture=True) venus.translate((-15000.0, 0.0, 0.0), inplace=True) pl = pyvista.Plotter(lighting="none") cubemap = examples.download_cubemap_space_16k() _ = pl.add_actor(cubemap.to_skybox()) pl.set_environment_texture(cubemap, True) pl.add_light(light) pl.add_mesh(venus, texture=venus_texture, smooth_shading=True) pl.show()
This code visualizes our very own homeland, Earth, along with appropriate space lighting and a realistic space-themed background.
import pyvista from pyvista import examples light = pyvista.Light() light.set_direction_angle(30, -20) earth = examples.planets.load_earth(radius=6378.1) earth_texture = examples.load_globe_texture() earth.translate((-30000.0, 0.0, 0.0)) pl = pyvista.Plotter(lighting="none") cubemap = examples.download_cubemap_space_16k() _ = pl.add_actor(cubemap.to_skybox()) pl.set_environment_texture(cubemap, True) pl.add_light(light) pl.add_mesh(earth, texture=earth_texture, smooth_shading=True) pl.show()
This code visualizes the planet Mars along with appropriate space lighting and a realistic space-themed background.
import pyvista from pyvista import examples light = pyvista.Light() light.set_direction_angle(30, -20) mars = examples.planets.load_mars(radius=3397.2) mars_texture = examples.planets.download_mars_surface(texture=True) mars.translate((-30000.0, 0.0, 0.0), inplace=True) pl = pyvista.Plotter(lighting="none") cubemap = examples.download_cubemap_space_16k() _ = pl.add_actor(cubemap.to_skybox()) pl.set_environment_texture(cubemap, True) pl.add_light(light) pl.add_mesh(mars, texture=mars_texture, smooth_shading=True) pl.show()
This code visualizes the planet Jupiter along with appropriate space lighting and a realistic space-themed background.
import pyvista from pyvista import examples light = pyvista.Light() light.set_direction_angle(30, -20) jupiter = examples.planets.load_jupiter(radius=71492.0) jupiter_texture = examples.planets.download_jupiter_surface(texture=True) jupiter.translate((-45000.0, 0.0, 0.0), inplace=True) pl = pyvista.Plotter(lighting="none") cubemap = examples.download_cubemap_space_16k() _ = pl.add_actor(cubemap.to_skybox()) pl.set_environment_texture(cubemap, True) pl.add_light(light) pl.add_mesh(jupiter, texture=jupiter_texture, smooth_shading=True) pl.show()
This is where things get interesting! To render Saturn, we'll add its rings within the visualization.
For this purpose, we can use the following parameters for our examples.planets.load_saturn_rings()
function:
inner
specifies the inner radius of the rings.
outer
specifies the outer radius of the rings.
c_res
specifies the resolution of the rings i.e., the number of segments used to create the ring.
import pyvista from pyvista import examples light = pyvista.Light() light.set_direction_angle(30, -20) saturn = examples.planets.load_saturn(radius=60268.0) saturn_texture = examples.planets.download_saturn_surface(texture=True) inner = 60268.0 + 7000.0 outer = 60268.0 + 80000.0 saturn_rings = examples.planets.load_saturn_rings(inner=inner, outer=outer, c_res=50) saturn_rings_texture = examples.planets.download_saturn_rings(texture=True) saturn.translate((-150000.0, 0.0, 0.0), inplace=True) saturn_rings.translate((-150000.0, 0.0, 0.0), inplace=True) pl = pyvista.Plotter(lighting="none") cubemap = examples.download_cubemap_space_16k() _ = pl.add_actor(cubemap.to_skybox()) pl.set_environment_texture(cubemap, True) pl.add_light(light) pl.add_mesh(saturn, texture=saturn_texture, smooth_shading=True) pl.add_mesh(saturn_rings, texture=saturn_rings_texture, smooth_shading=True) pl.show()
This code visualizes the planet Uranus along with appropriate space lighting and a realistic space-themed background.
import pyvista from pyvista import examples light = pyvista.Light() light.set_direction_angle(30, -20) uranus = examples.planets.load_uranus(radius=25559.0) uranus_texture = examples.planets.download_uranus_surface(texture=True) uranus.translate((-400000.0, 0.0, 0.0), inplace=True) pl = pyvista.Plotter(lighting="none") cubemap = examples.download_cubemap_space_16k() _ = pl.add_actor(cubemap.to_skybox()) pl.set_environment_texture(cubemap, True) pl.add_light(light) pl.add_mesh(uranus, texture=uranus_texture, smooth_shading=True) pl.show()
This code visualizes the planet Neptune along with appropriate space lighting and a realistic space-themed background.
import pyvista from pyvista import examples light = pyvista.Light() light.set_direction_angle(30, -20) neptune = examples.planets.load_neptune(radius=24764.0) neptune_texture = examples.planets.download_neptune_surface(texture=True) neptune.translate((-600000.0, 0.0, 0.0), inplace=True) pl = pyvista.Plotter(lighting="none") cubemap = examples.download_cubemap_space_16k() _ = pl.add_actor(cubemap.to_skybox()) pl.set_environment_texture(cubemap, True) pl.add_light(light) pl.add_mesh(neptune, texture=neptune_texture, smooth_shading=True) pl.show()
Having learned how to visualize the different planets separately, we can combine the codes and create a space scene with all of the planets together. This allows us to visualize the differences in their relative sizes as well.
import pyvista from pyvista import examples light = pyvista.Light() light.set_direction_angle(30, -20) mercury = examples.planets.load_mercury(radius=2449.0) venus = examples.planets.load_venus(radius=6062.0) earth = examples.planets.load_earth(radius=6388.1) mars = examples.planets.load_mars(radius=3407.2) jupiter = examples.planets.load_jupiter(radius=71502.0) saturn = examples.planets.load_saturn(radius=60278.0) uranus = examples.planets.load_uranus(radius=25669.0) neptune = examples.planets.load_neptune(radius=24874.0) inner = 60268.0 + 7000.0 outer = 60268.0 + 80000.0 saturn_rings = examples.planets.load_saturn_rings(inner=inner, outer=outer, c_res=50) saturn_rings_texture = examples.planets.download_saturn_rings(texture=True) mercury_texture = examples.planets.download_mercury_surface(texture=True) venus_texture = examples.planets.download_venus_surface(texture=True) earth_texture = examples.load_globe_texture() mars_texture = examples.planets.download_mars_surface(texture=True) jupiter_texture = examples.planets.download_jupiter_surface(texture=True) saturn_texture = examples.planets.download_saturn_surface(texture=True) saturn_rings_texture = examples.planets.download_saturn_rings(texture=True) uranus_texture = examples.planets.download_uranus_surface(texture=True) neptune_texture = examples.planets.download_neptune_surface(texture=True) mercury.translate((10.0, 0.0, 0.0), inplace=True) venus.translate((-15015.0, 0.0, 0.0), inplace=True) earth.translate((-30030.0, 0.0, 0.0), inplace=True) mars.translate((-45045.0, 0.0, 0.0), inplace=True) jupiter.translate((-150150.0, 0.0, 0.0), inplace=True) saturn.translate((-400400.0, 0.0, 0.0), inplace=True) saturn_rings.translate((-400400.0, 0.0, 0.0), inplace=True) uranus.translate((-600600.0, 0.0, 0.0), inplace=True) neptune.translate((-700700.0, 0.0, 0.0), inplace=True) pl = pyvista.Plotter(lighting="none") cubemap = examples.download_cubemap_space_16k() _ = pl.add_actor(cubemap.to_skybox()) pl.set_environment_texture(cubemap, True) pl.add_light(light) pl.add_mesh(mercury, texture=mercury_texture, smooth_shading=True) pl.add_mesh(venus, texture=venus_texture, smooth_shading=True) pl.add_mesh(earth, texture=earth_texture, smooth_shading=True) pl.add_mesh(mars, texture=mars_texture, smooth_shading=True) pl.add_mesh(jupiter, texture=jupiter_texture, smooth_shading=True) pl.add_mesh(saturn, texture=saturn_texture, smooth_shading=True) pl.add_mesh(saturn_rings, texture=saturn_rings_texture, smooth_shading=True) pl.add_mesh(uranus, texture=uranus_texture, smooth_shading=True) pl.add_mesh(neptune, texture=neptune_texture, smooth_shading=True) pl.show()
Lines 1–2: First and foremost, we import our necessary modules.
Lines 4–5: A new Light
object named light
is created, and its direction angle is set to (30, -20) degrees to determine the lighting direction.
Lines 7–14: We load various planet meshes such as Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, and Neptune using the load_*
functions from the example planets
module.
Lines 16–19: For our Saturn rendering, we define the inner and outer radii of its rings and load a ring-shaped mesh using load_saturn_rings
. For the texture of the rings, we use download_saturn_rings(texture=True)
.
Lines 21–29: Next, we also download textures for each planet using the download_*_surface(texture=True)
functions.
Lines 31–39: Each planet is translated to a specific position in the scene using the translate
method. We do this by specifying different offsets.
Line 41: A Plotter
object pl
is created for visualization.
Lines 43–44: We use a high-resolution space-themed cube map for the background using download_cubemap_space_16k
and add it as a skybox using add_actor
.
Line 46: The environment texture of the plot is set to it using set_environment_texture
.
Line 48: The light
object we created is added to the plot.
Lines 49–57: Our planets are now ready! Each planet mesh is added to the plot with its respective texture applied and with smooth shading for a smooth appearance.
Line 59: Finally, show
is called on pl
to display our amazing visualization.
Note: These codes require extensive processing so they may take a while to run and render an empty screen initially during processing.
The rendered 3D scene showcases all the planets, their rings, and the customized lighting and environment setup.
Celestial body rendering can be used in several cases like the ones mentioned below.
Engineers can use this visualization approach to simulate the movement and different positions of celestial bodies.
PyVista can help educators design astronomy lessons by visualizing planetary properties like relative sizes, rotations, etc.
An interesting application would be to power virtual planetarium applications, offering users an interactive tour of the solar system and beyond.
Conclusively, PyVista allows us to explore Earth and celestial bodies in a pretty visually appealing and interactive manner. The combination of planetary meshes, textures, lighting, and environment settings allows us to witness a realistic depiction of the cosmos.
How well do you know PyVista’s celestial visualization?
What’s different between rendering other planets and Saturn?
Free Resources