Visual Servoing Platform  version 3.6.1 under development (2024-10-18)
vpPanda3DBaseRenderer.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/vpPanda3DBaseRenderer.h>
32 
33 #if defined(VISP_HAVE_PANDA3D)
34 
35 #include <visp3/core/vpMath.h>
36 
37 #include "load_prc_file.h"
38 #include <antialiasAttrib.h>
39 #include "boundingSphere.h"
40 #include "boundingBox.h"
41 
42 BEGIN_VISP_NAMESPACE
44  1.0, 0.0, 0.0, 0.0,
45  0.0, 0.0, -1., 0.0,
46  0.0, 1.0, 0.0, 0.0,
47  0.0, 0.0, 0.0, 1.0
48 });
50 
52 {
53  if (m_framework.use_count() > 0) {
55  "Panda3D renderer: Reinitializing is not supported!");
56  }
57  m_framework = std::shared_ptr<PandaFramework>(new PandaFramework());
58  m_framework->open_framework();
59  WindowProperties winProps;
60  winProps.set_size(LVecBase2i(m_renderParameters.getImageWidth(), m_renderParameters.getImageHeight()));
61  int flags = GraphicsPipe::BF_refuse_window;
62  m_window = m_framework->open_window(winProps, flags);
63  // try and reopen with visible window
64  if (m_window == nullptr) {
65  winProps.set_minimized(true);
66  m_window = m_framework->open_window(winProps, 0);
67  }
68  if (m_window == nullptr) {
70  "Panda3D renderer: Could not create the requested window when performing initialization.");
71  }
72  m_window->set_background_type(WindowFramework::BackgroundType::BT_black);
73  setupScene();
74  setupCamera();
76  //m_window->get_display_region_3d()->set_camera(m_cameraPath);
77 }
78 
79 void vpPanda3DBaseRenderer::initFromParent(std::shared_ptr<PandaFramework> framework, PointerTo<WindowFramework> window)
80 {
81  m_framework = framework;
82  m_window = window;
83  setupScene();
84  setupCamera();
86 }
87 
89 {
90  initFromParent(renderer.m_framework, renderer.m_window);
91 }
92 
94 {
95  m_renderRoot = m_window->get_render().attach_new_node(m_name);
96  //m_renderRoot.set_antialias(AntialiasAttrib::M_none);
97 }
98 
100 {
101  m_cameraPath = m_window->make_camera();
102  m_camera = (Camera *)m_cameraPath.node();
103  // m_camera = m_window->get_camera(0);
104  m_cameraPath = m_renderRoot.attach_new_node(m_camera);
106  m_camera->set_scene(m_renderRoot);
107 }
108 
110 {
112  m_framework->get_graphics_engine()->render_frame();
114 }
115 
117 {
118  unsigned int previousH = m_renderParameters.getImageHeight(), previousW = m_renderParameters.getImageWidth();
119  bool resize = previousH != params.getImageHeight() || previousW != params.getImageWidth();
120 
121  m_renderParameters = params;
122 
123  if (resize) {
124  for (GraphicsOutput *buffer: m_buffers) {
125  //buffer->get_type().is_derived_from()
126  GraphicsBuffer *buf = dynamic_cast<GraphicsBuffer *>(buffer);
127  if (buf == nullptr) {
128  throw vpException(vpException::fatalError, "Panda3D: could not cast to GraphicsBuffer when rendering.");
129  }
130  else {
132  }
133  }
134  }
135 
136  // If renderer is already initialized, modify camera properties
137  if (m_camera != nullptr) {
139  }
140 }
141 
143 {
144  if (m_camera.is_null() || m_cameraPath.is_empty()) {
145  throw vpException(vpException::notInitialized, "Camera was not initialized before trying to set its pose");
146  }
148 }
149 
151 {
152  if (m_camera.is_null()) {
153  throw vpException(vpException::notInitialized, "Camera was not initialized before trying to get its pose");
154  }
155  return getNodePose(m_cameraPath);
156 }
157 
158 void vpPanda3DBaseRenderer::setNodePose(const std::string &name, const vpHomogeneousMatrix &wTo)
159 {
160  NodePath object = m_renderRoot.find(name);
161  setNodePose(object, wTo);
162 }
163 
164 void vpPanda3DBaseRenderer::setNodePose(NodePath &object, const vpHomogeneousMatrix &wTo)
165 {
166  const vpHomogeneousMatrix wpTo = wTo * VISP_T_PANDA;
169  object.set_pos(t[0], t[1], t[2]);
170  object.set_quat(LQuaternion(q.w(), q.x(), q.y(), q.z()));
171 }
172 
174 {
175  NodePath object = m_renderRoot.find(name);
176  if (object.is_empty()) {
177  throw vpException(vpException::badValue, "Node %s was not found", name.c_str());
178  }
179  return getNodePose(object);
180 }
181 
183 {
184  const LPoint3 pos = object.get_pos();
185  const LQuaternion quat = object.get_quat();
186  const vpTranslationVector t(pos[0], pos[1], pos[2]);
187  const vpQuaternionVector q(quat.get_i(), quat.get_j(), quat.get_k(), quat.get_r());
188  return vpHomogeneousMatrix(t, q) * PANDA_T_VISP;
189 }
190 
191 void vpPanda3DBaseRenderer::computeNearAndFarPlanesFromNode(const std::string &name, float &nearV, float &farV, bool fast)
192 {
193  if (m_camera == nullptr) {
194  throw vpException(vpException::notInitialized, "Cannot compute planes when the camera is not initialized");
195  }
196  NodePath object = m_renderRoot.find(name);
197  if (object.is_empty()) {
198  throw vpException(vpException::badValue, "Node %s was not found", name.c_str());
199  }
200  if (!fast) {
201  LPoint3 minP, maxP;
202  object.calc_tight_bounds(minP, maxP);
203  const BoundingBox box(minP, maxP);
204  float minZ = std::numeric_limits<float>::max(), maxZ = 0.f;
205  const vpHomogeneousMatrix wTcam = getCameraPose();
207  const vpHomogeneousMatrix camTobj = wTcam.inverse() * wTobj;
208  for (unsigned int i = 0; i < 8; ++i) {
209  const LPoint3 p = box.get_point(i);
210  const vpColVector pv = vpColVector({ p.get_x(), -p.get_z(), p.get_y(), 1.0 });
211  vpColVector cpV = camTobj * pv;
212  cpV /= cpV[3];
213  float Z = cpV[2];
214  if (Z > maxZ) {
215  maxZ = Z;
216  }
217  if (Z < minZ) {
218  minZ = Z;
219  }
220  }
221 
222  nearV = minZ;
223  farV = maxZ;
224  }
225  else {
226  const BoundingVolume *volume = object.node()->get_bounds();
227  if (volume->get_type() == BoundingSphere::get_class_type()) {
228  const BoundingSphere *sphere = (const BoundingSphere *)volume;
229  const LPoint3 center = sphere->get_center();
230  const float distCenter = (center - m_cameraPath.get_pos()).length();
231  nearV = vpMath::maximum<float>(0.f, distCenter - sphere->get_radius());
232  farV = vpMath::maximum<float>(nearV, distCenter + sphere->get_radius());
233  }
234  else if (volume->get_type() == BoundingBox::get_class_type()) {
235  const vpHomogeneousMatrix wTcam = getCameraPose();
237  const vpHomogeneousMatrix camTobj = wTcam.inverse() * wTobj;
238  const BoundingBox *box = (const BoundingBox *)volume;
239  double minZ = std::numeric_limits<double>::max(), maxZ = 0.0;
240 
241  for (unsigned int i = 0; i < 8; ++i) {
242  const LPoint3 p = box->get_point(i);
243  vpColVector cp = camTobj * vpColVector({ p.get_x(), -p.get_z(), p.get_y(), 1.0 });
244  double Z = cp[2] / cp[3];
245  if (Z < minZ) {
246  minZ = Z;
247  }
248  if (Z > maxZ) {
249  maxZ = Z;
250  }
251  }
252  nearV = minZ;
253  farV = maxZ;
254  }
255  else {
256  throw vpException(vpException::fatalError, "Unhandled bounding volume %s type returned by Panda3d", volume->get_type().get_name().c_str());
257  }
258  }
259 }
260 
262 {
263  if (isRendering3DScene()) {
264  GraphicsOutput *buffer = getMainOutputBuffer();
265  if (buffer != nullptr) {
266  buffer->set_clear_depth_active(false);
267  if (!buffer->share_depth_buffer(sourceBuffer.getMainOutputBuffer())) {
268  throw vpException(vpException::fatalError, "Could not share depth buffer!");
269  }
270  }
271  }
272 }
273 
274 NodePath vpPanda3DBaseRenderer::loadObject(const std::string &nodeName, const std::string &modelPath)
275 {
276  NodePath model = m_window->load_model(m_framework->get_models(), modelPath);
277  for (int i = 0; i < model.get_num_children(); ++i) {
278  model.get_child(i).clear_transform();
279  }
280 
281  model.detach_node();
282  model.set_name(nodeName);
283  return model;
284 }
285 
286 void vpPanda3DBaseRenderer::addNodeToScene(const NodePath &object)
287 {
288  NodePath objectInScene = object.copy_to(m_renderRoot);
289  objectInScene.set_name(object.get_name());
290  setNodePose(objectInScene, vpHomogeneousMatrix());
291 }
292 
294 {
295  if (useVsync) {
296  load_prc_file_data("", "sync-video true");
297  }
298  else {
299  load_prc_file_data("", "sync-video false");
300  }
301 }
303 {
304  if (abort) {
305  load_prc_file_data("", "assert-abort 1");
306  }
307  else {
308  load_prc_file_data("", "assert-abort 0");
309  }
310 }
311 
313 {
314  load_prc_file_data("", "gl-debug 1");
315  load_prc_file_data("", "notify-level-display spam");
316 }
317 
319 {
320  vpColVector pandaPos = PANDA_T_VISP * point;
321  pandaPos /= pandaPos[3];
322  return pandaPos;
323 }
325 {
326  vpColVector pandaPos = PANDA_T_VISP.getRotationMatrix() * point;
327  return pandaPos;
328 }
329 
331 {
332  m_renderRoot.ls();
333 }
334 
335 END_VISP_NAMESPACE
336 
337 #elif !defined(VISP_BUILD_SHARED_LIBS)
338 // Work around to avoid warning: libvisp_ar.a(vpPanda3DBaseRenderer.cpp.o) has no symbols
339 void dummy_vpPanda3DBaseRenderer() { };
340 
341 #endif
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
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
@ notInitialized
Used to indicate that a parameter is not initialized.
Definition: vpException.h:74
@ notImplementedError
Not implemented.
Definition: vpException.h:69
@ fatalError
Fatal error.
Definition: vpException.h:72
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
vpHomogeneousMatrix inverse() const
vpTranslationVector getTranslationVector() const
Base class for a panda3D renderer. This class handles basic functionalities, such as loading object,...
virtual void setupCamera()
Initialize camera. Should be called when the scene root of this render has already been created.
virtual void setupScene()
Initialize the scene for this specific renderer.
virtual vpHomogeneousMatrix getCameraPose()
Retrieve the camera's pose, in the world frame. The pose is specified using the ViSP convention (Y-do...
std::shared_ptr< PandaFramework > m_framework
Rendering priority for this renderer and its buffers. A lower value will be rendered first....
virtual GraphicsOutput * getMainOutputBuffer()
NodePath m_renderRoot
Rendering parameters.
void computeNearAndFarPlanesFromNode(const std::string &name, float &near, float &far, bool fast)
Compute the near and far planes for the camera at the current pose, given a certain node/part of the ...
PointerTo< Camera > m_camera
Node containing all the objects and the camera for this renderer.
virtual bool isRendering3DScene() const
Returns true if this renderer process 3D data and its scene root can be interacted with.
static vpColVector vispPointToPanda(const vpColVector &point)
virtual void initFramework()
Initialize the whole Panda3D framework. Create a new PandaFramework object and a new window.
void setVerticalSyncEnabled(bool useVsync)
set whether vertical sync is enabled. When vertical sync is enabled, render speed will be limited by ...
static const vpHomogeneousMatrix PANDA_T_VISP
Homogeneous transformation matrix to convert from the Panda coordinate system (right-handed Z-up) to ...
std::string m_name
Inverse of VISP_T_PANDA.
virtual void addNodeToScene(const NodePath &object)
Add a node to the scene. Its pose is set as the identity matrix.
void setAbortOnPandaError(bool abort)
Set the behaviour when a Panda3D assertion fails. If abort is true, the program will stop....
static const vpHomogeneousMatrix VISP_T_PANDA
virtual void initFromParent(std::shared_ptr< PandaFramework > framework, PointerTo< WindowFramework > window)
virtual void afterFrameRendered()
PointerTo< WindowFramework > m_window
Pointer to the active panda framework.
virtual void enableSharedDepthBuffer(vpPanda3DBaseRenderer &sourceBuffer)
virtual void setupRenderTarget()
Initialize buffers and other objects that are required to save the render.
static vpColVector vispVectorToPanda(const vpColVector &vec)
virtual void setRenderParameters(const vpPanda3DRenderParameters &params)
Set new rendering parameters. If the scene has already been initialized, the renderer camera is updat...
NodePath loadObject(const std::string &nodeName, const std::string &modelPath)
Load a 3D object. To load an .obj file, Panda3D must be compiled with assimp support.
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...
virtual void beforeFrameRendered()
virtual void setCameraPose(const vpHomogeneousMatrix &wTc)
Set the camera's pose. The pose is specified using the ViSP convention (Y-down right handed).
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.
virtual vpHomogeneousMatrix getNodePose(const std::string &name)
Get the pose of a Panda node, in world frame in the ViSP convention (Y-down right handed).
Rendering parameters for a panda3D simulation.
void setupPandaCamera(Camera *camera)
Update a Panda3D camera object to use this objects's parameters.
Implementation of a rotation vector as quaternion angle minimal representation.
const double & z() const
Returns the z-component of the quaternion.
const double & x() const
Returns the x-component of the quaternion.
const double & y() const
Returns the y-component of the quaternion.
const double & w() const
Returns the w-component of the quaternion.
Class that consider the case of a translation vector.