Raspberry Pi Cookbook for Python Programmers — Save 50%
Over 50 easy-to-comprehend tailor-made recipes to get the most out of the Raspberry Pi and unleash its huge potential using Python with this book and ebook
This article by Tim Cox, the author of Raspberry Pi Cookbook for Python Programmers, covers how to create a 3D world in which we can roam around.
(For more resources related to this topic, see here.)
We may be able to create models and objects within our 3D space, as well as generate backgrounds, but we may also want to create a more interesting environment within which to place them.
3D terrain maps provide an elegant way to define very complex landscapes. The terrain is defined using a grayscale image to set the elevation of the land. The following example shows how we can define our own landscape and simulate flying over it, or even walk on its surface:
A 3D landscape generated from a terrain map
You will need to place the Map.png file in the pi3d/textures directory of the Pi3D library. Alternatively, you can use one of the elevation maps already present—replace the reference to Map.png for another one of the elevation maps, such as testislands.jpg.
How to do it…
Create the following 3dWorld.py script:
#!/usr/bin/python3 from __future__ import absolute_import, division from __future__ import print_function, unicode_literals """ An example of generating a 3D environment using a elevation map """ from math import sin, cos, radians import demo import pi3d DISPLAY = pi3d.Display.create(x=50, y=50) #capture mouse and key presses inputs=pi3d.InputEvents() def limit(value,min,max): if (value < min): value = min elif (value > max): value = max return value def main(): CAMERA = pi3d.Camera.instance() tex = pi3d.Texture("textures/grass.jpg") flatsh = pi3d.Shader("uv_flat") # Create elevation map mapwidth,mapdepth,mapheight=200.0,200.0,50.0 mymap = pi3d.ElevationMap("textures/Map.png", width=mapwidth, depth=mapdepth, height=mapheight, divx=128, divy=128, ntiles=20) mymap.set_draw_details(flatsh, [tex], 1.0, 1.0) rot = 0.0 # rotation of camera tilt = 0.0 # tilt of camera height = 20 viewhight = 4 sky = 200 xm,ym,zm = 0.0,height,0.0 onGround = False # main display loop while DISPLAY.loop_running() and not \ inputs.key_state("KEY_ESC"): inputs.do_input_events() #Note:Some mice devices will be located on #get_mouse_movement(1) or (2) etc. mx,my,mv,mh,md=inputs.get_mouse_movement() rot -= (mx)*0.2 tilt -= (my)*0.2 CAMERA.reset() CAMERA.rotate(-tilt, rot, 0) CAMERA.position((xm,ym,zm)) mymap.draw() if inputs.key_state("KEY_W"): xm -= sin(radians(rot)) zm += cos(radians(rot)) elif inputs.key_state("KEY_S"): xm += sin(radians(rot)) zm -= cos(radians(rot)) elif inputs.key_state("KEY_R"): ym += 2 onGround = False elif inputs.key_state("KEY_T"): ym -= 2 ym-=0.1 #Float down! #Limit the movement xm=limit(xm,-(mapwidth/2),mapwidth/2) zm=limit(zm,-(mapdepth/2),mapdepth/2) if ym >= sky: ym = sky #Check onGround ground = mymap.calcHeight(xm, zm) + viewhight if (onGround == True) or (ym <= ground): ym = mymap.calcHeight(xm, zm) + viewhight onGround = True try: main() finally: inputs.release() DISPLAY.destroy() print("Closed Everything. END") #End
How it works…
Once we have defined the display, camera, textures, and shaders that we are going to use, we can define the ElevationMap object.
It works by assigning a height to the terrain image based on the pixel value of selected points of the image. For example, a single line of an image will provide a slice of the ElevationMap object and a row of elevation points on the 3D surface.
Mapping the map.png pixel shade to the terrain height
We create an ElevationMap object by providing the filename of the image we will use for the gradient information (textures/Map.png), and we also create the dimensions of the map (width, depth, and height—which is how high the white spaces will be compared to the black spaces).
The light parts of the map will create high points and the dark ones will create low points.
The Map.png texture provides an example terrain map, which is converted into a three-dimensional surface.
We also specify divx and divy, which determines how much detail of the terrain map is used (how many points from the terrain map are used to create the elevation surface). Finally, ntiles specifies that the texture used will be scaled to fit 20 times across the surface.
Within the main DISPLAY.loop_running() section, we will control the camera, draw ElevationMap, respond to inputs, and limit movements in our space.
As before, we use an InputEvents object to capture mouse movements and translate them to control the camera. We will also use inputs.key_state() to determine if W, S, R, and T have been pressed, which allow us to move forward, backwards, as well as rise up and down.
To ensure that we do not fall through the ElevationMap object when we move over it, we can use mymap.calcHeight() to provide us with the height of the terrain at a specific location (x,y,z). We can either follow the ground by ensuring the camera is set to equal this, or fly through the air by just ensuring that we never go below it. When we detect that we are on the ground, we ensure that we remain on the ground until we press R to rise again.
In this article, we created a 3D world by covering how to define landscapes, the use of elevation maps, and the script required to respond to particular inputs and control movements in a space.
Resources for Article:
|Over 50 easy-to-comprehend tailor-made recipes to get the most out of the Raspberry Pi and unleash its huge potential using Python with this book and ebook|
eBook Price: €20.99
Book Price: €34.99
About the Author :
Tim Cox lives in England with his wife and two young daughters and works as a software engineer. His passion for programming can be traced back to one Christmas in the mid 1980s when he received a Sinclair Spectrum 48k+ home computer (a joint present with his two elder brothers). By typing out and modifying BASIC programs, while dreaming about building robots, an interest in computers and electronics was sparked, which has never faded. This interest saw him through university, where he earned a BEng in Electronics and Electrical Engineering, and into a career in developing embedded software for a wide range of applications, for automotive, aerospace, and the oil industry, among others.
Keen to support the vision behind the Raspberry Pi, reignite engineering in schools, and encourage a new generation of engineers, Tim co-founded the MagPi magazine. Thanks to the dedication and time of the volunteers who contribute to it every month, it continues to have monthly issues and attract an ever-increasing number of readers (and writers) worldwide. Through his site PiHardware.com, Tim produces electronic kits and helps people learn about the Raspberry Pi and hardware interfacing; each of them is supported with detailed instructions and tutorials to help novices build the knowledge and skills for their projects.
This is Tim's first ever book; it mirrors his own experience of discovering the Raspberry Pi and showcasing its fantastic abilities.