Creating Animated 3D Objects with Python

Ever since the introduction of electronic devices with touch controls, interactive 3D graphics objects have become increasingly popular in multimedia electronic books (ebooks). The Open3D and the Rasterio packages for Python provide the necessary tools for creating and exporting 3D graphics objects for inclusion in documents such as multimedia ebooks, interactive websites, and presentations.

I worked on this for two full days, desperately missing the excellent support MathWorks for Python. The problem was that the 3D model needed not only nodes and edges, but also surfaces colored in a way typical for digital terrain models. My queries to ChatGPT also consistently provided solutions that did not work. Anyway, I managed to get it running after two days, here it is!

The Polygon File Format (PLY) files are text or binary files with the file extension .ply. Suche a file contains vertices, edges, and faces for 3D polygons. The PLY files can be viewed using a browser plugin (many different types of which are available online) or using 3D software, such as the open-source MeshLab software

https://www.meshlab.net

or the free Blender software available at

https:///www.blender.org

These tools (as well as others) can be used to convert the PLY format into other 3D graphics object file formats, such as the Universal 3D (U3D), the Virtual Reality Modeling Language (VRML), the Collada digital asset exchange (DAE) or Filmbox (FBX) formats. As an example, the U3D format is the format required to place a 3D graphics object onto a PDF page with Adobe Acrobat.

The digital terrain models such as the one in file s01_e036_1arc_v3.tif are great examples of such interactive 3D objects. We first import the required packages using

import numpy as np
import matplotlib.pyplot as plt
import open3d as o3d
import open3d.utility as o3du
import rasterio as rasterio
import rasterio.plot

We use rasterio.open to read the GeoTIFF file using

ginfo = rasterio.open('s01_e036_1arc_v3.tif')

SRTM = ginfo.read()
SRTM = np.squeeze(SRTM)

which is a generic tool for reading geospatial raster data files. The output arguments are the digital elevation data SRTM. The SRTM dataset actually has a resolution of 1/3600 degrees, but we first reduce it to 1/360 degrees so that our computers can handle a smooth 3D display. We define a coordinate grid lon and lat to match SRTM using

lon = np.linspace(36,37,361)
lat = np.linspace(-1,0,361)
SRTM = SRTM[::10,::10]

SRTM = SRTM/1000

nrows,ncols = SRTM.shape

We then create the vertices of the 3D model using

vertices = []
for i in range(nrows):
for j in range(ncols):
   vertices.append([lon[i],lat[j],-SRTM[i,j]])

vertices = np.array(vertices)

We then define scaling factors for each dimension using

vertices = vertices*np.array([1.0,1.0,0.2])

We then create faces for a regular grid structure and connect vertices within a grid to form triangles. Faces are defined based on vertex indices.

faces = []
for i in range(nrows-1):
for j in range(ncols-1):
    v0 = i*ncols+j
    v1 = v0+1
    v2 = v0+ncols
    v3 = v2+1

We then define two triangles per grid square (quad)

faces.append([v0,v1,v2])
faces.append([v1,v3,v2])

faces = np.array(faces)

We then create colors from SRTM using the ‘terrain’ colormap.

SRTM = (SRTM-SRTM.min()) \
   /(SRTM.max()-SRTM.min())
colormap = plt.get_cmap('terrain')
colors = colormap(SRTM)
colors = colors.reshape(-1,4)
colors = colors[:,:3]

We then create the mesh object using

mesh = o3d.geometry.TriangleMesh()
mesh.vertices = o3du.Vector3dVector(vertices)
mesh.triangles = o3du.Vector3iVector(faces)
mesh.vertex_colors = o3du.Vector3dVector(colors)

We can rotate the mesh object using

R = mesh.get_rotation_matrix_from_xyz((1.5,0,1.5))
mesh.rotate(R,center=(0,0,0))

Finally, we export the mesh to a PLY file using

o3d.io.write_triangle_mesh('srtm_1.ply',mesh)

Importing the resulting PLY file into a PLY client such as MeshLab or Blender reveals that the terrain model does indeed has colors, as defined by demcmap. We can use the file in the PLY format to create an interactive document.

References

Download all files to perform the experiment.

References

Trauth, M.H. (2024) Python Recipes for Earth Sciences – Second Edition. Springer International Publishing, 491 p., https://doi.org/10.1007/978-3-031-56906-7