Skip to content

Commit 4baf851

Browse files
committed
add support for log replay
1 parent 2d034df commit 4baf851

7 files changed

Lines changed: 4093 additions & 32 deletions

File tree

GEMstack/onboard/visualization/sr_viz/threeD/components/Car.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ export class Car {
7979
this.group.position.copy(this.position);
8080
this.group.rotation.y = this.heading;
8181
}
82+
updateFromLog(logData) {
83+
if (!this.group) return;
84+
this.velocity = logData.velocity;
85+
this.acceleration = logData.acceleration;
86+
this.steerAngle = logData.steering_wheel_angle;
87+
this.position.set(logData.position[1], logData.position[2], logData.position[0]);
88+
this.heading = logData.rotation[1];
89+
this.group.position.copy(this.position);
90+
this.group.rotation.y = this.heading;
91+
}
8292

8393

8494
dispose() {

GEMstack/onboard/visualization/sr_viz/threeD/components/Human.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const HUMAN_LEG_LENGTH = HUMAN_HEIGHT * HUMAN_BODY_RATIOS.leg;
1111
const HUMAN_LEG_COLOR = 0x555555;
1212

1313
export default class Human {
14-
constructor(color = 0x00aaff, position = { x: 0, y: 0, z: 0 }) {
14+
constructor(color = 0x00aaff, position = { x: 0, y: 0, z: 0 }, rotation = 0) {
1515
this.group = new THREE.Group();
1616

1717
const bodyGeometry = new THREE.BoxGeometry(HUMAN_BODY_LENGTH / 1.2, HUMAN_BODY_LENGTH, HUMAN_BODY_LENGTH / 1.6);
@@ -60,10 +60,17 @@ export default class Human {
6060
this.group.add(this.leftLeg, this.rightLeg);
6161

6262
this.group.position.set(position.x, position.y, position.z);
63+
this.group.rotation.y = rotation;
6364

64-
this.walkingSpeed = 0.03;
65+
this.walkingSpeed = 0;
6566
this.walkingPhase = 0;
6667
}
68+
updateFromLog(logData) {
69+
if (!this.group) return;
70+
this.group.position.set(logData.position[1], logData.position[2], logData.position[0]);
71+
this.group.rotation.y = logData.rotation[1];
72+
this.walkingSpeed = logData.velocity;
73+
}
6774

6875
walk() {
6976
this.walkingPhase += this.walkingSpeed;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
export default class LogReader {
2+
constructor(logData, scene, createFuncs) {
3+
this.framerate = logData.framerate || 60;
4+
this.totalFrames = logData.totalFrames || 0;
5+
this.frames = logData.data || [];
6+
this.scene = scene;
7+
this.currentFrame = 0;
8+
this.playing = true;
9+
this.createFuncs = createFuncs;
10+
this.models = {}
11+
this.car = null;
12+
for (const type of Object.keys(createFuncs)) {
13+
this.models[type] = new Map();
14+
}
15+
}
16+
17+
update(dt) {
18+
if (!this.playing) return;
19+
20+
const frameData = this.frames[this.currentFrame];
21+
if (!frameData) return;
22+
23+
frameData.objects.forEach(obj => {
24+
const id = obj.id;
25+
const type = obj.type;
26+
const position = obj.position;
27+
if (this.models[type].has(id)) {
28+
const model = this.models[type].get(id);
29+
if ((type === 'vehicle' && obj.frame === 0) || type !== 'vehicle') {
30+
model.updateFromLog(obj);
31+
}
32+
} else {
33+
const createFunc = this.createFuncs[type];
34+
if (createFunc) {
35+
const orientation = obj.orientation || obj.misc.orientation;
36+
const model = createFunc(position[1], position[2], position[0], orientation);
37+
if (type === 'vehicle' && id === 0) {
38+
this.car = model;
39+
}
40+
this.models[type].set(id, model);
41+
}
42+
}
43+
});
44+
45+
this.currentFrame++;
46+
if (this.currentFrame >= this.frames.length) {
47+
this.playing = false;
48+
}
49+
}
50+
51+
reset() {
52+
this.currentFrame = 0;
53+
this.playing = true;
54+
}
55+
56+
pause() {
57+
this.playing = false;
58+
}
59+
60+
play() {
61+
this.playing = true;
62+
}
63+
}

GEMstack/onboard/visualization/sr_viz/threeD/components/RoadVehicleViz.vue

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,19 @@ import Human from "@/components/Human.js";
1717
import {
1818
CAR_MODEL_PATH,
1919
TRAFFIC_LIGHT_MODEL_PATH,
20+
ENV_MAP_PATH,
21+
ENV_MAP_NAME,
2022
} from "../utils/constants.js";
23+
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
24+
import LogReader from "@/components/LogReader.js";
25+
import logJson1 from "@/logs/final_log_1.json";
26+
import logJson2 from "@/logs/final_log_2.json";
27+
import logJson3 from "@/logs/final_log_3.json";
2128
2229
const container = ref(null);
2330
const camera = ref(null);
24-
const cameraMode = ref("free");
25-
let scene, renderer, controls;
31+
const cameraMode = ref("follow");
32+
let scene, renderer, controls, logReader;
2633
2734
let car, roadGeometry, roadMaterial;
2835
let lastTime = performance.now();
@@ -32,26 +39,32 @@ let trafficLights = [];
3239
let carIdx = 0;
3340
3441
const keys = { forward: false, backward: false, left: false, right: false };
42+
const createFuncs = {
43+
'vehicle': createCar,
44+
'pedestrian': createHuman,
45+
'traffic_light': createTrafficLight,
46+
}
3547
3648
onMounted(() => {
3749
window.addEventListener("keydown", handleKeyDown);
3850
window.addEventListener("keyup", handleKeyUp);
3951
window.addEventListener("keypress", handleKeyPress);
4052
4153
initScene();
42-
car = createCar(0, 0, 0, Math.PI / 2);
43-
for (let i = 0; i < 4; i++) {
44-
const offset = (i + 1) * 10;
45-
createCar(
46-
offset,
47-
0,
48-
(i % 2 === 0 ? -1 : 1) * (Math.random() * 5),
49-
Math.PI / 2
50-
);
51-
}
52-
createTrafficLight(0, 0, 5);
53-
createHuman(-3, 0, 4);
54-
createHuman(2, 0, 6);
54+
logReader = new LogReader(logJson2, scene, createFuncs);
55+
// car = createCar(0, 0, 0, Math.PI / 2);
56+
// for (let i = 0; i < 4; i++) {
57+
// const offset = (i + 1) * 10;
58+
// createCar(
59+
// offset,
60+
// 0,
61+
// (i % 2 === 0 ? -1 : 1) * (Math.random() * 5),
62+
// Math.PI / 2
63+
// );
64+
// }
65+
// createTrafficLight(0, 0, 5);
66+
// createHuman(-3, 0, 4);
67+
// createHuman(2, 0, 6);
5568
animate();
5669
});
5770
@@ -61,19 +74,20 @@ function createCar(x, y, z, heading) {
6174
return newCar;
6275
}
6376
64-
function createTrafficLight(x, y, z) {
77+
function createTrafficLight(x, y, z, rotation) {
6578
const newTrafficLight = new TrafficLight(
6679
TRAFFIC_LIGHT_MODEL_PATH,
6780
{ x: x, y: y, z: z },
81+
rotation,
6882
loadCallBack
6983
);
7084
trafficLights.push(newTrafficLight);
7185
return newTrafficLight;
7286
}
7387
74-
function createHuman(x, y, z) {
88+
function createHuman(x, y, z, rotation) {
7589
const color = Math.random() * 0xffffff;
76-
const newHuman = new Human(color, { x: x, y: y, z: z });
90+
const newHuman = new Human(color, { x: x, y: y, z: z }, rotation);
7791
scene.add(newHuman.group);
7892
humans.push(newHuman);
7993
return newHuman;
@@ -167,9 +181,16 @@ function initScene() {
167181
controls = new OrbitControls(camera.value, renderer.domElement);
168182
controls.enableDamping = true;
169183
170-
const light = new THREE.DirectionalLight(0xffffff, 1);
171-
light.position.set(5, 10, 5);
172-
scene.add(light);
184+
new RGBELoader()
185+
.setPath(ENV_MAP_PATH)
186+
.load(ENV_MAP_NAME, (texture) => {
187+
texture.mapping = THREE.EquirectangularReflectionMapping;
188+
scene.environment = texture;
189+
});
190+
191+
// const light = new THREE.DirectionalLight(0xffffff, 1);
192+
// light.position.set(5, 10, 5);
193+
// scene.add(light);
173194
scene.add(new THREE.HemisphereLight(0xffffbb, 0x080820, 1));
174195
175196
loadRoad();
@@ -208,7 +229,7 @@ function loadRoad() {
208229
209230
scene.add(roadMesh);
210231
211-
createRoadLines();
232+
// createRoadLines();
212233
}
213234
214235
function createRoadLines() {
@@ -245,8 +266,9 @@ function createRoadLines() {
245266
}
246267
247268
function updateCamera() {
248-
if (!car || !car.group) return;
269+
if (!logReader || !logReader.car || !logReader.car.group) return;
249270
if (cameraMode.value === "free") return;
271+
const car = logReader.car;
250272
251273
const carPosition = car.group.position;
252274
const carDirection = new THREE.Vector3();
@@ -271,9 +293,12 @@ function animate() {
271293
const dt = (currentTime - lastTime) / 1000;
272294
lastTime = currentTime;
273295
274-
if (car) {
275-
car.update(keys, dt);
296+
if (logReader) {
297+
logReader.update(dt);
276298
}
299+
// if (car) {
300+
// car.update(keys, dt);
301+
// }
277302
// for (const h of humans) {
278303
// h.walk();
279304
// }
@@ -287,6 +312,12 @@ function onWindowResize() {
287312
camera.value.updateProjectionMatrix();
288313
renderer.setSize(window.innerWidth, window.innerHeight);
289314
}
315+
onBeforeUnmount(() => {
316+
window.removeEventListener("keydown", handleKeyDown);
317+
window.removeEventListener("keyup", handleKeyUp);
318+
window.removeEventListener("keypress", handleKeyPress);
319+
window.removeEventListener("resize", onWindowResize);
320+
});
290321
</script>
291322

292323
<style>

GEMstack/onboard/visualization/sr_viz/threeD/components/TrafficLight.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
6565
const SCALE_RATE = 1;
6666

6767
export default class TrafficLight {
68-
constructor(modelPath, position = { x: 0, y: 0, z: 0 }, onLoadCallback) {
68+
constructor(modelPath, position = { x: 0, y: 0, z: 0 }, rotation = 0, onLoadCallback) {
6969
this.position = new THREE.Vector3(position.x, position.y, position.z);
7070
// this.durations = {
7171
// red: 5,
@@ -82,14 +82,13 @@ export default class TrafficLight {
8282

8383
this.group.position.set(this.position.x, this.position.y, this.position.z);
8484
this.group.scale.set(SCALE_RATE, SCALE_RATE, SCALE_RATE);
85+
this.group.rotation.y = rotation;
8586

8687
if (onLoadCallback) onLoadCallback(this);
8788
},
8889
undefined,
8990
(error) => console.error("Error loading traffic light model:", error)
9091
);
9192
}
92-
// update() {
93-
94-
// }
93+
updateFromLog(logData) { }
9594
}

0 commit comments

Comments
 (0)