# Soya 3D tutorial1# Copyright (C) 2004 Jean-Baptiste 'Jiba' LAMY2# Copyright (C) 2001-2002 Bertrand 'blam!' LAMY3#4# This program is free software; you can redistribute it and/or modify5# it under the terms of the GNU General Public License as published by6# the Free Software Foundation; either version 2 of the License, or7# (at your option) any later version.8#9# This program is distributed in the hope that it will be useful,10# but WITHOUT ANY WARRANTY; without even the implied warranty of11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12# GNU General Public License for more details.13#14# You should have received a copy of the GNU General Public License15# along with this program; if not, write to the Free Software16# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA171819# land-1: Landscape : bitmap-based landscape2021# This lesson shows how to make a landscape (also known as heightmap or terrain), using22# a bitmap to describe the terrain. The bitmap acts like a popographic map ; the brighter23# a pixel is, the higher it is. You can make such bitmaps in software like the Gimp.242526# Imports and inits Soya (see lesson basic-1.py).2728import sys, os, os.path, soya, soya.sdlconst2930soya.init()31soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))32soya.set_quality(2)3334# Creates the scene.3536scene = soya.World()3738# Creates a new landscape in the scene.3940land = soya.Land(scene)4142# Gets the image "map1.png" from the tutorial data dir, and create the landscape43# from this image. The image dimension must be power of 2 plus 1 : (2 ** n) + 1.4445land.from_image(soya.Image.get("map1.png"))4647# By default, the landscape height ranges from 0.0 (black pixels) to 1.0 (white pixels).48# Here, we multiply the height by 8.0 so it ranges from 0.0 to 8.0.4950land.multiply_height(8.0)5152# Now that we have the landscape, we are going to texture it53# (see lesson modeling-material-2 about texturing). First, we creates two textured54# materials.5556#material1 = soya.Material(soya.Image.get("block2.png"))57#material2 = soya.Material(soya.Image.get("metal1.png"))58material1 = soya.Material.get("block2")59material2 = soya.Material.get("metal1")6061#material1 = soya.Material()62#material1.diffuse = (0.0, 0.0, 0.0, 1.0)63#material1 = soya.Material.get("block2")64#material2 = soya.Material()6566# asigns MATERIAL1 to any point whose height is in the range 0.0-6.0, and material2 to67# any point whose height is in the range 6.0-8.0 (remember, height ranges from 0.0 to 8.0).6869land.set_material_layer(material1, 0.0, 6.0)70land.set_material_layer(material2, 6.0, 8.0)7172# Assigns material1 to any point whose height is in the range 0.0-8.0 and if the angle73# between the surface normal and the verticalvector is in the range 0.0-20.0.7475land.set_material_layer_angle(material1, 0.0, 8.0, 0.0, 20.0)7677# Now we set some Land attributes:78# - texture_factor specifies how much the textures are zoomed (higher values mean79# smaller texture)8081# - scale_factor specifies how the landscape is scaled in the 2 horizontal dimensions.8283# - the 2 last attributes influence the behaviour of the level of detail (LOD) algorithm84# (LOD means that parts of the landscape are rendered with more detail / more triangle85# if they are close to the camera). They are a trading between speed and quality.86#87# The higher split_factor is, the better precision you have (it means more triangles88# to draw the Land even far from Camera).89#90# patch_size represents the size of patches. A patch is a square part of the Land that91# computes its visibility and precision.9293# the values below are the default ones.9495land.texture_factor = 1.096land.scale_factor = 1.097land.patch_size = 898land.split_factor = 2.099land.texture_factor = 0.25100101# Moves the landscape.102103land.y = -2.5104105# Adds a light.106107light = soya.Light(scene)108light.set_xyz(0.0, 15.0, 0.0)109110# Adds a keyboard-controlled camera and a rendering loop111112class MovableCamera(soya.Camera):113def __init__(self, parent):114soya.Camera.__init__(self, parent)115116self.speed = soya.Vector(self)117self.rotation_lateral_speed = 0.0118self.rotation_vertical_speed = 0.0119120def begin_round(self):121soya.Camera.begin_round(self)122123for event in soya.process_event():124if event[0] == soya.sdlconst.KEYDOWN:125if event[1] == soya.sdlconst.K_UP: self.speed.z = -1.0126elif event[1] == soya.sdlconst.K_DOWN: self.speed.z = 1.0127elif event[1] == soya.sdlconst.K_LEFT: self.rotation_lateral_speed = 10.0128elif event[1] == soya.sdlconst.K_RIGHT: self.rotation_lateral_speed = -10.0129elif event[1] == soya.sdlconst.K_q: soya.IDLER.stop()130elif event[1] == soya.sdlconst.K_ESCAPE: soya.IDLER.stop()131if event[0] == soya.sdlconst.KEYUP:132if event[1] == soya.sdlconst.K_UP: self.speed.z = 0.0133elif event[1] == soya.sdlconst.K_DOWN: self.speed.z = 0.0134elif event[1] == soya.sdlconst.K_LEFT: self.rotation_lateral_speed = 0.0135elif event[1] == soya.sdlconst.K_RIGHT: self.rotation_lateral_speed = 0.0136137def advance_time(self, proportion):138self.add_mul_vector(proportion, self.speed)139self.turn_lateral (self.rotation_lateral_speed * proportion)140self.turn_vertical(self.rotation_vertical_speed * proportion)141142143camera = MovableCamera(scene)144camera.set_xyz(16.0, 6.0, 0.0)145camera.look_at(soya.Point(scene, 16.0, 6.0, 10.0))146soya.set_root_widget(camera)147148149#camera.set_xyz(16.0, 8.0, 0.0)150#camera.look_at(soya.Point(scene, 16.0, 6.0, 10.0))151152153scene.x = 100.0154155156scene.atmosphere = soya.Atmosphere()157scene.atmosphere.ambient = (1.0, 1.0, 1.0, 1.0)158159#soya.Idler(scene).idle()160i = soya.Idler(scene)161#i.min_frame_duration = 0.0162i.idle()163print i.fps164165