VTK: visualize depth buffer - c++

I am trying to follow the example here: http://www.vtk.org/Wiki/VTK/Examples/Cxx/Utilities/ZBuffer to visualize the zbuffer. This works fine until I try to change the camera viewpoint.
My code is as follows: which is the same as the example except for the bit in bold:
// This demo creates depth map for a polydata instance by extracting
// exact ZBuffer values.
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkBMPWriter.h>
#include <vtkWindowToImageFilter.h>
#include <vtkImageShiftScale.h>
int main(int argc, char *argv[]) {
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkPLYReader> fileReader = vtkSmartPointer<vtkPLYReader>::New();
vtkSmartPointer<vtkWindowToImageFilter> filter = vtkSmartPointer<vtkWindowToImageFilter>::New();
vtkSmartPointer<vtkBMPWriter> imageWriter = vtkSmartPointer<vtkBMPWriter>::New();
vtkSmartPointer<vtkImageShiftScale> scale = vtkSmartPointer<vtkImageShiftScale>::New();
// Read .vtp file
fileReader->SetFileName("mesh.ply");
//Build visualization enviroment
mapper->SetInputConnection(fileReader->GetOutputPort());
actor->SetMapper(mapper);
renderer->AddActor(actor);
//change camera viewpoint
vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
camera->SetPosition(0, 0, 650);
renderer->SetActiveCamera(camera);
renWin->AddRenderer(renderer);
interactor->SetRenderWindow(renWin);
renWin->Render();
// Create Depth Map
filter->SetInput(renWin);
filter->SetMagnification(1);
filter->SetInputBufferTypeToZBuffer(); //Extract z buffer value
scale->SetOutputScalarTypeToUnsignedChar();
scale->SetInputConnection(filter->GetOutputPort());
scale->SetShift(0);
scale->SetScale(-255);
// Write depth map as a .bmp image
imageWriter->SetFileName("out2.bmp");
imageWriter->SetInputConnection(scale->GetOutputPort());
imageWriter->Write();
return EXIT_SUCCESS;
}
Now the entire depth visualization is completely black. However, at this camera position the mesh renders just fine, so I don't think it's due to camera being too far away. Any ideas what I am doing wrong?

That probably because your far plane is near the object that is being rendered. Try to put, after camera creation, a better clip plane, as example:
camera->SetClippingRange(640, 1000);

Related

Qt3D : How to display text on the 3D Window screen?

How does one display text on the 3D window screen? I know they a text2D entity module, but thats for displaying text in 3D next to the objects. I want to know if I can display 2D text on the screen.
Im using C++ so would like to know if this possible in C++ and not qml thanks.
There is QText2DEntity class for allowing the creation of a 2D text in 3D space.
#include <QApplication>
#include <QGuiApplication>
#include <Qt3DExtras>
#include <Qt3DRender/qcamera.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DRender/qcameralens.h>
#include <QtWidgets/QWidget>
#include <QtWidgets/QHBoxLayout>
int main(int argc, char **argv)
{
QApplication a(argc, argv);
auto *view = new Qt3DExtras::Qt3DWindow;
view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f)));
auto *container = QWidget::createWindowContainer(view);
auto screenSize = view->screen()->size();
container->setMinimumSize(QSize(200, 100));
container->setMaximumSize(screenSize);
auto *widget = new QWidget;
auto *hLayout = new QHBoxLayout(widget);
hLayout->addWidget(container, 1);
auto *input = new Qt3DInput::QInputAspect;
view->registerAspect(input);
// Root entity
auto *rootEntity = new Qt3DCore::QEntity();
// Camera
auto *cameraEntity = view->camera();
cameraEntity->lens()->setPerspectiveProjection(45.0f, 16.0f/7.0f, 0.1f, 1000.0f);
cameraEntity->setPosition(QVector3D(0, 10.0f, 20.0f));
cameraEntity->setUpVector(QVector3D(0, 1, 0));
cameraEntity->setViewCenter(QVector3D(0, 0, 0));
//light
auto *lightEntity = new Qt3DCore::QEntity(rootEntity);
auto *light = new Qt3DRender::QPointLight(lightEntity);
light->setColor("white");
light->setIntensity(1);
lightEntity->addComponent(light);
auto *lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(cameraEntity->position());
lightEntity->addComponent(lightTransform);
// For camera controls
auto *camController = new Qt3DExtras::QOrbitCameraController (rootEntity);
camController->setCamera(cameraEntity);
// Set root object of the scene
view->setRootEntity(rootEntity);
auto *text2dTransform = new Qt3DCore::QTransform;
text2dTransform->setScale(0.125f);
text2dTransform->setTranslation(QVector3D(-5, 0, 5));
auto *text2d = new Qt3DExtras::QText2DEntity(rootEntity);
text2d->setFont(QFont("monospace"));
text2d->setHeight(20);
text2d->setWidth(100);
text2d->setText("A");
text2d->setColor(Qt::yellow);
text2d->addComponent(text2dTransform);
widget->show();
widget->resize(1200, 800);
return a.exec();
}
Parisa has already provided a nice solution, I'll just post here mine here in case you are looking for something which allows to draw UI-like text:
Like stated in the comments, either draw a rectangular surface on top of everything using orthographic projection mode (similar to my Qt3DBackground example, just draw the texture last and make it transparent).
Or instead use my Qt3D Widget which allows to add Qt's widgets onto Qt3D. This way, you can draw your scene and use a simple QLabel on top.

Can't see/load a .obj file with Qt3D, written in cpp

I'm having a lot of issues to have a simple working app that load a light mesh in Qt3D, nothing shows up on screen.
Here's some code I put together to have a have striped down to show.
You'll notice that it's a shorter version of this Qt example
You won't see it in this example but in my actual project I already
tried loading it with
qrc and
localfile QUrl
Qt3DExtras::QTorusMesh work without an issue.
I tried to watch the loading status of the mesh, on my actual project it does go from None though Loading to Loaded
Also, I have no trouble loading the file su.obj using a Qt QML example, so it's
not the file that is corrupted. The file being a simple Suzanne from Blender, exported.
I used Qt5 and 6.
Finally, I know the question has been asked a few times, but nothing helped.
#include <QGuiApplication>
#include <Qt3DCore/QEntity>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QCameraLens>
#include <Qt3DCore/QTransform>
#include <Qt3DCore/QAspectEngine>
#include <Qt3DInput/QInputAspect>
#include <Qt3DRender/QRenderAspect>
#include <Qt3DRender/QGeometryRenderer>
#include <Qt3DExtras/QForwardRenderer>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DExtras/QTorusMesh>
#include <QMesh>
#include <QPropertyAnimation>
#include "orbittransformcontroller.h"
#include "qorbitcameracontroller.h"
#include "qt3dwindow.h"
#include <qdebug.h>
Qt3DCore::QEntity *createScene()
{
// Root entity
Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity;
// Material
Qt3DRender::QMaterial *material = new Qt3DExtras::QPhongMaterial(rootEntity);
// Sphere
Qt3DCore::QEntity *sphereEntity = new Qt3DCore::QEntity(rootEntity);
auto *sphereMesh = new Qt3DRender::QMesh();
sphereMesh->setSource(QUrl::fromLocalFile("su.obj"));
Qt3DCore::QTransform *sphereTransform = new Qt3DCore::QTransform;
OrbitTransformController *controller = new OrbitTransformController(sphereTransform);
controller->setTarget(sphereTransform);
controller->setRadius(20.0f);
QPropertyAnimation *sphereRotateTransformAnimation = new QPropertyAnimation(sphereTransform);
sphereRotateTransformAnimation->setTargetObject(controller);
sphereRotateTransformAnimation->setPropertyName("angle");
sphereRotateTransformAnimation->setStartValue(QVariant::fromValue(0));
sphereRotateTransformAnimation->setEndValue(QVariant::fromValue(360));
sphereRotateTransformAnimation->setDuration(10000);
sphereRotateTransformAnimation->setLoopCount(-1);
sphereRotateTransformAnimation->start();
sphereEntity->addComponent(sphereMesh);
sphereEntity->addComponent(sphereTransform);
sphereEntity->addComponent(material);
return rootEntity;
}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Qt3DExtras::Qt3DWindow view;
Qt3DCore::QEntity *scene = createScene();
// Camera
Qt3DRender::QCamera *camera = view.camera();
camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
camera->setPosition(QVector3D(0, 0, 40.0f));
camera->setViewCenter(QVector3D(0, 0, 0));
// For camera controls
Qt3DExtras::QOrbitCameraController *camController = new Qt3DExtras::QOrbitCameraController(scene);
camController->setLinearSpeed( 50.0f );
camController->setLookSpeed( 180.0f );
camController->setCamera(camera);
view.setRootEntity(scene);
view.show();
return app.exec();
}
With the help from #eyllanesc and qDebug, I found how to write it in three ways:
const QUrl url = QUrl( "qrc:/path/copied/from/qtcreator/su.obj");
const QUrl url = QUrl::fromLocalFile( "C:/path/to/folder/su.obj");
const QUrl url = QUrl::fromLocalFile( "su.obj");
qDebug() << QDir::currentPath(); // I used this to make sure I was at the right place
and
sphereMesh->setSource(url);

VTK rendering with wsl

I use WSL and tried to render a simple image with VTK. I used the following c++ code:
#include <vtkVersion.h>
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkDataSetMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
int main(int, char*[])
{
// Create an image data
vtkSmartPointer<vtkImageData> imageData =
vtkSmartPointer<vtkImageData>::New();
// Specify the size of the image data
imageData->SetDimensions(3,3,2);
imageData->SetSpacing(1.0, 1.0, 1.0);
imageData->SetOrigin(0.0, 0.0, 0.0);
vtkSmartPointer<vtkDataSetMapper> mapper =
vtkSmartPointer<vtkDataSetMapper>::New();
#if VTK_MAJOR_VERSION <= 5
mapper->SetInputConnection(imageData->GetProducerPort());
#else
mapper->SetInputData(imageData);
#endif
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
// Add both renderers to the window
renderWindow->AddRenderer(renderer);
// Add a sphere to the left and a cube to the right
renderer->AddActor(actor);
renderer->ResetCamera();
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
//renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
and used CMake with the following CMakeLists.txt:
project(test)
find_package(VTK)
message (STATUS "VTK_VERSION: ${VTK_VERSION}")
add_executable(test test.cxx )
target_link_libraries(test ${VTK_LIBRARIES})
vtk_module_autoinit(
TARGETS ${PROJECT_NAME}
MODULES ${VTK_LIBRARIES}
)
I can compile and run it but I just get a window but it's black. It is by the way a simple example of VTK. I use VcXsrv and disabled native OpenGL. I also set export GL_ALWAYS_INDIRECT=0 and when I run glxgears they are rotating.
I always get the following printed to my console:
[ 80D00780]vtkOpenGLFramebufferObj:1390 WARN| failed at glBlitFramebuffer 1 OpenGL errors detected
0 : (1282) Invalid operation
Thank you for your help!
It is commonly known bug in VcXsrv. It's quite tricky, but there is a simple work-around. You have to change your CMakeList. This YouTube-Tutorial explains it very well. If you have further questions, I'm happy to offer other excellent answers.

Importing a 3d object file (.obj) using VTK and C++

Recently I am working on a project which involves working on 3D Object files. I have to used VTK and C++ for the code. I used the code available from tutorials of VTK for importing a 3d Object File, but after building the solution I am not able to open the ReadObj.exe file.
Following is the code:-
#include <vtkSmartPointer.h>
#include <vtkOBJReader.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <vtkCamera.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkNamedColors.h>
#include <string>
int main(int argc, char* argv[])
{
// Parse command line arguments
if(argc != 2)
{
std::cout << "Usage: " << argv[0] << "Filename(.obj) e.g trumpet.obj " << std::endl;
return EXIT_FAILURE;
}
std::string filename = "Data/elephanm.obj";
vtkSmartPointer<vtkOBJReader> reader =
vtkSmartPointer<vtkOBJReader>::New();
reader->SetFileName(filename.c_str());
reader->Update();
// Visualize
vtkSmartPointer<vtkNamedColors> colors =
vtkSmartPointer<vtkNamedColors>::New();
vtkColor3d backgroundColor = colors->GetColor3d("SpringGreen");
vtkColor3d actorColor = colors->GetColor3d("HoneyDew");
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(reader->GetOutputPort());
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetDiffuseColor(actorColor.GetData());
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->SetBackground(backgroundColor.GetData());
renderer->ResetCamera();
renderer->GetActiveCamera()->Azimuth(30);
renderer->GetActiveCamera()->Elevation(30);
renderer->GetActiveCamera()->Dolly(1.5);
renderer->ResetCameraClippingRange();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
Also, Build is successful in Visual Studio and ReadObj.exe gets created. But the exe file does not open and does not show the result
Can anyone help me to fix this?

2D meshes in QT3D

It seems to me that Qt3D cannot render 2D meshes well. To see what I mean open the shadow map QML example and change the camera controller from FirstPersonCameraController to OrbitCameraController. Run the program and attempt to view the ground plane from below, you will see it disappear. So QT3D just renders 2D meshes from one side and makes them transparent from the other side.
How can I fix this? i.e. render 2D meshes from both sides?
EDIT: Now I know that I have to disable culling for the rendering to work. I came up to this point:
//'this' refers to Qt3DWindow
rootEntity->addComponent(this->renderSettings());
QCullFace *face = new QCullFace();
QRenderStateSet *stateSet = new QRenderStateSet(this->renderSettings()->activeFrameGraph());
QRenderSurfaceSelector *selector = new QRenderSurfaceSelector(this->renderSettings());
face->setMode(QCullFace::NoCulling);
stateSet->addRenderState(face);
selector->setSurface(this);
but this still doesn't seem to change anything. Am I missing something?
Here is a minimally working example:
main.cpp:
#include <QApplication>
#include "clickwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GraphicsWindow graphicsWindow;
graphicsWindow.show();
return a.exec();
}
graphicswindow.h:
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>
class GraphicsWindow : public Qt3DExtras::Qt3DWindow {
public:
GraphicsWindow();
void wheelEvent ( QWheelEvent * event ) override;
private:
Qt3DCore::QEntity *createScene();
Qt3DCore::QTransform *planeTransform;
};
graphicswindow.cpp:
#include "graphicswindow.h"
#include <QMouseEvent>
#include <Qt3DRender/QViewport>
#include <Qt3DRender/QClearBuffers>
#include <Qt3DRender/QRenderSurfaceSelector>
#include <Qt3DRender/QRenderStateSet>
#include <Qt3DRender/QCullFace>
#include <Qt3DRender/QCameraSelector>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QMaterial>
#include <Qt3DExtras/QGoochMaterial>
#include <Qt3DExtras/QPlaneMesh>
#include <Qt3DRender/QDepthTest>
GraphicsWindow::GraphicsWindow() : Qt3DExtras::Qt3DWindow() {
Qt3DRender::QCamera *camera = this->camera();
camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
camera->setPosition(QVector3D(20.0, 20.0, 20.0f));
camera->setViewCenter(QVector3D(0, 0, 0));
Qt3DRender::QRenderSurfaceSelector *surfaceSelector = new Qt3DRender::QRenderSurfaceSelector;
surfaceSelector->setSurface(this);
Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(surfaceSelector);
viewport->setNormalizedRect(QRectF(0, 0, 1.0, 1.0));
Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(viewport);
cameraSelector->setCamera(camera);
Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers(cameraSelector);
clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthBuffer);
clearBuffers->setClearColor(Qt::white);
Qt3DRender::QRenderStateSet *renderStateSet = new Qt3DRender::QRenderStateSet(clearBuffers);
Qt3DRender::QCullFace *cullFace = new Qt3DRender::QCullFace(renderStateSet);
cullFace->setMode(Qt3DRender::QCullFace::NoCulling);
renderStateSet->addRenderState(cullFace);
Qt3DRender::QDepthTest *depthTest = new Qt3DRender::QDepthTest;
depthTest->setDepthFunction(Qt3DRender::QDepthTest::Less);
renderStateSet->addRenderState(depthTest);
setActiveFrameGraph(surfaceSelector);
Qt3DCore::QEntity *root = createScene();
setRootEntity(root);
}
void GraphicsWindow::wheelEvent(QWheelEvent *event) {
planeTransform->setRotationZ(planeTransform->rotationZ() + event->delta() / 40.f);
}
Qt3DCore::QEntity* GraphicsWindow::createScene() { // Root entity
Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity;
Qt3DCore::QEntity *planeEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DRender::QMaterial *meshMaterial = new Qt3DExtras::QGoochMaterial;
Qt3DExtras::QPlaneMesh *planeMesh = new Qt3DExtras::QPlaneMesh;
planeMesh->setHeight(10);
planeMesh->setWidth(10);
planeTransform = new Qt3DCore::QTransform;
planeEntity->addComponent(planeTransform);
planeEntity->addComponent(planeMesh);
planeEntity->addComponent(meshMaterial);
return rootEntity;
}
Keep in mind that the setActiveFramegraph function of the Qt3DWindow automatically adds the QRenderSettings returned by the renderSettings() function of the window on the frame graph node that you set as the active frame graph. If you are implementing your own 3D window or create and offscreen renderer you have to use QRenderSettings as the root node of your framegraph (the window sets its render settings as the parent of the root frame graph node that you set) and add the render settings to the actual root node, i.e. the node that is the parent of the frame graph and the scene graph.