multimodalart's picture
multimodalart HF Staff
prep stage
1811aab verified
Raw History Blame Contribute Delete
5.05 kB
"""Third-person camera: open-code-world-model's FollowCamera, kept out of solid scenery.
FollowCamera (critically damped boom + stiffer aim, subject held at a fixed screen position) is the
camera that produces test-time proxies, so training clips use it with parameters drawn from the
ranges open-code calibrated against the released examples. open-code has no walls; here the boom is
shortened to stay clear of them:
* rays from the protagonist's head, hips and knees to the camera and to points 0.3 m around it
(one head-to-camera ray passed over a low wall and left the camera inside its cap stone)
* thin things -- posts, signs, passers-by -- only count right at the camera (they used to yank it
in by 1-3 m within one frame, ~450 such pops in dataset_v1; now it neither pops nor passes
through them)
* the boom length is rate-limited: in at <= 4 m/s, out at <= 1.5 m/s
* a shortened boom re-aims at the point FollowCamera was looking at (keeping the long boom's
angles put the protagonist out of frame at wall corners during the turn-round)
"""
from __future__ import annotations
import math
import carla
from ... import paths
from ..geometry import carla_to_renderer, renderer_to_carla
HIP_TO_FEET = 0.93 # walker actor origin is at the hips
EYE_ABOVE_HIP = 0.75
RAY_ORIGINS = (0.75, 0.0, -0.45) # head, hips, knees (relative to the actor origin)
RAY_SPREAD = 0.3
BOOM_IN_SPEED, BOOM_OUT_SPEED = 4.0, 1.5
MIN_BOOM_M = 0.8
YAW_TAU = 0.25
def sample_params(rng) -> dict:
return dict(distance=rng.uniform(1.8, 4.0), height=rng.uniform(1.3, 2.5), aim_height=0.875,
aim_screen_x=rng.uniform(0.36, 0.58), aim_screen_y=rng.uniform(0.51, 0.57),
focal_px=206.6, boom_tau=0.70, zeta=0.50, aim_tau=0.15)
class FollowRig:
def __init__(self, world, hero, params: dict):
paths.use_ocwm()
from compiler.follow import FollowCamera
self.world, self.hero, self.params = world, hero, params
self.follow = FollowCamera(**params)
self.yaw = None # smoothed walking direction
self.k = None # current boom fraction (1 = full length)
L = carla.CityObjectLabel
self.thin = {getattr(L, n) for n in ("Poles", "TrafficSigns", "TrafficLight", "Pedestrians", "Rider", "Other")
if hasattr(L, n)}
def _heading(self, ht, dt):
v = self.hero.get_velocity()
head = ht.rotation.yaw if math.hypot(v.x, v.y) < 0.3 else math.degrees(math.atan2(v.y, v.x))
if self.yaw is None:
self.yaw = head
self.yaw += ((head - self.yaw + 180.0) % 360.0 - 180.0) * (1.0 - math.exp(-dt / YAW_TAU))
return self.yaw
def _clear_fraction(self, ht, want, d, dist):
side = carla.Location(x=-d.y / dist, y=d.x / dist, z=0.0)
offs = [carla.Location()] + [side * s for s in (RAY_SPREAD, -RAY_SPREAD)] + \
[carla.Location(z=s) for s in (RAY_SPREAD, -RAY_SPREAD)]
k = 1.0
for oz in RAY_ORIGINS:
o = ht.location + carla.Location(z=oz)
for off in offs:
tgt = want + off
seg = o.distance(tgt)
for h in self.world.cast_ray(o, tgt):
t = h.location.distance(o)
if t > 0.4 and (h.label not in self.thin or t > seg - 0.6):
k = min(k, max(0.25, (t - 0.35) / seg))
return max(k, min(1.0, MIN_BOOM_M / dist))
def pose(self, dt: float) -> carla.Transform:
ht = self.hero.get_transform()
feet = ht.location + carla.Location(z=-HIP_TO_FEET)
c = self.follow.update(carla_to_renderer([feet.x, feet.y, feet.z]), self._heading(ht, dt), dt)
p0 = carla.Location(*renderer_to_carla(c.position))
want = p0
eye = ht.location + carla.Location(z=EYE_ABOVE_HIP)
d = want - eye
dist = math.sqrt(d.x ** 2 + d.y ** 2 + d.z ** 2)
if dist > 0.5:
k = self._clear_fraction(ht, want, d, dist)
if self.k is None: # first frame: no history to rate-limit against
self.k = k
if k < self.k:
self.k = max(k, self.k - BOOM_IN_SPEED * dt / dist)
else:
self.k = min(k, self.k + BOOM_OUT_SPEED * dt / dist)
if self.k < 1.0:
want = eye + carla.Location(x=d.x * self.k, y=d.y * self.k, z=d.z * self.k)
pitch, yaw = c.pitch_deg, c.yaw_deg
if want.distance(p0) > 0.01:
pr, yr = math.radians(pitch), math.radians(yaw)
f0 = carla.Location(x=math.cos(pr) * math.cos(yr), y=math.cos(pr) * math.sin(yr), z=math.sin(pr))
aim = feet + carla.Location(z=self.params["aim_height"])
v = (p0 + f0 * p0.distance(aim)) - want
yaw = math.degrees(math.atan2(v.y, v.x))
pitch = math.degrees(math.atan2(v.z, math.hypot(v.x, v.y)))
return carla.Transform(want, carla.Rotation(pitch=pitch, yaw=yaw))