Visual Servoing Platform  version 3.6.1 under development (2024-10-18)
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 
37 BEGIN_VISP_NAMESPACE
38 
39 const std::string SHADER_VERT_NORMAL_AND_DEPTH_CAMERA =
40 "#version 330\n"
41 "in vec3 p3d_Normal;\n"
42 "in vec4 p3d_Vertex;\n"
43 "uniform mat3 p3d_NormalMatrix;\n"
44 "uniform mat4 p3d_ModelViewMatrix;\n"
45 "uniform mat4 p3d_ModelViewProjectionMatrix;\n"
46 "out vec3 oNormal;\n"
47 "out float distToCamera;\n"
48 "void main()\n"
49 "{\n"
50 " gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\n"
51 " oNormal = p3d_NormalMatrix * normalize(p3d_Normal);\n"
52 " vec4 cs_position = p3d_ModelViewMatrix * p3d_Vertex;\n"
53 " distToCamera = -cs_position.z;\n"
54 "}\n";
55 
56 const std::string SHADER_VERT_NORMAL_AND_DEPTH_OBJECT =
57 "#version 330\n"
58 "in vec3 p3d_Normal;\n"
59 "in vec4 p3d_Vertex;\n"
60 "uniform mat4 p3d_ModelViewMatrix;\n"
61 "uniform mat4 p3d_ModelViewProjectionMatrix;\n"
62 "out vec3 oNormal;\n"
63 "out float distToCamera;\n"
64 "void main()\n"
65 "{\n"
66 " gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\n"
67 " oNormal = vec3(p3d_Normal.x, -p3d_Normal.z, p3d_Normal.y);\n"
68 " vec4 cs_position = p3d_ModelViewMatrix * p3d_Vertex;\n"
69 " distToCamera = -cs_position.z;\n"
70 "}\n";
71 
72 const std::string SHADER_FRAG_NORMAL_AND_DEPTH =
73 "#version 330\n"
74 "in vec3 oNormal;\n"
75 "in float distToCamera;\n"
76 "out vec4 p3d_FragData;\n"
77 "void main()\n"
78 "{\n"
79 " p3d_FragData.bgra = vec4(normalize(oNormal), distToCamera);\n"
80 "}\n";
81 
82 std::string renderTypeToName(vpPanda3DGeometryRenderer::vpRenderType type)
83 {
84  switch (type) {
85  case vpPanda3DGeometryRenderer::vpRenderType::OBJECT_NORMALS:
86  return "normals-world";
87  case vpPanda3DGeometryRenderer::vpRenderType::CAMERA_NORMALS:
88  return "normals-camera";
89  default:
90  return "";
91  }
92 }
93 
94 vpPanda3DGeometryRenderer::vpPanda3DGeometryRenderer(vpRenderType renderType) : vpPanda3DBaseRenderer(renderTypeToName(renderType)), m_renderType(renderType) { }
95 
97 {
98  m_renderRoot = m_window->get_render().attach_new_node(m_name);
99  PT(Shader) shader;
100  if (m_renderType == OBJECT_NORMALS) {
101  shader = Shader::make(Shader::ShaderLanguage::SL_GLSL,
102  SHADER_VERT_NORMAL_AND_DEPTH_OBJECT,
103  SHADER_FRAG_NORMAL_AND_DEPTH);
104  }
105  else if (m_renderType == CAMERA_NORMALS) {
106  shader = Shader::make(Shader::ShaderLanguage::SL_GLSL,
107  SHADER_VERT_NORMAL_AND_DEPTH_CAMERA,
108  SHADER_FRAG_NORMAL_AND_DEPTH);
109  }
110  m_renderRoot.set_shader(shader);
111 }
112 
114 {
115  if (m_window == nullptr) {
116  throw vpException(vpException::fatalError, "Cannot setup render target when window is null");
117  }
118  FrameBufferProperties fbp;
119  fbp.set_rgb_color(true);
120  fbp.set_float_depth(false);
121  fbp.set_float_color(true);
122  fbp.set_depth_bits(16);
123  fbp.set_rgba_bits(32, 32, 32, 32);
124 
125  WindowProperties win_prop;
127  // Don't open a window - force it to be an offscreen buffer.
128  int flags = GraphicsPipe::BF_refuse_window | GraphicsPipe::BF_resizeable | GraphicsPipe::BF_refuse_parasite;
129  GraphicsOutput *windowOutput = m_window->get_graphics_output();
130  GraphicsEngine *engine = windowOutput->get_engine();
131  GraphicsPipe *pipe = windowOutput->get_pipe();
132 
133  m_normalDepthBuffer = engine->make_output(pipe, renderTypeToName(m_renderType), m_renderOrder, fbp, win_prop, flags,
134  windowOutput->get_gsg(), windowOutput);
135 
136  if (m_normalDepthBuffer == nullptr) {
137  throw vpException(vpException::fatalError, "Could not create geometry info buffer");
138  }
139  // if (!m_normalDepthBuffer->is_valid()) {
140  // throw vpException(vpException::fatalError, "Geometry info buffer is invalid");
141  // }
142  m_buffers.push_back(m_normalDepthBuffer);
143  m_normalDepthTexture = new Texture();
144  m_normalDepthBuffer->set_inverted(windowOutput->get_gsg()->get_copy_texture_inverted());
145  fbp.setup_color_texture(m_normalDepthTexture);
146  m_normalDepthTexture->set_format(Texture::F_rgba32);
147  m_normalDepthBuffer->add_render_texture(m_normalDepthTexture, GraphicsOutput::RenderTextureMode::RTM_bind_or_copy, GraphicsOutput::RenderTexturePlane::RTP_color);
148  m_normalDepthBuffer->set_clear_color(LColor(0.f));
149  m_normalDepthBuffer->set_clear_color_active(true);
150  DisplayRegion *region = m_normalDepthBuffer->make_display_region();
151  if (region == nullptr) {
152  throw vpException(vpException::fatalError, "Could not create display region");
153  }
154  region->set_camera(m_cameraPath);
155  region->set_clear_color(LColor(0.f));
156 }
157 
159 {
160  normals.resize(m_normalDepthTexture->get_y_size(), m_normalDepthTexture->get_x_size());
161  depth.resize(m_normalDepthTexture->get_y_size(), m_normalDepthTexture->get_x_size());
162  if (m_normalDepthTexture->get_component_type() != Texture::T_float) {
163  throw vpException(vpException::badValue, "Unexpected data type in normals texture");
164  }
165 
166  int rowIncrement = normals.getWidth() * 4;
167  float *data = (float *)(&(m_normalDepthTexture->get_ram_image().front()));
168  data = data + rowIncrement * (normals.getHeight() - 1);
169  rowIncrement = -rowIncrement;
170 
171  for (unsigned int i = 0; i < normals.getHeight(); ++i) {
172  vpRGBf *normalRow = normals[i];
173  float *depthRow = depth[i];
174  for (unsigned int j = 0; j < normals.getWidth(); ++j) {
175  normalRow[j].R = (data[j * 4]);
176  normalRow[j].G = (data[j * 4 + 1]);
177  normalRow[j].B = (data[j * 4 + 2]);
178  depthRow[j] = (data[j * 4 + 3]);
179  }
180  data += rowIncrement;
181  }
182 }
183 
184 void vpPanda3DGeometryRenderer::getRender(vpImage<vpRGBf> &normals, vpImage<float> &depth, const vpRect &bb, unsigned int h, unsigned w) const
185 {
186  normals.resize(h, w);
187  // memset(normals.bitmap, 0, normals.getSize() * sizeof(vpRGBf));
188  depth.resize(normals.getHeight(), normals.getWidth(), 0.f);
189  // memset(depth.bitmap, 0, normals.getSize());
190 
191  const unsigned top = static_cast<unsigned int>(std::max(0.0, bb.getTop()));
192  const unsigned left = static_cast<unsigned int>(std::max(0.0, bb.getLeft()));
193  const unsigned numComponents = m_normalDepthTexture->get_num_components();
194  const unsigned rowIncrement = m_renderParameters.getImageWidth() * numComponents; // we ask for only 8 bits image, but we may get an rgb image
195  const float *data = (float *)(&(m_normalDepthTexture->get_ram_image().front()));
196  // Panda3D stores data upside down
197  data += rowIncrement * (m_renderParameters.getImageHeight() - 1);
198  if (numComponents != 4) {
199  throw vpException(vpException::dimensionError, "Expected panda texture to have 4 components!");
200  }
201  for (unsigned int i = 0; i < m_renderParameters.getImageHeight(); ++i) {
202  const float *const rowData = data - i * rowIncrement;
203  vpRGBf *normalRow = normals[top + i];
204  float *depthRow = depth[top + i];
205 #pragma omp simd
206  for (unsigned int j = 0; j < m_renderParameters.getImageWidth(); ++j) {
207  normalRow[left + j].R = (rowData[j * 4]);
208  normalRow[left + j].G = (rowData[j * 4 + 1]);
209  normalRow[left + j].B = (rowData[j * 4 + 2]);
210  depthRow[left + j] = (rowData[j * 4 + 3]);
211  }
212  }
213 }
214 
216 {
217  normals.resize(m_normalDepthTexture->get_y_size(), m_normalDepthTexture->get_x_size());
218  if (m_normalDepthTexture->get_component_type() != Texture::T_float) {
219  throw vpException(vpException::badValue, "Unexpected data type in normals texture");
220  }
221 
222  int rowIncrement = normals.getWidth() * 4;
223  float *data = (float *)(&(m_normalDepthTexture->get_ram_image().front()));
224  data = data + rowIncrement * (normals.getHeight() - 1);
225  rowIncrement = -rowIncrement;
226  for (unsigned int i = 0; i < normals.getHeight(); ++i) {
227  vpRGBf *normalRow = normals[i];
228  for (unsigned int j = 0; j < normals.getWidth(); ++j) {
229  normalRow[j].R = (data[j * 4]);
230  normalRow[j].G = (data[j * 4 + 1]);
231  normalRow[j].B = (data[j * 4 + 2]);
232  }
233  data += rowIncrement;
234  }
235 }
236 
238 {
239  depth.resize(m_normalDepthTexture->get_y_size(), m_normalDepthTexture->get_x_size());
240  if (m_normalDepthTexture->get_component_type() != Texture::T_float) {
241  throw vpException(vpException::badValue, "Unexpected data type in normals texture");
242  }
243 
244  int rowIncrement = depth.getWidth() * 4;
245  float *data = (float *)(&(m_normalDepthTexture->get_ram_image().front()));
246  data = data + rowIncrement * (depth.getHeight() - 1);
247  rowIncrement = -rowIncrement;
248 
249  for (unsigned int i = 0; i < depth.getHeight(); ++i) {
250  float *depthRow = depth[i];
251  for (unsigned int j = 0; j < depth.getWidth(); ++j) {
252  depthRow[j] = (data[j * 4 + 3]);
253  }
254  data += rowIncrement;
255  }
256 }
257 
258 END_VISP_NAMESPACE
259 
260 #elif !defined(VISP_BUILD_SHARED_LIBS)
261 // Work around to avoid warning: libvisp_ar.a(vpPanda3DGeometryRenderer.cpp.o) has no symbols
262 void dummy_vpPanda3DGeometryRenderer() { };
263 
264 #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:542
unsigned int getHeight() const
Definition: vpImage.h:181
Base class for a panda3D renderer. This class handles basic functionalities, such as loading object,...
NodePath m_renderRoot
Rendering parameters.
std::string m_name
Inverse of VISP_T_PANDA.
PointerTo< WindowFramework > m_window
Pointer to the active panda framework.
int m_renderOrder
name of the renderer
std::vector< GraphicsOutput * > m_buffers
NodePath of the camera.
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.
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.
vpPanda3DGeometryRenderer(vpRenderType renderType)
@ CAMERA_NORMALS
Surface normals in the object frame.
Definition: vpRGBf.h:60
float B
Blue component.
Definition: vpRGBf.h:142
float G
Green component.
Definition: vpRGBf.h:141
float R
Red component.
Definition: vpRGBf.h:140
Defines a rectangle in the plane.
Definition: vpRect.h:79
double getLeft() const
Definition: vpRect.h:173
double getTop() const
Definition: vpRect.h:192