Visual Servoing Platform  version 3.6.1 under development (2024-10-18)
vpPanda3DRGBRenderer.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/ar/vpPanda3DRGBRenderer.h>
32 
33 #if defined(VISP_HAVE_PANDA3D)
34 
35 #include "orthographicLens.h"
36 #include "cardMaker.h"
37 #include "texturePool.h"
38 
39 BEGIN_VISP_NAMESPACE
40 const char *vpPanda3DRGBRenderer::COOK_TORRANCE_VERT =
41 "#version 330\n"
42 "in vec3 p3d_Normal;\n"
43 "in vec4 p3d_Vertex;\n"
44 "out vec3 oNormal;\n"
45 "out vec4 viewVertex;\n"
46 "uniform mat3 p3d_NormalMatrix;\n"
47 "uniform mat4 p3d_ModelViewMatrix;\n"
48 "uniform mat4 p3d_ModelViewProjectionMatrix;\n"
49 "in vec2 p3d_MultiTexCoord0;\n"
50 "out vec2 texcoords;\n"
51 "out vec3 F0;\n"
52 "uniform struct p3d_MaterialParameters {\n"
53 " vec4 ambient;\n"
54 " vec4 diffuse;\n"
55 " vec4 emission;\n"
56 " vec3 specular;\n"
57 " float shininess;\n"
58 " // These properties are new in 1.10.\n"
59 " vec4 baseColor;\n"
60 " float roughness;\n"
61 " float metallic;\n"
62 " float refractiveIndex;\n"
63 "} p3d_Material;\n"
64 "vec3 computeF0(float ior, float metallic, vec3 baseColor)\n"
65 "{\n"
66 " float F0f = pow(abs((1.0 - ior) / (1.0 + ior)), 2.0);\n"
67 " vec3 F0 = vec3(F0f, F0f, F0f);\n"
68 " return mix(F0, baseColor, metallic);\n"
69 "}\n"
70 "void main()\n"
71 "{\n"
72 " gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\n"
73 " oNormal = p3d_NormalMatrix * normalize(p3d_Normal);\n"
74 " viewVertex = p3d_ModelViewMatrix * p3d_Vertex;\n"
75 " texcoords = p3d_MultiTexCoord0;\n"
76 " F0 = computeF0(p3d_Material.refractiveIndex, p3d_Material.metallic, p3d_Material.baseColor.xyz);\n"
77 "}\n";
78 
79 const char *vpPanda3DRGBRenderer::COOK_TORRANCE_FRAG =
80 "// Version 330, specified when generating shader\n"
81 "#define M_PI 3.1415926535897932384626433832795\n"
82 "in vec3 oNormal;\n"
83 "in vec4 viewVertex;\n"
84 "in vec3 F0;\n"
85 "out vec4 p3d_FragData;\n"
86 "uniform struct {\n"
87 " vec4 ambient;\n"
88 "} p3d_LightModel;\n"
89 "uniform struct p3d_LightSourceParameters {\n"
90 " // Primary light color.\n"
91 " vec4 color;\n"
92 " // View-space position. If w=0, this is a directional light, with the xyz\n"
93 " // being -direction.\n"
94 " vec4 position;\n"
95 " // constant, linear, quadratic attenuation in one vector\n"
96 " vec3 attenuation;\n"
97 "} p3d_LightSource[4];\n"
98 "uniform struct p3d_MaterialParameters {\n"
99 " vec4 ambient;\n"
100 " vec4 diffuse;\n"
101 " vec4 emission;\n"
102 " vec3 specular;\n"
103 " float shininess;\n"
104 " // These properties are new in 1.10.\n"
105 " vec4 baseColor;\n"
106 " float roughness;\n"
107 " float metallic;\n"
108 " float refractiveIndex;\n"
109 "} p3d_Material;\n"
110 "in vec2 texcoords;\n"
111 "#ifdef HAS_TEXTURE\n"
112 "uniform sampler2D p3d_Texture0;\n"
113 "#endif\n"
114 "float D(float roughness2, float hn)\n"
115 "{\n"
116 " return (1.f / (M_PI * roughness2)) * pow(hn, (2.f / roughness2) - 2.f);\n"
117 "}\n"
118 "float G(float hn, float nv, float nl, float vh)\n"
119 "{\n"
120 " return min(1.0, min((2.f * hn * nv) / vh, (2.f * hn * nl) / vh));\n"
121 "}\n"
122 "vec3 F(vec3 F0, float vh)\n"
123 "{\n"
124 " return F0 + (vec3(1.f, 1.f, 1.f) - F0) * pow(1.f - vh, 5);\n"
125 "}\n"
126 "void main()\n"
127 "{\n"
128 " vec3 n = normalize(oNormal); // normalized normal vector\n"
129 " vec3 v = normalize(-viewVertex.xyz); // normalized view vector\n"
130 " float nv = max(0.f, dot(n, v));\n"
131 " float roughness2 = clamp(pow(p3d_Material.roughness, 2), 0.01, 0.99);\n"
132 
133 " #ifdef HAS_TEXTURE\n"
134 " vec4 baseColor = texture(p3d_Texture0, texcoords);\n"
135 " vec4 ambientColor = baseColor;\n"
136 " #else\n"
137 " vec4 ambientColor = p3d_Material.ambient;\n"
138 " vec4 baseColor = p3d_Material.baseColor;\n"
139 " #endif\n"
140 " p3d_FragData = p3d_LightModel.ambient * baseColor;\n"
141 " for(int i = 0; i < p3d_LightSource.length(); ++i) {\n"
142 " vec3 lf = p3d_LightSource[i].position.xyz - (viewVertex.xyz * p3d_LightSource[i].position.w);\n"
143 " float lightDist = length(lf);\n"
144 " vec3 l = normalize(lf); // normalized light vector\n"
145 " vec3 h = normalize(l + v); // half way vector\n"
146 " float hn = dot(h, n);\n"
147 " float nl = max(0.f, dot(n, l));\n"
148 " float vh = max(0.f, dot(v, h));\n"
149 " vec3 aFac = p3d_LightSource[i].attenuation;\n"
150 " float attenuation = 1.f / (aFac[0] + aFac[1] * lightDist + aFac[2] * lightDist * lightDist);\n"
151 " vec3 FV = F(F0, vh);\n"
152 " vec3 kd = (1.f - p3d_Material.metallic) * (1.f - FV) * (1.f / M_PI);\n"
153 " #ifdef SPECULAR\n"
154 " vec3 specularColor = vec3(0.f, 0.f, 0.f);\n"
155 " if(nl > 0.f && nv > 0.f) {\n"
156 " float DV = D(roughness2, hn);\n"
157 " float GV = G(hn, nv, nl, vh);\n"
158 " vec3 rs = (DV * GV * FV) / (4.f * nl * nv);\n"
159 " specularColor = rs * p3d_Material.specular;\n"
160 " }\n"
161 " #else\n"
162 " vec3 specularColor = vec3(0.0, 0.0, 0.0);\n"
163 " #endif\n"
164 " p3d_FragData += (p3d_LightSource[i].color * attenuation) * nl * (baseColor * vec4(kd, 1.f) + vec4(specularColor, 1.f));\n"
165 " }\n"
166 " p3d_FragData.bgra = p3d_FragData;\n"
167 "}\n";
168 
169 std::string vpPanda3DRGBRenderer::makeFragmentShader(bool hasTexture, bool specular)
170 {
171  std::stringstream ss;
172  ss << "#version 330" << std::endl;
173  if (hasTexture) {
174  ss << "#define HAS_TEXTURE 1" << std::endl;
175  }
176  if (specular) {
177  ss << "#define SPECULAR 1" << std::endl;
178  }
179  else {
180  ss << "#undef SPECULAR" << std::endl;
181  }
182  ss << vpPanda3DRGBRenderer::COOK_TORRANCE_FRAG;
183  return ss.str();
184 }
185 
186 void vpPanda3DRGBRenderer::addNodeToScene(const NodePath &object)
187 {
188  NodePath objectInScene = object.copy_to(m_renderRoot);
189  objectInScene.set_name(object.get_name());
190  TextureCollection txs = objectInScene.find_all_textures();
191  bool hasTexture = (static_cast<unsigned int>(txs.size()) > 0);
192  // gltf2bam and other tools may store some fallback textures. We shouldnt use them as they whiten the result
193  if (hasTexture) {
194  std::vector<std::string> fallbackNames { "pbr-fallback", "normal-fallback", "emission-fallback" };
195  unsigned int numMatches = 0;
196  for (const std::string &fallbackName: fallbackNames) {
197  numMatches += static_cast<int>(txs.find_texture(fallbackName) != nullptr);
198  }
199  hasTexture = (static_cast<unsigned int>(txs.size()) > numMatches); // Some textures are not fallback textures
200  }
201 
202  PT(Shader) shader = Shader::make(Shader::ShaderLanguage::SL_GLSL,
203  COOK_TORRANCE_VERT,
204  makeFragmentShader(hasTexture, m_showSpeculars));
205 
206  objectInScene.set_shader(shader);
207 
208  setNodePose(objectInScene, vpHomogeneousMatrix());
209 }
210 
212 {
213 
214  if (m_display2d == nullptr) {
215  CardMaker cm("card");
216  cm.set_frame_fullscreen_quad();
217 
218  NodePath myCamera2d(new Camera("myCam2d"));
219  PT(OrthographicLens) lens = new OrthographicLens();
220  lens->set_film_size(2, 2);
221  lens->set_near_far(-1000, 1000);
222  lens->set_film_offset(0, 0);
223  ((Camera *)myCamera2d.node())->set_lens(lens);
224 
225  NodePath myRender2d("myRender2d");
226  myRender2d.set_depth_test(false);
227  myRender2d.set_depth_write(false);
228  myCamera2d.reparent_to(myRender2d);
229  m_backgroundImage = myRender2d.attach_new_node(cm.generate());
230 
231  m_display2d = m_colorBuffer->make_display_region();
232  m_display2d->set_sort(-100);
233  m_display2d->set_camera(myCamera2d);
234  }
235  if (m_backgroundTexture == nullptr) {
236  m_backgroundTexture = new Texture();
237  }
238  m_backgroundImage.set_texture(m_backgroundTexture);
239  m_backgroundTexture->setup_2d_texture(background.getWidth(), background.getHeight(),
240  Texture::ComponentType::T_unsigned_byte,
241  Texture::Format::F_rgba8);
242  //m_backgroundTexture = TexturePool::load_texture("/home/sfelton/IMG_20230221_165330430.jpg");
243  unsigned char *data = (unsigned char *)m_backgroundTexture->modify_ram_image();
244 
245  for (unsigned int i = 0; i < background.getHeight(); ++i) {
246  const vpRGBa *srcRow = background[background.getHeight() - (i + 1)];
247  unsigned char *destRow = data + i * background.getWidth() * 4;
248  for (unsigned int j = 0; j < background.getWidth(); ++j) {
249  destRow[j * 4] = srcRow[j].B;
250  destRow[j * 4 + 1] = srcRow[j].G;
251  destRow[j * 4 + 2] = srcRow[j].R;
252  destRow[j * 4 + 3] = srcRow[j].A;
253  }
254  }
255 }
256 
258 {
259  I.resize(m_colorTexture->get_y_size(), m_colorTexture->get_x_size());
260  unsigned char *data = (unsigned char *)(&(m_colorTexture->get_ram_image().front()));
261  int rowIncrement = I.getWidth() * 4;
262  // Panda3D stores the image using the OpenGL convention (origin is bottom left),
263  // while we store data with origin as upper left. We copy with a flip
264  data = data + rowIncrement * (I.getHeight() - 1);
265  rowIncrement = -rowIncrement;
266 
267  for (unsigned int i = 0; i < I.getHeight(); ++i) {
268  vpRGBa *colorRow = I[i];
269 
270  memcpy((unsigned char *)(colorRow), data, sizeof(unsigned char) * 4 * I.getWidth());
271  // for (unsigned int j = 0; j < I.getWidth(); ++j) {
272  // // BGRA order in panda3d
273  // colorRow[j].R = data[j * 4];
274  // colorRow[j].G = data[j * 4 + 1];
275  // colorRow[j].B = data[j * 4 + 2];
276  // colorRow[j].A = data[j * 4 + 3];
277  // }
278  data += rowIncrement;
279  }
280 }
281 
283 {
286 }
287 
289 {
290  if (m_window == nullptr) {
291  throw vpException(vpException::fatalError, "Cannot setup render target when window is null");
292  }
293  FrameBufferProperties fbp;
294  fbp.set_rgb_color(true);
295  fbp.set_float_depth(false);
296  fbp.set_float_color(false);
297  fbp.set_depth_bits(16);
298  fbp.set_rgba_bits(8, 8, 8, 8);
299  fbp.set_srgb_color(true);
300 
301  WindowProperties win_prop;
303 
304  // Don't open a window - force it to be an offscreen buffer.
305  int flags = GraphicsPipe::BF_refuse_window | GraphicsPipe::BF_resizeable;
306  GraphicsOutput *windowOutput = m_window->get_graphics_output();
307  GraphicsEngine *engine = windowOutput->get_engine();
308  GraphicsStateGuardian *gsg = windowOutput->get_gsg();
309  GraphicsPipe *pipe = windowOutput->get_pipe();
310  m_colorBuffer = engine->make_output(pipe, "Color Buffer", m_renderOrder,
311  fbp, win_prop, flags,
312  gsg, windowOutput);
313  if (m_colorBuffer == nullptr) {
314  throw vpException(vpException::fatalError, "Could not create color buffer");
315  }
316  m_buffers.push_back(m_colorBuffer);
317  //m_colorBuffer->set_inverted(gsg->get_copy_texture_inverted());
318  m_colorTexture = new Texture();
319  fbp.setup_color_texture(m_colorTexture);
320  //m_colorTexture->set_format(Texture::Format::F_srgb_alpha);
321  m_colorBuffer->add_render_texture(m_colorTexture, GraphicsOutput::RenderTextureMode::RTM_copy_texture);
322  m_colorBuffer->set_clear_color(LColor(0.f));
323  m_colorBuffer->set_clear_color_active(true);
324  DisplayRegion *region = m_colorBuffer->make_display_region();
325  if (region == nullptr) {
326  throw vpException(vpException::fatalError, "Could not create display region");
327  }
328  region->set_camera(m_cameraPath);
329  region->set_clear_color(LColor(0.f));
330 }
331 
332 END_VISP_NAMESPACE
333 
334 #elif !defined(VISP_BUILD_SHARED_LIBS)
335 // Work around to avoid warning: libvisp_ar.a(vpPanda3DRGBRenderer.cpp.o) has no symbols
336 void dummy_vpPanda3DRGBRenderer() { };
337 
338 #endif
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ fatalError
Fatal error.
Definition: vpException.h:72
Implementation of an homogeneous matrix and operations on such kind of matrices.
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
virtual void setupScene()
Initialize the scene for this specific renderer.
NodePath m_renderRoot
Rendering parameters.
PointerTo< WindowFramework > m_window
Pointer to the active panda framework.
int m_renderOrder
name of the renderer
virtual void setNodePose(const std::string &name, const vpHomogeneousMatrix &wTo)
Set the pose of a node. This node can be any Panda object (light, mesh, camera). The pose is specifie...
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 setLightableScene(NodePath &scene)
virtual std::string makeFragmentShader(bool hasTexture, bool specular)
void getRender(vpImage< vpRGBa > &I) const
Store the render resulting from calling renderFrame() into a vpImage.
void addNodeToScene(const NodePath &object) VP_OVERRIDE
Add a node to the scene. Its pose is set as the identity matrix.
void setBackgroundImage(const vpImage< vpRGBa > &background)
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.
Definition: vpRGBa.h:65
unsigned char B
Blue component.
Definition: vpRGBa.h:169
unsigned char R
Red component.
Definition: vpRGBa.h:167
unsigned char G
Green component.
Definition: vpRGBa.h:168
unsigned char A
Additionnal component.
Definition: vpRGBa.h:170