40#include <visp3/core/vpConfig.h>
42#if defined(VISP_HAVE_PANDA3D) && defined(VISP_HAVE_CATCH2)
43#include <visp3/core/vpCameraParameters.h>
44#include <visp3/core/vpIoTools.h>
45#include <visp3/ar/vpPanda3DBaseRenderer.h>
46#include <visp3/ar/vpPanda3DRGBRenderer.h>
47#include <visp3/ar/vpPanda3DFrameworkManager.h>
48#include <visp3/ar/vpPanda3DRendererSet.h>
49#include <visp3/ar/vpPanda3DGeometryRenderer.h>
50#include <catch_amalgamated.hpp>
52#ifdef ENABLE_VISP_NAMESPACE
58const std::string objCube =
60"v -0.050000 -0.050000 0.050000\n"
61"v -0.050000 0.050000 0.050000\n"
62"v -0.050000 -0.050000 -0.050000\n"
63"v -0.050000 0.050000 -0.050000\n"
64"v 0.050000 -0.050000 0.050000\n"
65"v 0.050000 0.050000 0.050000\n"
66"v 0.050000 -0.050000 -0.050000\n"
67"v 0.050000 0.050000 -0.050000\n"
68"f 2/4/1 3/8/1 1/1/1\n"
69"f 4/9/2 7/13/2 3/8/2\n"
70"f 8/14/3 5/11/3 7/13/3\n"
71"f 6/12/4 1/2/4 5/11/4\n"
72"f 7/13/5 1/3/5 3/7/5\n"
73"f 4/10/6 6/12/6 8/14/6\n"
74"f 2/4/1 4/9/1 3/8/1\n"
75"f 4/9/2 8/14/2 7/13/2\n"
76"f 8/14/3 6/12/3 5/11/3\n"
77"f 6/12/4 2/5/4 1/2/4\n"
78"f 7/13/5 5/11/5 1/3/5\n"
79"f 4/10/6 2/6/6 6/12/6\n";
82std::string createObjFile()
86 std::ofstream f(objFile);
87 std::cout << objFile << std::endl;
100bool opt_no_display =
false;
102SCENARIO(
"Instanciating multiple Panda3D renderers",
"[Panda3D]")
104 if (opt_no_display) {
105 std::cout <<
"Display is disabled for tests, skipping..." << std::endl;
108 GIVEN(
"A single renderer")
111 r1.setRenderParameters(defaultRenderParams());
117 THEN(
"Creating another, uncoupled renderer is ok and its destruction does not raise an error")
120 r2.setRenderParameters(defaultRenderParams());
132SCENARIO(
"Sequentially instanciating and destroying Panda3D renderers",
"[Panda3D]")
134 if (opt_no_display) {
135 std::cout <<
"Display is disabled for tests, skipping..." << std::endl;
139 r3.setRenderParameters(defaultRenderParams());
147 r1.setRenderParameters(defaultRenderParams());
155 r2.setRenderParameters(defaultRenderParams());
165SCENARIO(
"Sequentially instanciating and destroying Panda3D renderer sets",
"[Panda3D]")
167 if (opt_no_display) {
168 std::cout <<
"Display is disabled for tests, skipping..." << std::endl;
174 r1.addSubRenderer(std::make_shared<vpPanda3DRGBRenderer>(
true));
182 r1.addSubRenderer(std::make_shared<vpPanda3DRGBRenderer>(
true));
189SCENARIO(
"Using multiple panda3d renderers in parallel",
"[Panda3D]")
191 if (opt_no_display) {
192 std::cout <<
"Display is disabled for tests, skipping..." << std::endl;
196 r3.setRenderParameters(defaultRenderParams());
201 r1.setRenderParameters(defaultRenderParams());
208 r2.setRenderParameters(defaultRenderParams());
219TEST_CASE(
"Testing Geometry renderer",
"[panda3D]")
221 if (opt_no_display) {
222 std::cout <<
"Display is disabled for tests, skipping..." << std::endl;
229 std::vector<vpPanda3DGeometryRenderer *> renderers = { &r1, &r2, &r3, &r4 };
231 std::vector<vpHomogeneousMatrix> cameraPoses = {
237 std::vector<vpImage<vpRGBf>> normalsImages;
238 std::vector<vpImage<float>> depthImages;
241 const std::string objId =
"object";
242 for (
const auto r: renderers) {
243 r->setRenderParameters(params);
245 r->addNodeToScene(
r->loadObject(objId, createObjFile()));
247 r->setCameraPose(
p.inverse());
253 r->getRender(normals, depth);
254 r->getRender(normalsSolo);
255 r->getRender(depthSolo);
258 REQUIRE((
depth.getMinValue() == 0 &&
depth.getMaxValue() > 0.0));
259 REQUIRE(depth == depthSolo);
260 REQUIRE(depth == depthBB);
261 REQUIRE((normals.getSum() != 0.0));
262 REQUIRE(normals == normalsSolo);
263 REQUIRE(normals == normalsBB);
264 normalsImages.push_back(normals);
265 depthImages.push_back(depth);
268 const float thresholdN = 1 / 127.5f;
270 for (
unsigned int i = 0;
i < normalsImages.size() - 1; ++
i) {
271 for (
unsigned int j = i + 1;
j < normalsImages.size(); ++
j) {
272 if (renderers[i]->getRenderType() == renderers[j]->getRenderType()) {
274 std::cout <<
"Comparing renderers" <<
i <<
" and " <<
j << std::endl;
276 for (
unsigned int b = 0; b < depthImages[
i].getSize(); ++b) {
278 float depthDiff = fabs(depthImages[i].bitmap[b] - depthImages[j].bitmap[b]);
279 if (depthDiff > thresholdDepth) {
280 FAIL(
"Depth error is too great");
282 if (depthImages[i].bitmap[b] > 0.0) {
283 const vpRGBf c1 = normalsImages[
i].bitmap[b];
284 const vpRGBf c2 = normalsImages[
j].bitmap[b];
287 if (fabs(c1.
R - c2.
R) > thresholdN || fabs(c1.
G - c2.
G) > thresholdN || fabs(c1.
B - c2.
B) > thresholdN) {
288 std::cout << c1 << c2 << std::endl;
289 FAIL(
"Normal error is too great");
302int main(
int argc,
char *argv[])
304 Catch::Session session;
305 auto cli = session.cli()
306 | Catch::Clara::Opt(opt_no_display)[
"--no-display"](
"Disable display");
309 const int returnCode = session.applyCommandLine(argc, argv);
310 if (returnCode != 0) {
314 const int numFailed = session.run();
324int main() {
return EXIT_SUCCESS; }
Generic class defining intrinsic camera parameters.
Implementation of an homogeneous matrix and operations on such kind of matrices.
Definition of the vpImage class member functions.
static double rad(double deg)
static vpPanda3DFrameworkManager & getInstance()
Renderer that outputs object geometric information.
@ CAMERA_NORMALS
Surface normals in the object frame.
Implementation of a traditional RGB renderer in Panda3D.
Rendering parameters for a panda3D simulation.
unsigned int getImageWidth() const
unsigned int getImageHeight() const
double getFarClippingDistance() const
Class that renders multiple datatypes, in a single pass. A renderer set contains multiple subrenderer...
Defines a rectangle in the plane.