-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathcamera.cpp
More file actions
118 lines (102 loc) · 3.45 KB
/
camera.cpp
File metadata and controls
118 lines (102 loc) · 3.45 KB
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
#include "sim/camera.h"
#include <math.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <eigen3/Eigen/Eigen>
#include <memory>
#include <set>
#include <stdexcept>
#include <tuple>
#include <utility>
#include "common/Robot.h"
#include "mujoco/mjdata.h"
#include "mujoco/mjmodel.h"
#include "mujoco/mujoco.h"
namespace rcs {
namespace sim {
SimCameraSet::SimCameraSet(std::shared_ptr<Sim> sim, SimCameraSetConfig cfg)
: sim{sim}, cfg{cfg}, buffer{}, buffer_lock{}, cameras{} {
for (auto const& [id, cam] : cfg.cameras) {
this->sim->register_rendering_callback(
[this](const std::string& id, mjrContext& ctx, mjvScene& scene,
mjvOption& opt) { this->frame_callback(id, ctx, scene, opt); },
id, 1.0 / this->cfg.frame_rate, this->cfg.resolution_width,
this->cfg.resolution_height);
mjvCamera mjcam;
mjv_defaultCamera(&mjcam);
if (cam.type == CameraType::default_free) {
mjv_defaultFreeCamera(this->sim->m, &mjcam);
} else {
mjcam.type = cam.type;
mjcam.fixedcamid =
mj_name2id(this->sim->m, mjOBJ_CAMERA, cam.identifier.c_str());
}
cameras[id] = mjcam;
}
}
SimCameraSet::~SimCameraSet() {}
int SimCameraSet::buffer_size() {
std::lock_guard<std::mutex> lock(buffer_lock);
return buffer.size();
}
void SimCameraSet::clear_buffer() {
std::lock_guard<std::mutex> lock(buffer_lock);
// when we clear the buffer, there is no last image timestep
this->last_ts = 0;
buffer.clear();
}
std::optional<FrameSet> SimCameraSet::get_latest_frameset() {
if (buffer.empty()) {
return std::nullopt;
}
std::lock_guard<std::mutex> lock(buffer_lock);
return buffer.back();
}
std::optional<FrameSet> SimCameraSet::get_timestamp_frameset(float ts) {
std::lock_guard<std::mutex> lock(buffer_lock);
for (auto it = buffer.rbegin(); it != buffer.rend(); ++it) {
if (it->timestamp == ts) {
return *it;
}
}
return std::nullopt;
}
void SimCameraSet::frame_callback(const std::string& id, mjrContext& ctx,
mjvScene& scene, mjvOption& opt) {
mjrRect viewport = mjr_maxViewport(&ctx);
int W = viewport.width;
int H = viewport.height;
// allocate rgb and depth buffers
ColorFrame frame = ColorFrame::Zero(3 * W * H);
DepthFrame depth = DepthFrame::Zero(1 * W * H);
// update abstract scene
// TODO: we might be able to call this once for all cameras
// there is also a mjv_updateCamera function
mjv_updateScene(this->sim->m, this->sim->d, &opt, NULL, &this->cameras[id],
mjCAT_ALL, &scene);
// mjv_updateCamera(this->sim->m, this->sim->d, &this->cameras[id], &scene);
// render scene in offscreen buffer
mjr_render(viewport, &scene, &ctx);
// read rgb and depth buffers
// depth documentation can be found here:
// https://registry.khronos.org/OpenGL-Refpages/gl4/html/glReadPixels.xhtml
mjr_readPixels(frame.data(), depth.data(), viewport, &ctx);
auto ts = this->sim->d->time;
std::lock_guard<std::mutex> lock(buffer_lock);
// The following code assumes that all render callbacks for a timestep
// happen directly after each other
if (this->last_ts == ts) {
buffer[buffer.size() - 1].color_frames[id] = frame;
buffer[buffer.size() - 1].depth_frames[id] = depth;
} else {
FrameSet fs;
fs.timestamp = ts;
fs.color_frames[id] = frame;
fs.depth_frames[id] = depth;
buffer.push_back(fs);
this->last_ts = ts;
}
}
} // namespace sim
} // namespace rcs