forked from IntelRealSense/librealsense
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rs-gl.cpp
250 lines (205 loc) · 8.93 KB
/
rs-gl.cpp
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
// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015-2017 Intel Corporation. All Rights Reserved.
#include <librealsense2/rs.hpp> // Include RealSense Cross Platform API
#include "example.hpp" // Include short list of convenience functions for rendering
#include <librealsense2-gl/rs_processing_gl.hpp> // Include GPU-Processing API
// Helper functions
void register_glfw_callbacks(window& app, glfw_state& app_state);
void prepare_matrices(glfw_state& app_state, float width, float height, float* projection, float* view);
bool handle_input(window& app, bool& use_gpu_processing);
// This helper class will be used to keep track of FPS and print instructions:
struct instructions_printer
{
instructions_printer();
void print_instructions(window& app, bool use_gpu_processing);
std::chrono::high_resolution_clock::time_point last_clock;
int rendered_frames;
int last_fps;
};
int main(int argc, char * argv[]) try
{
// The following toggle is going to control
// if we will use CPU or GPU for depth data processing
bool use_gpu_processing = true;
// Create a simple OpenGL window for rendering:
window app(1280, 720, "RealSense GPU-Processing Example");
// Once we have a window, initialize GL module
// Pass our window to enable sharing of textures between processed frames and the window
rs2::gl::init_processing(app, use_gpu_processing);
// Initialize rendering module:
rs2::gl::init_rendering();
// Construct an object to manage view state
glfw_state app_state;
// register callbacks to allow manipulation of the pointcloud
register_glfw_callbacks(app, app_state);
texture tex; // For when not using GPU frames, we will need standard texture object
// to render pointcloud texture (similar to pointcloud example)
instructions_printer printer;
// Every iteration the demo will render 3D pointcloud that will be stored in points object:
rs2::points points;
// The pointcloud will use colorized depth as a texture:
rs2::frame depth_texture;
// ---- Declare GL processing blocks ----
rs2::gl::pointcloud pc; // similar to rs2::pointcloud
rs2::gl::colorizer colorizer; // similar to rs2::colorizer
rs2::gl::uploader upload; // used to explicitly copy frame to the GPU
// ---- Declare rendering block ----
rs2::gl::pointcloud_renderer pc_renderer; // Will handle rendering points object to the screen
// We will manage two matrices - projection and view
// to handle mouse input and perspective
float proj_matrix[16];
float view_matrix[16];
// Enable pipeline
rs2::pipeline pipe;
rs2::config cfg;
// For this example, we are only interested in depth:
cfg.enable_stream(RS2_STREAM_DEPTH, RS2_FORMAT_Z16);
pipe.start(cfg);
while (app) // Application still alive?
{
// Any new frames?
rs2::frameset frames;
if (pipe.poll_for_frames(&frames))
{
auto depth = frames.get_depth_frame();
// Since both colorizer and pointcloud are going to use depth
// It helps to explicitly upload it to the GPU
// Otherwise, each block will upload the same depth to GPU separately
// [ This step is optional, but can speed things up on some cards ]
// The result of this step is still a rs2::depth_frame,
// but now it is also extendible to rs2::gl::gpu_frame
depth = upload.process(depth);
// Apply color map with histogram equalization
depth_texture = colorizer.colorize(depth);
// Tell pointcloud object to map to this color frame
pc.map_to(depth_texture);
// Generate the pointcloud and texture mappings
points = pc.calculate(depth);
}
// Populate projection and view matrices based on user input
prepare_matrices(app_state,
app.width(), app.height(),
proj_matrix, view_matrix);
// We need to get OpenGL texture ID for pointcloud texture
uint32_t texture_id = 0;
// First, check if the frame is already a GPU-frame
if (auto gpu_frame = depth_texture.as<rs2::gl::gpu_frame>())
{
// If it is (and you have passed window for sharing to init_processing
// you can just get the texture ID of the GPU frame
texture_id = gpu_frame.get_texture_id(0);
}
else
{
// Otherwise, we need to upload texture like in all other examples
tex.upload(depth_texture);
texture_id = tex.get_gl_handle();
}
// Clear screen
glClearColor(0.2f, 0.2f, 0.2f, 1.f);
glClear(GL_DEPTH_BUFFER_BIT);
// We need Depth-Test unless you want pointcloud to intersect with itself
glEnable(GL_DEPTH_TEST);
// Set texture to our selected texture ID
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_id);
// Inform pointcloud-renderer of the projection and view matrices:
pc_renderer.set_matrix(RS2_GL_MATRIX_PROJECTION, proj_matrix);
pc_renderer.set_matrix(RS2_GL_MATRIX_TRANSFORMATION, view_matrix);
// If we have something to render, use pointcloud-renderer to do it
if (points) pc_renderer.process(points);
// Disable texturing
glDisable(GL_TEXTURE_2D);
// Print textual information
printer.print_instructions(app, use_gpu_processing);
// Handle user input and check if reset is required
if (handle_input(app, use_gpu_processing))
{
// First, shutdown processing and rendering
rs2::gl::shutdown_rendering();
rs2::gl::shutdown_processing();
// Next, reinitialize processing and rendering with new settings
rs2::gl::init_processing(app, use_gpu_processing);
rs2::gl::init_rendering();
}
}
return EXIT_SUCCESS;
}
catch (const rs2::error & e)
{
std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << std::endl;
return EXIT_FAILURE;
}
catch (const std::exception & e)
{
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
instructions_printer::instructions_printer()
{
// Initialize running clock to keep track of time (for FPS calculation)
auto last_clock = std::chrono::high_resolution_clock::now();
int rendered_frames = 0; // Counts number of frames since last update
int last_fps = 0; // Stores last calculated FPS
glfwSwapInterval(0); // This is functionally disabling V-Sync,
// allowing application FPS to go beyond monitor refresh rate
}
void instructions_printer::print_instructions(window& app, bool use_gpu_processing)
{
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glOrtho(0, app.width(), app.height(), 0, -1, +1);
glColor3f(1.f, 1.f, 1.f);
std::stringstream ss;
ss << "Performing Point-Cloud and Histogram-Equalization (Colorize) on the " << (use_gpu_processing ? "GPU" : "CPU");
draw_text(20, 20, ss.str().c_str());
ss.str("");
ss << "( Press " << (use_gpu_processing ? "[C] - Switch to processing on the CPU )" : "[G] - Switch to processing on the GPU )");
draw_text(20, 36, ss.str().c_str());
ss.str("");
ss << "This demo is being rendered at " << last_fps << " frames per second, ~" << (1000 / (last_fps + 1)) << "ms for single rendered frame";
draw_text(20, 52, ss.str().c_str());
rendered_frames++;
auto since_last_clock = std::chrono::high_resolution_clock::now() - last_clock;
auto sec_elapsed = std::chrono::duration_cast<std::chrono::seconds>(since_last_clock).count();
if (sec_elapsed > 0)
{
last_clock = std::chrono::high_resolution_clock::now();
last_fps = rendered_frames;
rendered_frames = 0;
}
}
bool handle_input(window& app, bool& use_gpu_processing)
{
bool reset = false;
if (glfwGetKey(app, GLFW_KEY_C) == GLFW_PRESS)
{
reset = use_gpu_processing;
use_gpu_processing = false;
}
if (glfwGetKey(app, GLFW_KEY_G) == GLFW_PRESS)
{
reset = !use_gpu_processing;
use_gpu_processing = true;
}
return reset;
}
void prepare_matrices(glfw_state& app_state, float width, float height, float* projection, float* view)
{
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluPerspective(60, width / height, 0.01f, 10.0f);
glGetFloatv(GL_PROJECTION_MATRIX, projection);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
gluLookAt(0, 0, 0, 0, 0, 1, 0, -1, 0);
glTranslatef(0, 0, 0.5f + app_state.offset_y * 0.05f);
glRotated(app_state.pitch, 1, 0, 0);
glRotated(app_state.yaw, 0, 1, 0);
glTranslatef(0, 0, -0.5f);
glGetFloatv(GL_MODELVIEW_MATRIX, view);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}