forked from pi3d/pi3d_demos
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TigerShadow.py
314 lines (269 loc) · 10 KB
/
TigerShadow.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#!/usr/bin/python
from __future__ import absolute_import, division, print_function, unicode_literals
""" TigerTank demo but with cast shadows
"""
import math, random, time, traceback
import demo
import pi3d
LOGGER = pi3d.Log.logger(__name__)
# Create a Tkinter window
winw, winh, bord = 1200, 800, 0 #64MB GPU memory setting
# winw,winh,bord = 1920,1200,0 #128MB GPU memory setting
DISPLAY = pi3d.Display.create(tk=True, window_title='Tiger Tank demo in Pi3D',
w=winw, h=winh - bord, far=3000.0,
background=(0.4, 0.8, 0.8, 1), frames_per_second=16)
#inputs = InputEvents()
#inputs.get_mouse_movement()
mylight = pi3d.Light(lightpos=(1.0, -1.0, 1.0), lightcol =(0.8, 0.8, 0.8), lightamb=(0.20, 0.20, 0.22))
win = DISPLAY.tkwin
shader = pi3d.Shader('shadow_uv_bump')
flatsh = pi3d.Shader('uv_flat')
shade2d = pi3d.Shader('2d_flat')
CAMERA = pi3d.Camera()
#========================================
# create splash screen and draw it
splash = pi3d.ImageSprite("textures/tiger_splash.jpg", shade2d, w=10, h=10, z=0.2)
splash.draw()
DISPLAY.swap_buffers()
# create environment cube
ectex = pi3d.loadECfiles('textures/ecubes/Miramar', 'miramar_256',
suffix='png')
myecube = pi3d.EnvironmentCube(size=1800.0, maptype='FACES')
myecube.set_draw_details(flatsh, ectex)
# Create elevation map
mapwidth = 1800.0
mapdepth = 1800.0
mapheight = 120.0
mountimg1 = pi3d.Texture('textures/mountains3_512.jpg')
bumpimg = pi3d.Texture('textures/grasstile_n.jpg')
tigerbmp = pi3d.Texture('models/Tiger/tiger_bump.jpg')
topbmp = pi3d.Texture('models/Tiger/top_bump.jpg')
#roadway = pi3d.Texture('textures/road5.png')
mymap = pi3d.ElevationMap(mapfile='textures/mountainsHgt2.png',
width=mapwidth, depth=mapdepth,
height=mapheight, divx=64, divy=64)
mymap.set_draw_details(shader, [mountimg1, bumpimg], 128.0, 0.0)
FOG = (0.5, 0.5, 0.5, 0.8)
def set_fog(shape):
shape.set_fog(FOG, 1000.0)
#Load tank
tank_body = pi3d.Model(file_string='models/Tiger/body.obj', sx=0.1, sy=0.1, sz=0.1)
tank_body.set_shader(shader)
tank_body.set_normal_shine(tigerbmp)
""" NB the shadow texture must be the third texture in Buffer.textures
but OffscreenTextures textures don't exists until after they have been
drawn to. This isn't a problem where the textures can be passed to the
draw() method as with the ElevationMap see line 260. However for Model
drawing the diffuse texture is loaded automatically so the botch is to
check if there are still only two texttures and add the shadow map as
the third one see line 177
"""
tank_gun = pi3d.Model(file_string='models/Tiger/gun.obj')
tank_gun.set_shader(shader)
tank_turret = pi3d.Model(file_string='models/Tiger/turret.obj')
tank_turret.set_shader(shader)
tank_turret.set_normal_shine(topbmp)
### because these children will inherit matrix operation applied to
# their parent they don't need to be scaled
tank_body.add_child(tank_turret)
tank_turret.add_child(tank_gun)
#Load church
x, z = 20, -320
y = mymap.calcHeight(x,z)
church = pi3d.Model(file_string='models/AllSaints/AllSaints.obj',
sx=0.1, sy=0.1, sz=0.1, x=x, y=y, z=z)
church.set_shader(shader)
#Load cottages
x, z = 250,-40
y = mymap.calcHeight(x,z)
cottages = pi3d.Model(file_string='models/Cottages/cottages_low.obj',
sx=0.1, sy=0.1, sz=0.1, x=x, y=y, z=z, ry=-5)
cottages.set_shader(shader)
#cross-hairs in gun sight
targtex = pi3d.Texture("textures/target.png", blend=True)
target = pi3d.ImageSprite(targtex, shade2d, w=10, h=10, z=0.4)
target.set_2d_size(targtex.ix, targtex.iy, (DISPLAY.width - targtex.ix)/2,
(DISPLAY.height - targtex.iy)/2)
#telescopic gun sight
sniptex = pi3d.Texture("textures/snipermode.png", blend=True)
sniper = pi3d.ImageSprite(sniptex, shade2d, w=10, h=10, z=0.3)
scx = DISPLAY.width/sniptex.ix
scy = DISPLAY.height/sniptex.iy
if scy > scx:
scx = scy # enlarge to fill screen but use same scale for both directions
scw, sch = sniptex.ix * scx, sniptex.iy * scx
sniper.set_2d_size(scw, sch, (DISPLAY.width - scw)/2,(DISPLAY.height - sch)/2)
#player tank vars
tankrot = 180.0
turret = 0.0
tankroll = 0.0 #side-to-side roll of tank on ground
tankpitch = 0.0 #too and fro pitch of tank on ground
#key presses
mymouse = pi3d.Mouse(restrict = False)
mymouse.start()
omx, omy = mymouse.position()
#position vars
mouserot = 0.0
tilt = 0.0
avhgt = 0.85
xm, oxm = 5.0, -1.0
zm, ozm = -185.0, -1.0
ym = mymap.calcHeight(xm, zm) + avhgt
#ShadowCaster
myshadows = pi3d.ShadowCaster([xm, ym, zm], mylight, scale=5.0)
#enemy tank vars
etx = 20
etz = -100
etr = 70.0
ltm = 0.0 #last pitch roll check
smode = False #sniper mode
def drawTiger(x, y, z, rot, roll, pitch, turret, gunangle, shadows=None):
tank_body.position(x, y, z)
tank_body.rotateToX(pitch)
tank_body.rotateToY(rot-90)
tank_body.rotateToZ(roll)
tank_turret.rotateToY(turret - rot)
tank_gun.rotateToZ(gunangle)
if shadows == None:
if len(tank_body.buf[0].textures) == 2: # i.e. first time drawn add shadow texture
tank_body.buf[0].textures.append(myshadows)
tank_turret.buf[0].textures.append(myshadows)
tank_body.draw(light_camera=myshadows.LIGHT_CAM)
else:
shadows.cast_shadow(tank_body)
# Update display before we begin (user might have moved window)
win.update()
DISPLAY.resize(win.winx, win.winy, win.width, win.height - bord)
is_running = True
try:
while DISPLAY.loop_running():
mx, my = mymouse.position()
mouserot -= (mx-omx)*0.2
tilt += (my-omy)*0.2
omx=mx
omy=my
CAMERA.reset()
sf = 60 - 55.0 / abs(tilt) if tilt < -1 else 5.0
xoff = sf * math.sin(math.radians(mouserot))
yoff = abs(1.25 * sf * math.sin(math.radians(tilt))) + 3.0
zoff = -sf * math.cos(math.radians(mouserot))
if tilt > -5 and smode == False: # zoom in
CAMERA.reset(lens=(1, 3000, 12.5, DISPLAY.width / DISPLAY.height))
smode = True
elif tilt <= -5 and smode == True: # zoom out
CAMERA.reset(lens=(1, 3000, 45, DISPLAY.width / DISPLAY.height))
smode = False
#adjust CAMERA position in and out so we can see our tank
CAMERA.rotate(tilt, mouserot, 0)
CAMERA.position((xm + xoff, ym + yoff + 5, zm + zoff))
oxm, ozm = xm, zm
myshadows.start_cast([xm, ym, zm])
#shadows player tank with smoothing on pitch and roll to lessen jerkiness
tmnow = time.time()
if tmnow > (ltm + 0.5):
tankpitch_to, tankroll_to = mymap.pitch_roll(xm, zm)
tankpitch += (tankpitch_to - tankpitch)/3.0
tankroll += (tankroll_to - tankroll)/3.0
drawTiger(xm, ym, zm, tankrot, tankroll, tankpitch, 180 - turret,
(tilt*-2.0 if tilt > 0.0 else 0.0), shadows=myshadows)
#shadows enemy tank
difx = etx - xm # distance from self
difz = etz - zm
difd = (difx**2 + difz**2)**0.5
detx = 1.5 * difz / difd - 0.005 * (difd - etr) * difx / difd
detz = -1.5 * difx / difd - 0.005 * (difd - etr) * difz / difd
etx += detx # gradually turns to circle player tank
etz += detz
ety = mymap.calcHeight(etx, etz) + avhgt
if tmnow > (ltm + 0.5):
pitch, roll = mymap.pitch_roll(etx, etz)
ltm = tmnow # updating this here but not for users tank relies on everything
# being done in the right order
drawTiger(etx, ety, etz, math.degrees(math.atan2(detx, detz)), roll, pitch, math.degrees(math.atan2(-detz, detx)), 0, shadows=myshadows)
myshadows.cast_shadow(church)
myshadows.cast_shadow(cottages)
myshadows.cast_shadow(mymap)
myshadows.end_cast()
#Tanks and buildings for real
drawTiger(xm, ym, zm, tankrot, tankroll, tankpitch, 180 - turret,
(tilt*-2.0 if tilt > 0.0 else 0.0))
drawTiger(etx, ety, etz, math.degrees(math.atan2(-detx, -detz)), roll, pitch, math.degrees(math.atan2(-detz, detx)), 0)
church.draw()
cottages.draw()
#mymap.draw() # Draw the landscape
mymap.draw(shader, [mountimg1, bumpimg, myshadows], 128.0, 0.0, light_camera=myshadows.LIGHT_CAM)
myecube.position(xm, ym, zm)
myecube.draw() #Draw environment cube
if smode:
""" because some of the overlays have blend=True they must be done AFTER
other objects have been rendered.
"""
target.draw()
sniper.draw()
# turns player tankt turret towards center of screen which will have a crosshairs
if turret + 2.0 < mouserot:
turret += 2.0
if turret - 2.0 > mouserot:
turret -= 2.0
try:
win.update()
except Exception as e:
print("bye,bye2", e)
myshadows.delete_buffers()
DISPLAY.destroy()
try:
win.destroy()
except:
pass
mymouse.stop()
exit()
if win.ev == "resized":
print("resized")
DISPLAY.resize(win.winx, win.winy, win.width, win.height-bord)
CAMERA.reset((DISPLAY.near, DISPLAY.far, DISPLAY.fov,
DISPLAY.width / float(DISPLAY.height)))
win.resized = False
if win.ev == "key":
if win.key == "w":
xm -= math.sin(math.radians(tankrot)) * 2
zm -= math.cos(math.radians(tankrot)) * 2
ym = (mymap.calcHeight(xm, zm) + avhgt)
if win.key == "s":
xm += math.sin(math.radians(tankrot)) * 2
zm += math.cos(math.radians(tankrot)) * 2
ym = (mymap.calcHeight(xm, zm) + avhgt)
if win.key == "a":
tankrot -= 2
if win.key == "d":
tankrot += 2
if win.key == "p":
pi3d.screenshot("TigerTank.jpg")
if win.key == "Escape":
try:
print("bye,bye1")
myshadows.delete_buffers()
DISPLAY.destroy()
try:
win.destroy()
except:
pass
mymouse.stop()
exit()
except:
pass
if win.ev=="drag" or win.ev=="click" or win.ev=="wheel":
xm -= math.sin(math.radians(tankrot)) * 2
zm -= math.cos(math.radians(tankrot)) * 2
ym = (mymap.calcHeight(xm, zm) + avhgt)
else:
win.ev="" #clear the event so it doesn't repeat
except Exception as e:
print("bye,bye3", e)
myshadows.delete_buffers()
DISPLAY.destroy()
try:
win.destroy()
except:
pass
mymouse.stop()
exit()