Sharedwww / talks / 2006-05-09-sage-digipen / tutorial / portal-1.pyOpen in CoCalc
Author: William A. Stein
1
# Soya 3D tutorial
2
# Copyright (C) 2004 Jean-Baptiste 'Jiba' LAMY
3
# Copyright (C) 2001-2003 Bertrand 'blam!' LAMY
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19
20
# portal-1: Portal
21
22
# A portal is a 2D rectangle used to link 2 worlds just as if the world
23
# beyond was seen through an open door.
24
# Portals are usefull to compute visibility and avoid renderering the
25
# world beyond when it is not visible.
26
27
28
import sys, os, os.path, soya, soya.cube, soya.widget, soya.sdlconst
29
30
soya.init()
31
soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))
32
33
m1 = soya.Material(soya.Image.get("block2.png"))
34
m2 = soya.Material(soya.Image.get("metal1.png"))
35
36
scene = soya.World()
37
38
# Create world 1
39
40
w1 = soya.World(scene)
41
w1.set_xyz(0.0, 0.0, 0.0)
42
w1.atmosphere = soya.Atmosphere()
43
w1.atmosphere.bg_color = (0.0, 0.0, 1.0, 1.0)
44
w1.atmosphere.ambient = (0.0, 0.5, 0.0, 1.0)
45
w1.atmosphere.fog_color = (0.0, 0.0, 1.0, 1.0)
46
w1.atmosphere.fog_start = 10.0
47
w1.atmosphere.fog_end = 50.0
48
w1.atmosphere.fog = 1
49
w1.atmosphere.fog_type = 0
50
w1.set_shape(soya.cube.Cube(None, m1).shapify())
51
52
# Create world 2
53
# Notice that w2 doesn't have the same atmosphere than w1
54
55
w2 = soya.World(scene)
56
w2.set_xyz(0.0, 0.0, -10.0)
57
w2.atmosphere = soya.SkyAtmosphere()
58
w2.atmosphere.bg_color = (1.0, 0.0, 0.0, 1.0)
59
w2.atmosphere.ambient = (0.5, 0.5, 0.0, 1.0)
60
w2.atmosphere.skyplane = 1
61
w2.atmosphere.sky_color = (1.0, 1.0, 0.0, 1.0)
62
w2.atmosphere.cloud = soya.Material(soya.Image.get("cloud.png"))
63
w2.set_shape(soya.cube.Cube(None, m2).shapify())
64
65
66
# Add a light in world 2.
67
# The light will not light the objects in world 1 unless light.top_level is true.
68
69
light = soya.Light(w2)
70
light.top_level = 0
71
light.ambient = (1.0, 1.0, 0.0, 1.0)
72
light.set_xyz(0.0, 2.0, 0.0)
73
74
75
# Portal creation
76
# Create a portal that link to world 2. The attribute "beyond" is the world beyond
77
# the portal
78
79
portal1 = soya.Portal(w1)
80
portal1.beyond = w2
81
portal1.set_xyz(0.0, 0.0, -5.0)
82
83
# To change the size of the portal, we scale it (the z scale factor has no meaning)
84
85
portal1.scale(4.0, 4.0, 1.0)
86
# Attr bound_atm must be set to 1 if the 2 worlds linked doesn't have the
87
# same atmosphere (else set the value to 0).
88
#portal1.bound_atmosphere = 1
89
# Setting use_clip_plane to 1 will affect object rendered in world beyond,
90
# this means only the part of the objects that are visible through the portal
91
# 2D rectangle will be rendered.
92
#portal1.nb_clip_planes = 4
93
94
# Create a portal that link world 2 to world 1
95
96
portal2 = soya.Portal(w2)
97
portal2.rotate_lateral(180.0)
98
portal2.beyond = w1
99
portal2.scale(4.0, 4.0, 1.0)
100
portal2.set_xyz(0.0, 0.0, 5.0)
101
102
#portal1.nb_clip_planes = 0
103
#portal2.nb_clip_planes = 0
104
105
# ASCII art representation of the two world :
106
# \
107
# \ |
108
# +-+ | |
109
# | |\ | |
110
# +-+ + > world2 |
111
# \ \| | |
112
# +-+ | |
113
# | |
114
# <-portal2-> / |
115
#--------------+ |
116
# <-portal1-> \ |
117
# | > scene
118
# +-+ | |
119
# | |\ | |
120
# +-+ + | |
121
# \ \| | |
122
# +-+ > world1 |
123
# | |
124
# ___ | |
125
# \^/ | |
126
# V | |
127
# camera / |
128
# /
129
130
class MovableCamera(soya.Camera):
131
def __init__(self, parent):
132
soya.Camera.__init__(self, parent)
133
134
self.speed = soya.Vector(self)
135
self.rotation_lateral_speed = 0.0
136
self.rotation_vertical_speed = 0.0
137
138
def begin_round(self):
139
soya.Camera.begin_round(self)
140
141
for event in soya.process_event():
142
if event[0] == soya.sdlconst.KEYDOWN:
143
if event[1] == soya.sdlconst.K_UP: self.speed.z = -1.0
144
elif event[1] == soya.sdlconst.K_DOWN: self.speed.z = 1.0
145
elif event[1] == soya.sdlconst.K_LEFT: self.rotation_lateral_speed = 10.0
146
elif event[1] == soya.sdlconst.K_RIGHT: self.rotation_lateral_speed = -10.0
147
elif event[1] == soya.sdlconst.K_q: soya.IDLER.stop()
148
elif event[1] == soya.sdlconst.K_ESCAPE: soya.IDLER.stop()
149
if event[0] == soya.sdlconst.KEYUP:
150
if event[1] == soya.sdlconst.K_UP: self.speed.z = 0.0
151
elif event[1] == soya.sdlconst.K_DOWN: self.speed.z = 0.0
152
elif event[1] == soya.sdlconst.K_LEFT: self.rotation_lateral_speed = 0.0
153
elif event[1] == soya.sdlconst.K_RIGHT: self.rotation_lateral_speed = 0.0
154
155
# Checks if the camera has passed through a portal.
156
# First, collects all portals in the camera's root world.
157
# the World.search_all method take a predicat (a one argument callable), and
158
# returns a list of all items (recursively) in the world that satisfy the predicat.
159
160
portals = camera.to_render.search_all(lambda item: isinstance(item, soya.Portal))
161
162
# Then for each portal, checks if the camera has pass through it, and if so,
163
# transfers the camera in the world beyond the portal.
164
# The has_passed_through method takes two argument : the old position of the object
165
# and the new one or (as here) the speed vector.
166
167
for portal in portals:
168
if portal.has_passed_through(self, self.speed):
169
print "pass !", self.position(), self.speed
170
portal.pass_through(camera)
171
172
def advance_time(self, proportion):
173
self.add_mul_vector(proportion, self.speed)
174
self.turn_lateral (self.rotation_lateral_speed * proportion)
175
self.turn_vertical(self.rotation_vertical_speed * proportion)
176
177
178
# Creates a movable camera, that render the world 1 only (to_render attribute)
179
180
camera = MovableCamera(scene)
181
camera.to_render = w1
182
camera.set_xyz(0.0, 0.0, 8.0)
183
184
root = soya.widget.Group()
185
186
root.add(camera)
187
188
label = soya.widget.Label(root, " - Portal demo - use cursor keys to move.")
189
label.resize_style = soya.widget.WIDGET_RESIZE_MAXIMIZE
190
191
soya.set_root_widget(root)
192
193
soya.Idler(scene).idle()
194