Test saving and parsing JSON configuration for Panda 3D renderer.
#include <visp3/core/vpConfig.h>
#if defined(VISP_HAVE_PANDA3D) && defined(VISP_HAVE_CATCH2)
#include <visp3/core/vpCameraParameters.h>
#include <visp3/core/vpIoTools.h>
#include <visp3/ar/vpPanda3DBaseRenderer.h>
#include <visp3/ar/vpPanda3DRGBRenderer.h>
#include <visp3/ar/vpPanda3DFrameworkManager.h>
#include <visp3/ar/vpPanda3DRendererSet.h>
#include <visp3/ar/vpPanda3DGeometryRenderer.h>
#include <catch_amalgamated.hpp>
#ifdef ENABLE_VISP_NAMESPACE
#endif
#include <random>
const std::string objCube =
"o Cube\n"
"v -0.050000 -0.050000 0.050000\n"
"v -0.050000 0.050000 0.050000\n"
"v -0.050000 -0.050000 -0.050000\n"
"v -0.050000 0.050000 -0.050000\n"
"v 0.050000 -0.050000 0.050000\n"
"v 0.050000 0.050000 0.050000\n"
"v 0.050000 -0.050000 -0.050000\n"
"v 0.050000 0.050000 -0.050000\n"
"f 2/4/1 3/8/1 1/1/1\n"
"f 4/9/2 7/13/2 3/8/2\n"
"f 8/14/3 5/11/3 7/13/3\n"
"f 6/12/4 1/2/4 5/11/4\n"
"f 7/13/5 1/3/5 3/7/5\n"
"f 4/10/6 6/12/6 8/14/6\n"
"f 2/4/1 4/9/1 3/8/1\n"
"f 4/9/2 8/14/2 7/13/2\n"
"f 8/14/3 6/12/3 5/11/3\n"
"f 6/12/4 2/5/4 1/2/4\n"
"f 7/13/5 5/11/5 1/3/5\n"
"f 4/10/6 2/6/6 6/12/6\n";
std::string createObjFile()
{
std::ofstream f(objFile);
std::cout << objFile << std::endl;
f << objCube;
f.close();
return objFile;
}
{
}
bool opt_no_display = false;
SCENARIO("Instanciating multiple Panda3D renderers", "[Panda3D]")
{
if (opt_no_display) {
std::cout << "Display is disabled for tests, skipping..." << std::endl;
}
else {
GIVEN("A single renderer")
{
r1.setRenderParameters(defaultRenderParams());
r1.initFramework();
r1.renderFrame();
r1.getRender(depth);
THEN("Creating another, uncoupled renderer is ok and its destruction does not raise an error")
{
r2.setRenderParameters(defaultRenderParams());
r2.initFramework();
r2.renderFrame();
}
r1.renderFrame();
r1.getRender(depth);
}
}
}
SCENARIO("Sequentially instanciating and destroying Panda3D renderers", "[Panda3D]")
{
if (opt_no_display) {
std::cout << "Display is disabled for tests, skipping..." << std::endl;
}
else {
r3.setRenderParameters(defaultRenderParams());
r3.initFramework();
r3.renderFrame();
r3.getRender(depth);
{
r1.setRenderParameters(defaultRenderParams());
r1.initFramework();
r1.renderFrame();
r1.getRender(depth);
}
{
r2.setRenderParameters(defaultRenderParams());
r2.initFramework();
r2.renderFrame();
r2.getRender(depth);
}
}
}
SCENARIO("Sequentially instanciating and destroying Panda3D renderer sets", "[Panda3D]")
{
if (opt_no_display) {
std::cout << "Display is disabled for tests, skipping..." << std::endl;
}
else {
{
r1.addSubRenderer(std::make_shared<vpPanda3DRGBRenderer>(true));
r1.initFramework();
r1.renderFrame();
}
{
r1.addSubRenderer(std::make_shared<vpPanda3DRGBRenderer>(true));
r1.initFramework();
r1.renderFrame();
}
}
}
SCENARIO("Using multiple panda3d renderers in parallel", "[Panda3D]")
{
if (opt_no_display) {
std::cout << "Display is disabled for tests, skipping..." << std::endl;
}
else {
r3.setRenderParameters(defaultRenderParams());
r3.initFramework();
r3.renderFrame();
r1.setRenderParameters(defaultRenderParams());
r1.initFramework();
r1.renderFrame();
r1.getRender(depth);
r2.setRenderParameters(defaultRenderParams());
r2.initFramework();
r2.renderFrame();
r2.getRender(depth);
r1.renderFrame();
r1.getRender(depth);
}
}
TEST_CASE("Testing Geometry renderer", "[panda3D]")
{
if (opt_no_display) {
std::cout << "Display is disabled for tests, skipping..." << std::endl;
return;
}
std::vector<vpPanda3DGeometryRenderer *> renderers = { &r1, &r2, &r3, &r4 };
std::vector<vpHomogeneousMatrix> cameraPoses = {
};
std::vector<vpImage<vpRGBf>> normalsImages;
std::vector<vpImage<float>> depthImages;
const std::string objId = "object";
for (const auto r: renderers) {
r->setRenderParameters(params);
r->addNodeToScene(
r->loadObject(objId, createObjFile()));
r->setCameraPose(
p.inverse());
r->getRender(normals, depth);
r->getRender(normalsSolo);
REQUIRE((
depth.getMinValue() == 0 &&
depth.getMaxValue() > 0.0));
REQUIRE(depth == depthSolo);
REQUIRE(depth == depthBB);
REQUIRE((normals.getSum() != 0.0));
REQUIRE(normals == normalsSolo);
REQUIRE(normals == normalsBB);
normalsImages.push_back(normals);
depthImages.push_back(depth);
}
const float thresholdN = 1 / 127.5f;
for (
unsigned int i = 0;
i < normalsImages.size() - 1; ++
i) {
for (
unsigned int j = i + 1;
j < normalsImages.size(); ++
j) {
if (renderers[i]->getRenderType() == renderers[j]->getRenderType()) {
std::cout <<
"Comparing renderers" <<
i <<
" and " <<
j << std::endl;
for (
unsigned int b = 0; b < depthImages[
i].getSize(); ++b) {
float depthDiff = fabs(depthImages[i].bitmap[b] - depthImages[j].bitmap[b]);
if (depthDiff > thresholdDepth) {
FAIL("Depth error is too great");
}
if (depthImages[i].bitmap[b] > 0.0) {
const vpRGBf c1 = normalsImages[
i].bitmap[b];
const vpRGBf c2 = normalsImages[
j].bitmap[b];
if (fabs(c1.
R - c2.
R) > thresholdN || fabs(c1.
G - c2.
G) > thresholdN || fabs(c1.
B - c2.
B) > thresholdN) {
std::cout << c1 << c2 << std::endl;
FAIL("Normal error is too great");
}
}
}
}
}
}
}
}
int main(int argc, char *argv[])
{
Catch::Session session;
auto cli = session.cli()
| Catch::Clara::Opt(opt_no_display)["--no-display"]("Disable display");
session.cli(cli);
const int returnCode = session.applyCommandLine(argc, argv);
if (returnCode != 0) {
return returnCode;
}
const int numFailed = session.run();
return numFailed;
}
#else
#include <stdlib.h>
int main() { return EXIT_SUCCESS; }
#endif
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.