-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcamera.py
executable file
·256 lines (228 loc) · 9.67 KB
/
camera.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
from math import cos, pi
from panda3d.core import Vec3, LVector3f, Mat4
from yyagl.gameobject import GameObject
from yyagl.engine.vec import Vec
class Camera(GameObject):
speed = 50
inertia_dist = 15
speed_slow = 20
speed_fast = 5000
dist_min = 24
dist_max = 48 # 24
look_dist_min = 2 # 0
look_dist_max = 16 # 0
overwrite = [0, 0, 0] # [8, 8, 1]
def __init__(self, car_np, cam_vec, car):
GameObject.__init__(self)
self.car_np = car_np
self.cam_vec = cam_vec # eye to look_at
self.curr_look_dist = 0
self.curr_speed_ratio = 0
self.fwd_car_vec = LVector3f(0, 0, 0)
self.curr_dist = 0
self.curr_h = 0
self.car = car
base.camLens.set_near_far(1.0, 1000.0)
@staticmethod
def ease(val):
if val <= 0: ret_val = 0
elif val >= 1: ret_val = 1
else: ret_val = 1 - cos(val * pi)
return ret_val
def curr_speed(self, pos, tgt):
dist = (tgt - pos).length()
easeval = self.ease(dist / self.inertia_dist)
inertia_fact = max(0, min(1, easeval)) if dist else 0
return self.speed * inertia_fact
def get_camera(self):
regions = base.win.get_active_display_regions()
if self.eng.cfg.dev_cfg.shaders_dev:
return self.eng.shader_mgr.filter_mgr.camera
if self.eng.cfg.dev_cfg.pbr: return base.camera
return regions[self.car.player_car_idx].get_camera()
@staticmethod
def new_val(val, tgt, incr):
beyond = abs(val - tgt) < incr
next_val = lambda: val + (1 if tgt > val else -1) * incr
return tgt if beyond else next_val()
@staticmethod
def new_val_vec(vec_val, vec_tgt, incr):
val_els = [vec_val.x, vec_val.y, vec_val.z]
tgt_els = [vec_tgt.x, vec_tgt.y, vec_tgt.z]
res = []
for val, tgt in zip(val_els, tgt_els):
beyond = abs(val - tgt) > incr
fit_p = lambda val=val, tgt=tgt: \
val + (1 if tgt > val else -1) * incr
res += [fit_p() if beyond else tgt]
return LVector3f(* res)
@property
def _back_vec_z(self):
dist_diff = self.dist_max - self.dist_min
return self.dist_min + dist_diff * self.curr_speed_ratio
def _new_pos(self, look_at_pos, back_car_vec, curr_l, c_i_length, c_i_rot):
d_t = globalClock.get_dt()
cam_pos = self.get_camera().get_pos()
vec = cam_pos - look_at_pos
prj_vec = Vec3(vec.x, vec.y, 0).normalized()
prj_back_car_vec = Vec3(back_car_vec.x, back_car_vec.y, 0).normalized()
angle = prj_vec.signed_angle_deg(prj_back_car_vec, (0, 0, 1))
rot_angle = self.new_val(0, angle, c_i_rot)
new_vec = prj_vec.normalized()
rot_new_vec = self.__rotate(new_vec, rot_angle * d_t)
# new_vec_l = self.new_val(prj_vec.length(), prj_back_car_vec.length(),
# c_i_length * d_t)
new_vec = rot_new_vec * curr_l
new_pos = look_at_pos + new_vec
new_pos.z = self.new_val(cam_pos.z, look_at_pos.z + back_car_vec.z,
8 * d_t)
return new_pos
@staticmethod
def __rotate(vec, deg):
rot_mat = Mat4()
rot_mat.set_rotate_mat(deg, (0, 0, 1))
return rot_mat.xform_vec(vec)
def update(self, speed_ratio, is_rolling, is_fast, is_rotating):
d_t = globalClock.get_dt()
self.curr_speed_ratio = self.new_val(self.curr_speed_ratio,
speed_ratio, 1 * d_t)
dist_diff = self.dist_max - self.dist_min
look_dist_diff = self.look_dist_max - self.look_dist_min
gfx_root = self.eng.gfx.root
fwd_car_vec = gfx_root.get_relative_vector(self.car_np, Vec3(0, 1, 0))
fwd_car_vec.normalize()
fwd_incr = (.05 if is_rotating else .5) * d_t
self.fwd_car_vec = self.new_val_vec(self.fwd_car_vec, fwd_car_vec,
fwd_incr)
self.curr_dist = self.new_val(
self.curr_dist, self.dist_min + dist_diff * self.curr_speed_ratio,
10.0 * d_t)
back_car_vec = -fwd_car_vec * self.curr_dist
car_pos = self.car_np.get_pos()
back_car_vec += (0, 0, self._back_vec_z)
tmp_back_pos = car_pos + back_car_vec
curr_gnd_h = self.gnd_height(tmp_back_pos)
if curr_gnd_h and tmp_back_pos.z < curr_gnd_h + .5:
back_car_vec.z = curr_gnd_h - car_pos.z + .5
l_d_speed = self.look_dist_min + look_dist_diff * self.curr_speed_ratio
l_d = 0 if is_rolling else l_d_speed
cam_pos = self.get_camera().get_pos()
curr_incr = self.curr_speed(cam_pos, car_pos + back_car_vec) * d_t
curr_incr_slow = self.speed_slow * d_t
if is_fast: curr_incr_slow = self.speed_fast * d_t
self.curr_look_dist = self.new_val(self.curr_look_dist, l_d,
curr_incr_slow)
tgt_vec = self.fwd_car_vec * self.curr_look_dist
curr_wp = self.car.logic.closest_wp().next
if curr_wp.node.has_tag('camera'):
cam_forced_pos = curr_wp.node.get_tag('camera')
cam_forced_pos = cam_forced_pos.split(',')
cam_forced_pos = (float(elm) for elm in cam_forced_pos)
cam_forced_pos = Vec3(*cam_forced_pos)
cam_forced_vec = cam_forced_pos - curr_wp.pos
cam_forced_vec.normalize()
cam_forced_vec *= back_car_vec.length()
back_car_vec = cam_forced_vec
c_i = curr_incr_slow if is_fast else curr_incr
look_at_pos = car_pos + tgt_vec
new_pos = self._new_pos(look_at_pos, back_car_vec, self.curr_dist, c_i,
20)
# overwrite camera's position to set the physics
if any(val for val in self.overwrite):
ovw = self.overwrite
new_pos = car_pos.x + ovw[0], car_pos.y + ovw[1], \
car_pos.z + ovw[2]
if not is_rolling: self.get_camera().set_pos(new_pos)
self.get_camera().look_at(car_pos + tgt_vec)
@property
def camera(self): return self.get_camera()
def gnd_height(self, pos):
phys_root = self.eng.phys_mgr.root
bottompos = pos - (0, 0, 100)
bottom = Vec(bottompos.x, bottompos.y, bottompos.z)
toppos = pos + (0, 0, 100)
top = Vec(toppos.x, toppos.y, toppos.z)
hits = phys_root.ray_test_all(bottom, top)
for hit in hits.get_hits():
prefs = ['RoadOBJ', 'OffroadOBJ']
if any(hit.getNode().getName().startswith(pref) for pref in prefs):
return hit.getHitPos().z
return 0
# def render_all(self, track_model):
# workaround for premunge_scene in 1.9
# self.get_camera().set_pos(0, 0, 10000)
# self.get_camera().look_at(0, 0, 0)
# skydome = track_model.find('**/OBJSkydome*')
# info('skydome %sfound' % ('' if skydome else 'not '))
# if skydome: skydome.hide()
# base.graphicsEngine.render_frame()
# base.graphicsEngine.render_frame()
# if skydome: skydome.show()
def destroy(self):
GameObject.destroy(self)
class FPCamera(Camera):
dist_min = 16
dist_max = 24
height = 8
def __init__(self, car_np, cam_vec, car):
Camera.__init__(self, car_np, cam_vec, car)
def _new_pos(self, look_at_pos, back_car_vec, curr_l, c_i_length, c_i_rot):
car_pos = self.car_np.get_pos()
curr_cam_pos = car_pos + back_car_vec
curr_occl = self.__occlusion_mesh(curr_cam_pos)
is_occl = False
if curr_occl:
occl_pos = curr_occl.getHitPos()
back_car_vec = occl_pos - car_pos
is_occl = True
if not is_occl:
# cam_vec = car_pos - curr_cam_pos
look_at_pos = car_pos # + tgt_vec
new_pos = Camera._new_pos(self, look_at_pos, back_car_vec,
self.curr_dist, c_i_length, 20)
else:
new_pos = occl_pos
return new_pos
@property
def _back_vec_z(self):
return self.height
def __occlusion_mesh(self, pos):
tgt = self.car.gfx.nodepath.get_pos()
occl = self.__closest_occl(pos, tgt)
if not occl:
return None
car_vec = self.car.logic.car_vec
rot_mat_left = Mat4()
rot_mat_left.setRotateMat(90, (0, 0, 1))
car_vec_left = rot_mat_left.xformVec(car_vec._vec)
# access to a protected member
tgt_left = tgt + car_vec_left
pos_left = pos + car_vec_left
occl_left = self.__closest_occl(pos_left, tgt_left)
if not occl_left:
return None
rot_mat_right = Mat4()
rot_mat_right.setRotateMat(-90, (0, 0, 1))
car_vec_right = rot_mat_right.xformVec(car_vec._vec)
# access to a protected member
car_vec_right += (0, 0, 2)
tgt_right = tgt + car_vec_right
pos_right = pos + car_vec_right
phys_root = self.eng.phys_mgr.root
occl_right = phys_root.ray_test_closest(tgt_right, pos_right)
occl_right = self.__closest_occl(pos_right, tgt_right)
if not occl_right:
return None
return occl
def __closest_occl(self, pos, tgt):
occl = None
dist = 9999
tgtv = Vec(tgt.x, tgt.y, tgt.z)
posv = Vec(pos.x, pos.y, pos.z)
occl_l = self.eng.phys_mgr.root.ray_test_all(tgtv, posv) # , mask)
for _occl in occl_l.get_hits():
if _occl.getNode().getName() not in ['Vehicle', 'Goal']:
if (Vec(*_occl.getHitPos()) - tgtv).length() < dist:
dist = (Vec(*_occl.getHitPos()) - tgtv).length()
occl = _occl
return occl