Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpPanda3DGeometryRenderer.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 */
30
31#include <visp3/core/vpConfig.h>
32
33#if defined(VISP_HAVE_PANDA3D)
34
35#include <visp3/ar/vpPanda3DGeometryRenderer.h>
36#include "windowFramework.h"
37#include "graphicsOutput.h"
38#include "graphicsEngine.h"
39#include "graphicsBuffer.h"
40
42
43const std::string SHADER_VERT_NORMAL_AND_DEPTH_CAMERA =
44"#version 330\n"
45"in vec3 p3d_Normal;\n"
46"in vec4 p3d_Vertex;\n"
47"uniform mat3 p3d_NormalMatrix;\n"
48"uniform mat4 p3d_ModelViewMatrix;\n"
49"uniform mat4 p3d_ModelViewProjectionMatrix;\n"
50"out vec3 oNormal;\n"
51"out float distToCamera;\n"
52"void main()\n"
53"{\n"
54" gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\n"
55" oNormal = p3d_NormalMatrix * normalize(p3d_Normal);\n"
56" vec4 cs_position = p3d_ModelViewMatrix * p3d_Vertex;\n"
57" distToCamera = -cs_position.z;\n"
58"}\n";
59
60const std::string SHADER_VERT_NORMAL_AND_DEPTH_OBJECT =
61"#version 330\n"
62"in vec3 p3d_Normal;\n"
63"in vec4 p3d_Vertex;\n"
64"uniform mat4 p3d_ModelViewMatrix;\n"
65"uniform mat4 p3d_ModelViewProjectionMatrix;\n"
66"out vec3 oNormal;\n"
67"out float distToCamera;\n"
68"void main()\n"
69"{\n"
70" gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\n"
71" oNormal = vec3(p3d_Normal.x, -p3d_Normal.z, p3d_Normal.y);\n"
72" vec4 cs_position = p3d_ModelViewMatrix * p3d_Vertex;\n"
73" distToCamera = -cs_position.z;\n"
74"}\n";
75
76const std::string SHADER_FRAG_NORMAL_AND_DEPTH =
77"#version 330\n"
78"in vec3 oNormal;\n"
79"in float distToCamera;\n"
80"out vec4 p3d_FragData;\n"
81"void main()\n"
82"{\n"
83" p3d_FragData.bgra = vec4(normalize(oNormal), distToCamera);\n"
84"}\n";
85
86
87const std::string SHADER_FRAG_NORMAL_AND_DEPTH_FAST =
88"#version 330\n"
89"in vec3 oNormal;\n"
90"in float distToCamera;\n"
91"out vec4 p3d_FragData;\n"
92"uniform float nearV;\n"
93"uniform float farV;\n"
94"void main()\n"
95"{\n"
96" //float depthV = distToCamera <= nearV ? 0.0 : (distToCamera - nearV) / (farV - nearV);\n"
97" float depthV = distToCamera / farV;\n"
98" vec3 n = normalize(oNormal);\n"
99" n = (n + 1.0) / 2.0;\n"
100" p3d_FragData.bgra = vec4(n, depthV);\n"
101"}\n";
102
103
104std::string renderTypeToName(vpPanda3DGeometryRenderer::vpRenderType type)
105{
106 switch (type) {
108 return "normals-world";
110 return "normals-camera";
111 default:
112 return "";
113 }
114}
115
117{
118 if (m_fast) {
119 m_renderRoot.set_shader_input("nearV", LVector2f(m_renderParameters.getNearClippingDistance()));
120 m_renderRoot.set_shader_input("farV", LVector2f(m_renderParameters.getFarClippingDistance()));
121 }
122
123}
124
125vpPanda3DGeometryRenderer::vpPanda3DGeometryRenderer(vpRenderType renderType, bool fast) : vpPanda3DBaseRenderer(renderTypeToName(renderType)), m_renderType(renderType), m_fast(fast) { }
126
128{
129 m_renderRoot = m_window->get_render().attach_new_node(m_name);
130 PT(Shader) shader;
131 if (m_renderType == OBJECT_NORMALS) {
132 shader = Shader::make(Shader::ShaderLanguage::SL_GLSL,
133 SHADER_VERT_NORMAL_AND_DEPTH_OBJECT,
134 m_fast ? SHADER_FRAG_NORMAL_AND_DEPTH_FAST : SHADER_FRAG_NORMAL_AND_DEPTH);
135 }
136 else if (m_renderType == CAMERA_NORMALS) {
137 shader = Shader::make(Shader::ShaderLanguage::SL_GLSL,
138 SHADER_VERT_NORMAL_AND_DEPTH_CAMERA,
139 m_fast ? SHADER_FRAG_NORMAL_AND_DEPTH_FAST : SHADER_FRAG_NORMAL_AND_DEPTH);
140 }
141 m_renderRoot.set_shader(shader);
142}
143
145{
146 if (m_window == nullptr) {
147 throw vpException(vpException::fatalError, "Cannot setup render target when window is null");
148 }
149 FrameBufferProperties fbp;
150 if (!m_fast) {
151 fbp.set_rgb_color(true);
152 fbp.set_float_depth(false);
153 fbp.set_float_color(true);
154 fbp.set_depth_bits(16);
155 fbp.set_rgba_bits(32, 32, 32, 32);
156 }
157 else {
158 fbp.set_rgb_color(true);
159 fbp.set_float_depth(false);
160 fbp.set_float_color(false);
161 fbp.set_depth_bits(16);
162 fbp.set_rgba_bits(8, 8, 8, 8);
163 }
164
165 WindowProperties win_prop;
166 win_prop.set_size(m_renderParameters.getImageWidth(), m_renderParameters.getImageHeight());
167 // Don't open a window - force it to be an offscreen buffer.
168 int flags = GraphicsPipe::BF_refuse_window | GraphicsPipe::BF_resizeable;
169 GraphicsOutput *windowOutput = m_window->get_graphics_output();
170 GraphicsEngine *engine = windowOutput->get_engine();
171 GraphicsPipe *pipe = windowOutput->get_pipe();
172
173 static int id = 0;
174 m_normalDepthBuffer = engine->make_output(pipe, renderTypeToName(m_renderType) + std::to_string(id), m_renderOrder, fbp, win_prop, flags,
175 windowOutput->get_gsg(), windowOutput);
176 m_normalDepthTexture = new Texture("geometry texture " + std::to_string(id));
177 ++id;
178 if (m_normalDepthBuffer == nullptr) {
179 throw vpException(vpException::fatalError, "Could not create geometry info buffer");
180 }
181 // if (!m_normalDepthBuffer->is_valid()) {
182 // throw vpException(vpException::fatalError, "Geometry info buffer is invalid");
183 // }
184 m_buffers.push_back(m_normalDepthBuffer);
185 m_normalDepthBuffer->set_inverted(windowOutput->get_gsg()->get_copy_texture_inverted());
186 // fbp.setup_color_texture(m_normalDepthTexture);
187 if (!m_fast) {
188 m_normalDepthTexture->set_format(Texture::F_rgba32);
189 }
190 else {
191 m_normalDepthTexture->set_component_type(Texture::T_unsigned_byte);
192 m_normalDepthTexture->set_format(Texture::F_rgba);
193 }
194 m_normalDepthBuffer->add_render_texture(m_normalDepthTexture, GraphicsOutput::RenderTextureMode::RTM_copy_texture, GraphicsOutput::RenderTexturePlane::RTP_color);
195 m_normalDepthBuffer->set_clear_color(LColor(0.f));
196 m_normalDepthBuffer->set_clear_color_active(true);
197
198 DisplayRegion *region = m_normalDepthBuffer->make_display_region();
199 if (region == nullptr) {
200 throw vpException(vpException::fatalError, "Could not create display region");
201 }
202 region->set_camera(m_cameraPath);
203 region->set_clear_color(LColor(0.f));
204}
205
207{
208 normals.resize(m_normalDepthTexture->get_y_size(), m_normalDepthTexture->get_x_size());
209 depth.resize(m_normalDepthTexture->get_y_size(), m_normalDepthTexture->get_x_size());
210
211 const unsigned numComponents = m_normalDepthTexture->get_num_components();
212 if (numComponents != 4) {
213 throw vpException(vpException::dimensionError, "Expected panda texture to have 4 components!");
214 }
215
216 int rowIncrement = normals.getWidth() * 4;
217
218 if (!m_fast) {
219 using T = float;
220 T *data = (T *)(&(m_normalDepthTexture->get_ram_image().front()));
221 data = data + rowIncrement * (normals.getHeight() - 1);
222#if defined(VISP_HAVE_OPENMP)
223#pragma omp parallel for
224#endif
225 for (int i = 0; i < static_cast<int>(normals.getHeight()); ++i) {
226 const T *const rowData = data - i * rowIncrement;
227
228 vpRGBf *normalRow = normals[i];
229 float *depthRow = depth[i];
230 for (unsigned int j = 0; j < normals.getWidth(); ++j) {
231 normalRow[j].R = (rowData[j * 4]);
232 normalRow[j].G = (rowData[j * 4 + 1]);
233 normalRow[j].B = (rowData[j * 4 + 2]);
234 depthRow[j] = (rowData[j * 4 + 3]);
235 }
236 }
237 }
238 else {
239 float farV = m_renderParameters.getFarClippingDistance();
240 using T = uint8_t;
241 Texture::ComponentType expectedComponent = Texture::T_unsigned_byte;
242 float maxValue = static_cast<float>(std::numeric_limits<T>::max());
243 const T *data = (T *)(&(m_normalDepthTexture->get_ram_image().front()));
244 // Panda3D stores data upside down
245 data += rowIncrement * (m_renderParameters.getImageHeight() - 1);
246
247 if (m_normalDepthTexture->get_component_type() != expectedComponent) {
248 throw vpException(vpException::badValue, "Unexpected data type in normals texture");
249 }
250#if defined(VISP_HAVE_OPENMP)
251#pragma omp parallel for
252#endif
253 for (int i = 0; i < static_cast<int>(normals.getHeight()); ++i) {
254 const T *const rowData = data - i * rowIncrement;
255 vpRGBf *normalRow = normals[i];
256 float *depthRow = depth[i];
257 std::array<float, 3> v;
258 for (int j = 0; j < static_cast<int>(normals.getWidth()); ++j) {
259 int j_4 = j * 4;
260 v[0] = (static_cast<float>(rowData[j_4]) / maxValue) * 2.f - 1.f;
261 v[1] = (static_cast<float>(rowData[j_4 + 1]) / maxValue) * 2.f - 1.f;
262 v[2] = (static_cast<float>(rowData[j_4 + 2]) / maxValue) * 2.f - 1.f;
263 // const double norm = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
264
265 normalRow[j].R = v[0];
266 normalRow[j].G = v[1];
267 normalRow[j].B = v[2];
268 depthRow[j] = (static_cast<float>(rowData[j_4 + 3]) / maxValue) * farV;
269 }
270 }
271 }
272}
273
274void vpPanda3DGeometryRenderer::getRender(vpImage<vpRGBf> &normals, vpImage<float> &depth, const vpRect &bb, unsigned int h, unsigned w) const
275{
276 normals.resize(h, w);
277 // memset(normals.bitmap, 0, normals.getSize() * sizeof(vpRGBf));
278 depth.resize(normals.getHeight(), normals.getWidth(), 0.f);
279 // memset(depth.bitmap, 0, normals.getSize());
280
281 const unsigned top = static_cast<unsigned int>(std::max(0.0, bb.getTop()));
282 const unsigned left = static_cast<unsigned int>(std::max(0.0, bb.getLeft()));
283 const unsigned numComponents = m_normalDepthTexture->get_num_components();
284 const unsigned rowIncrement = m_renderParameters.getImageWidth() * numComponents; // we ask for only 8 bits image, but we may get an rgb image
285
286
287 int image_width = static_cast<int>(std::min(m_renderParameters.getImageWidth(), w - left));
288 int image_height = std::min(m_renderParameters.getImageHeight(), h - top);
289
290 if (!m_fast) {
291 const float *data = (float *)(&(m_normalDepthTexture->get_ram_image().front()));
292 // Panda3D stores data upside down
293 data += rowIncrement * (m_renderParameters.getImageHeight() - 1);
294 if (numComponents != 4) {
295 throw vpException(vpException::dimensionError, "Expected panda texture to have 4 components!");
296 }
297 if (m_normalDepthTexture->get_component_type() != Texture::T_float) {
298 throw vpException(vpException::badValue, "Unexpected data type in normals texture");
299 }
300#if defined(VISP_HAVE_OPENMP)
301#pragma omp parallel for
302#endif
303 for (int i = 0; i < image_height; ++i) {
304 const float *const rowData = data - i * rowIncrement;
305 vpRGBf *normalRow = normals[top + i];
306 float *depthRow = depth[top + i];
307 for (int j = 0; j < image_width; ++j) {
308 int left_j = left + j;
309 int j_4 = j * 4;
310 normalRow[left_j].R = (rowData[j_4]);
311 normalRow[left_j].G = (rowData[j_4 + 1]);
312 normalRow[left_j].B = (rowData[j_4 + 2]);
313 depthRow[left_j] = (rowData[j_4 + 3]);
314 }
315 }
316 }
317 else {
318 float farV = m_renderParameters.getFarClippingDistance();
319 using T = uint8_t;
320 Texture::ComponentType expectedComponent = Texture::T_unsigned_byte;
321 float maxValue = static_cast<float>(std::numeric_limits<T>::max());
322 const T *data = (T *)(&(m_normalDepthTexture->get_ram_image().front()));
323 // Panda3D stores data upside down
324 data += rowIncrement * (m_renderParameters.getImageHeight() - 1);
325
326 if (numComponents != 4) {
327 throw vpException(vpException::dimensionError, "Expected panda texture to have 4 components!");
328 }
329 if (m_normalDepthTexture->get_component_type() != expectedComponent) {
330 throw vpException(vpException::badValue, "Unexpected data type in normals texture");
331 }
332
333 for (int i = 0; i < image_height; ++i) {
334 const T *const rowData = data - i * rowIncrement;
335 vpRGBf *normalRow = normals[top + i];
336 float *depthRow = depth[top + i];
337 std::array<float, 3> v;
338 for (int j = 0; j < image_width; ++j) {
339 int left_j = left + j;
340 int j_4 = j * 4;
341 v[0] = (static_cast<float>(rowData[j_4]) / maxValue) * 2.f - 1.f;
342 v[1] = (static_cast<float>(rowData[j_4 + 1]) / maxValue) * 2.f - 1.f;
343 v[2] = (static_cast<float>(rowData[j_4 + 2]) / maxValue) * 2.f - 1.f;
344 // const double norm = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
345 normalRow[left_j].R = v[0];
346 normalRow[left_j].G = v[1];
347 normalRow[left_j].B = v[2];
348 depthRow[left_j] = (static_cast<float>(rowData[j_4 + 3]) / maxValue) * farV;
349 }
350 }
351 }
352
353}
354
356{
357
358 normals.resize(m_normalDepthTexture->get_y_size(), m_normalDepthTexture->get_x_size());
359 int rowIncrement = normals.getWidth() * 4;
360 if (!m_fast) {
361 if (m_normalDepthTexture->get_component_type() != Texture::T_float) {
362 throw vpException(vpException::badValue, "Unexpected data type in normals texture");
363 }
364
365 float *data = (float *)(&(m_normalDepthTexture->get_ram_image().front()));
366 data = data + rowIncrement * (normals.getHeight() - 1);
367 for (unsigned int i = 0; i < normals.getHeight(); ++i) {
368 const float *const rowData = data - i * rowIncrement;
369 vpRGBf *normalRow = normals[i];
370 for (unsigned int j = 0; j < normals.getWidth(); ++j) {
371 normalRow[j].R = (rowData[j * 4]);
372 normalRow[j].G = (rowData[j * 4 + 1]);
373 normalRow[j].B = (rowData[j * 4 + 2]);
374 }
375 }
376 }
377 else {
378 using T = uint8_t;
379 Texture::ComponentType expectedComponent = Texture::T_unsigned_byte;
380 float maxValue = static_cast<float>(std::numeric_limits<T>::max());
381 const T *data = (T *)(&(m_normalDepthTexture->get_ram_image().front()));
382 // Panda3D stores data upside down
383 data += rowIncrement * (m_renderParameters.getImageHeight() - 1);
384
385 if (m_normalDepthTexture->get_component_type() != expectedComponent) {
386 throw vpException(vpException::badValue, "Unexpected data type in normals texture");
387 }
388
389 for (unsigned int i = 0; i < normals.getHeight(); ++i) {
390 const T *const rowData = data - i * rowIncrement;
391 vpRGBf *normalRow = normals[i];
392 std::array<float, 3> v;
393 for (int j = 0; j < static_cast<int>(normals.getWidth()); ++j) {
394 int j_4 = j * 4;
395 v[0] = (static_cast<float>(rowData[j_4]) / maxValue) * 2.f - 1.f;
396 v[1] = (static_cast<float>(rowData[j_4 + 1]) / maxValue) * 2.f - 1.f;
397 v[2] = (static_cast<float>(rowData[j_4 + 2]) / maxValue) * 2.f - 1.f;
398 normalRow[j].R = v[0];
399 normalRow[j].G = v[1];
400 normalRow[j].B = v[2];
401 }
402 }
403 }
404}
405
407{
408
409 depth.resize(m_normalDepthTexture->get_y_size(), m_normalDepthTexture->get_x_size());
410 int rowIncrement = depth.getWidth() * 4;
411
412 if (!m_fast) {
413 if (m_normalDepthTexture->get_component_type() != Texture::T_float) {
414 throw vpException(vpException::badValue, "Unexpected data type in normals texture");
415 }
416
417 float *data = (float *)(&(m_normalDepthTexture->get_ram_image().front()));
418 data = data + rowIncrement * (depth.getHeight() - 1);
419
420 for (unsigned int i = 0; i < depth.getHeight(); ++i) {
421 const float *const rowData = data - i * rowIncrement;
422 float *depthRow = depth[i];
423 for (unsigned int j = 0; j < depth.getWidth(); ++j) {
424 depthRow[j] = (rowData[j * 4 + 3]);
425 }
426 }
427
428 }
429 else {
430 float farV = m_renderParameters.getFarClippingDistance();
431 using T = uint8_t;
432 Texture::ComponentType expectedComponent = Texture::T_unsigned_byte;
433 float maxValue = static_cast<float>(std::numeric_limits<T>::max());
434 const T *data = (T *)(&(m_normalDepthTexture->get_ram_image().front()));
435 // Panda3D stores data upside down
436 data += rowIncrement * (m_renderParameters.getImageHeight() - 1);
437
438 if (m_normalDepthTexture->get_component_type() != expectedComponent) {
439 throw vpException(vpException::badValue, "Unexpected data type in normals texture");
440 }
441
442 for (unsigned int i = 0; i < depth.getHeight(); ++i) {
443 const T *const rowData = data - i * rowIncrement;
444 float *depthRow = depth[i];
445
446 for (int j = 0; j < static_cast<int>(depth.getWidth()); ++j) {
447 int j_4 = j * 4;
448 depthRow[j] = (static_cast<float>(rowData[j_4 + 3]) / maxValue) * farV;
449 }
450 }
451 }
452}
453
454END_VISP_NAMESPACE
455
456#elif !defined(VISP_BUILD_SHARED_LIBS)
457// Work around to avoid warning: libvisp_ar.a(vpPanda3DGeometryRenderer.cpp.o) has no symbols
458void dummy_vpPanda3DGeometryRenderer() { }
459
460#endif
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ badValue
Used to indicate that a value is not in the allowed range.
Definition vpException.h:73
@ dimensionError
Bad dimension.
Definition vpException.h:71
@ fatalError
Fatal error.
Definition vpException.h:72
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition vpImage.h:544
unsigned int getHeight() const
Definition vpImage.h:181
vpPanda3DBaseRenderer(const std::string &rendererName)
NodePath m_renderRoot
Rendering parameters.
std::string m_name
Inverse of VISP_T_PANDA.
std::vector< PointerTo< GraphicsOutput > > m_buffers
NodePath of the camera.
PointerTo< WindowFramework > m_window
Rendering priority for this renderer and its buffers. A lower value will be rendered first....
int m_renderOrder
name of the renderer
vpPanda3DRenderParameters m_renderParameters
Pointer to owning window, which can create buffers etc. It is not necessarily visible.
void getRender(vpImage< vpRGBf > &colorData, vpImage< float > &depth) const
Get render results into ViSP readable structures.
vpPanda3DGeometryRenderer(vpRenderType renderType, bool fast=true)
void setupScene() VP_OVERRIDE
Initialize the scene for this specific renderer.
void setupRenderTarget() VP_OVERRIDE
Initialize buffers and other objects that are required to save the render.
@ CAMERA_NORMALS
Surface normals in the object frame.
float B
Blue component.
Definition vpRGBf.h:161
float G
Green component.
Definition vpRGBf.h:160
float R
Red component.
Definition vpRGBf.h:159
Defines a rectangle in the plane.
Definition vpRect.h:79