-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example on how to leverage this with QOpenglWidget? #561
Comments
I created a simple example using QOpenglWidget but not sure why I am getting weird rendering like what is shown below. I can sometime get it to render correctly after multiple resizes, but not sue what could be causing this. Below is a condensed version of the class. The class SimpleRenderWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
void SimpleRenderWidget::resizeGL(int w, int h)
{
this->dataPtr->renderer.Resize(w, h);
glViewport(0, 0, w, h);
}
/////////////////////////////////////////////////
void SimpleRenderWidget::paintGL()
{
makeCurrent();
ignition::rendering::Image image = this->dataPtr->renderer.Render();
ignition::rendering::PixelFormat f = image.Format();
ignerr << "Format: " << f << std::endl;
auto* data = image.Data<unsigned char>();
ignerr << "Image, w: " << image.Width() << " h: " << image.Height() << std::endl;
ignition::common::Image tmp;
tmp.SetFromData(data, image.Width(), image.Height(), ignition::common::Image::RGB_INT8);
tmp.SavePNG("/tmp/ign_image.png");
doneCurrent();
makeCurrent();
GLint m_viewport[4];
glGetIntegerv( GL_VIEWPORT, m_viewport );
ignerr << "ViewPort, x: " << m_viewport[0] << " y: " << m_viewport[1] << " w: " << m_viewport[2] << " h: " << m_viewport[3] << std::endl;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawPixels(image.Width(), image.Height(), GL_RGB, GL_UNSIGNED_BYTE, data);
doneCurrent();
}
}; |
Here is a minimal example. minimal_example.h #ifndef MINIMAL_EXAMPLE_H
#define MINIMAL_EXAMPLE_H
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLExtraFunctions>
#include <QOffscreenSurface>
#include <QtDebug>
#include <QOpenGLFunctions_4_5_Core>
#include <QPainter>
#include <ignition/rendering/Camera.hh>
#include <ignition/rendering/RayQuery.hh>
#include <ignition/rendering/RenderEngine.hh>
#include <ignition/rendering/RenderingIface.hh>
#include <ignition/rendering/Scene.hh>
#include <ignition/rendering/Grid.hh>
#include <ignition/common/Console.hh>
#include <ignition/common/Image.hh>
inline GLenum glCheckError_(const char *file, int line)
{
GLenum errorCode;
while ((errorCode = QOpenGLContext::currentContext()->functions()->glGetError()) != GL_NO_ERROR)
{
const char *error;
switch (errorCode)
{
case GL_INVALID_ENUM: error = "INVALID_ENUM"; break;
case GL_INVALID_VALUE: error = "INVALID_VALUE"; break;
case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break;
case GL_STACK_OVERFLOW: error = "STACK_OVERFLOW"; break;
case GL_STACK_UNDERFLOW: error = "STACK_UNDERFLOW"; break;
case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break;
}
qDebug() << error << " | " << file << " (" << line << ")";
}
return errorCode;
}
#define glCheckError() glCheckError_(__FILE__, __LINE__)
inline void APIENTRY glDebugOutput(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei,
const GLchar *message,
const void *)
{
// ignore non-significant error/warning codes
// if(id == 131169 || id == 131185 || id == 131218 || id == 131204) return;
qDebug() << "---------------";
qDebug() << "Debug message (" << id << "):" << message;
switch (source)
{
case GL_DEBUG_SOURCE_API: qDebug() << "Source: API"; break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM: qDebug() << "Source: Window System"; break;
case GL_DEBUG_SOURCE_SHADER_COMPILER: qDebug() << "Source: Shader Compiler"; break;
case GL_DEBUG_SOURCE_THIRD_PARTY: qDebug() << "Source: Third Party"; break;
case GL_DEBUG_SOURCE_APPLICATION: qDebug() << "Source: Application"; break;
case GL_DEBUG_SOURCE_OTHER: qDebug() << "Source: Other"; break;
}
switch (type)
{
case GL_DEBUG_TYPE_ERROR: qDebug() << "Type: Error"; break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: qDebug() << "Type: Deprecated Behaviour"; break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: qDebug() << "Type: Undefined Behaviour"; break;
case GL_DEBUG_TYPE_PORTABILITY: qDebug() << "Type: Portability"; break;
case GL_DEBUG_TYPE_PERFORMANCE: qDebug() << "Type: Performance"; break;
case GL_DEBUG_TYPE_MARKER: qDebug() << "Type: Marker"; break;
case GL_DEBUG_TYPE_PUSH_GROUP: qDebug() << "Type: Push Group"; break;
case GL_DEBUG_TYPE_POP_GROUP: qDebug() << "Type: Pop Group"; break;
case GL_DEBUG_TYPE_OTHER: qDebug() << "Type: Other"; break;
}
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH: qDebug() << "Severity: high"; break;
case GL_DEBUG_SEVERITY_MEDIUM: qDebug() << "Severity: medium"; break;
case GL_DEBUG_SEVERITY_LOW: qDebug() << "Severity: low"; break;
case GL_DEBUG_SEVERITY_NOTIFICATION: qDebug() << "Severity: notification"; break;
}
}
class IssueRenderWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
IssueRenderWidget()
{
}
void initialize()
{
std::map<std::string, std::string> params;
params["useCurrentGLContext"] = "1";
params["winID"] = std::to_string(this->winId());
// params["winID"] = std::to_string(
// ignition::gui::App()->findChild<ignition::gui::MainWindow *>()->
// QuickWindow()-winId());
auto* engine = ignition::rendering::engine(engine_name_, params);
if (engine == nullptr)
{
ignerr << "Engine [" << this->engine_name_ << "] is not supported" << std::endl;
return;
}
// Scene
scene_ = engine->SceneByName(scene_name_);
if (!scene_)
{
igndbg << "Create scene [" << scene_name_ << "]" << std::endl;
scene_ = engine->CreateScene(scene_name_);
scene_->SetAmbientLight(ambient_light_);
scene_->SetBackgroundColor(background_color_);
}
scene_->SetSkyEnabled(true);
ignition::rendering::VisualPtr visual = scene_->VisualByName("tesseract_grid");
if (visual == nullptr)
{
ignition::rendering::VisualPtr root = scene_->RootVisual();
// create gray material
ignition::rendering::MaterialPtr gray = scene_->CreateMaterial();
gray->SetAmbient(0.7, 0.7, 0.7);
gray->SetDiffuse(0.7, 0.7, 0.7);
gray->SetSpecular(0.7, 0.7, 0.7);
// create grid visual
unsigned id = 1000; //static_cast<unsigned>(this->dataPtr->entity_manager.addVisual("tesseract_grid"));
ignition::rendering::VisualPtr visual = scene_->CreateVisual(id, "tesseract_grid");
ignition::rendering::GridPtr gridGeom = scene_->CreateGrid();
if (!gridGeom)
{
ignwarn << "Failed to create grid for scene ["
<< scene_->Name() << "] on engine ["
<< scene_->Engine()->Name() << "]"
<< std::endl;
return;
}
gridGeom->SetCellCount(20);
gridGeom->SetCellLength(1);
gridGeom->SetVerticalCellCount(0);
visual->AddGeometry(gridGeom);
visual->SetLocalPosition(0, 0, 0.015);
visual->SetMaterial(gray);
root->AddChild(visual);
}
else
{
visual->SetVisible(true);
}
auto root = scene_->RootVisual();
// Camera
camera_ = scene_->CreateCamera();
camera_->SetUserData("user-camera", true);
root->AddChild(camera_);
camera_->SetLocalPose(camera_pose_);
camera_->SetNearClipPlane(camera_near_clip_);
camera_->SetFarClipPlane(camera_far_clip_);
camera_->SetImageWidth(texture_size_.width());
camera_->SetImageHeight(texture_size_.height());
camera_->SetAntiAliasing(8);
camera_->SetHFOV(M_PI * 0.5);
/** @todo LEVI Need figure out haw to get the camera by name. */
// create directional light
ignition::rendering::DirectionalLightPtr light0 = scene_->CreateDirectionalLight();
light0->SetDirection(1, 0, 0);
light0->SetDiffuseColor(0.8, 0.8, 0.8);
light0->SetSpecularColor(0.5, 0.5, 0.5);
camera_->AddChild(light0);
initialized_ = true;
}
void resizeGL(int w, int h)
{
glViewport( 0, 0, w, h );
// Resizing camera causes issues, but not sure why
texture_size_ = QSize(w, h);
texture_dirty_ = true;
ignerr << "Resized" << std::endl;
}
void initializeGL()
{
ignerr << "initializeGL" << std::endl;
initializeOpenGLFunctions();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
auto* f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();
f->glDebugMessageCallback(glDebugOutput, nullptr);
// Initialize renderer
if (!initialized_)
initialize();
// check if engine has been successfully initialized
if (!initialized_)
{
ignerr << "Unable to initialize renderer" << std::endl;
}
}
void paintGL()
{
ignerr << "paintGL" << std::endl;
if (!initialized_)
return;
if (texture_dirty_)
{
camera_->SetImageWidth(texture_size_.width());
camera_->SetImageHeight(texture_size_.height());
camera_->SetAspectRatio(static_cast<double>(texture_size_.width()) / static_cast<double>(texture_size_.height()));
// setting the size should cause the render texture to be rebuilt
camera_->PreRender();
texture_dirty_ = false;
}
GLuint texture_id = camera_->RenderTextureGLId();
image_ = camera_->CreateImage();
camera_->Capture(image_);
// {
// ignition::common::Image tmp;
// tmp.SetFromData(data, image.Width(), image.Height(), ignition::common::Image::RGB_INT8);
// tmp.SavePNG("/tmp/ign_image.png");
// }
// ignition::rendering::Image image(image_);
auto* data = image_.Data<unsigned char>();
makeCurrent();
auto imgw = image_.Width();
auto imgh = image_.Height();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
bool use_texture{false};
if (use_texture)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glEnable(GL_TEXTURE_RECTANGLE);
glViewport (0, 0, (GLsizei) imgw, (GLsizei) imgh);
glDeleteTextures(1, &texture_);
glGenTextures (1, &texture_);
glBindTexture (GL_TEXTURE_RECTANGLE, texture_);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glTexImage2D (GL_TEXTURE_RECTANGLE, 0, GL_RGBA8, (GLint)imgw, (GLint)imgh, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glBegin (GL_QUADS);
// Bottom left
glTexCoord2d (imgw, imgh);
glVertex2f(-1, -1);
// Top left
glTexCoord2d (0, imgh);
glVertex2f (1, -1);
// Top right
glTexCoord2d (0, 0);
glVertex2f (1, 1);
// Bottom right
glTexCoord2d (imgw, 0);
glVertex2f (-1, 1);
glEnd();
glDisable(GL_TEXTURE_RECTANGLE);
}
else
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelZoom(1, -1);
glRasterPos2f(-1, 1);
glDrawPixels(imgw, imgh, GL_RGB, GL_UNSIGNED_BYTE, data);
}
doneCurrent();
}
protected:
bool initialized_{false};
std::string engine_name_{"ogre"};
std::string scene_name_{"IssueScene"};
ignition::rendering::ScenePtr scene_{nullptr};
ignition::rendering::CameraPtr camera_{nullptr};
ignition::math::Color background_color_{ignition::math::Color::Black};
ignition::math::Color ambient_light_{ignition::math::Color(0.3f, 0.3f, 0.3f, 1.0f)};
ignition::math::Pose3d camera_pose_ {ignition::math::Pose3d(0, 0, 2, 0, 0.4, 0)};
double camera_near_clip_ {0.01};
double camera_far_clip_ {1000.0};
QSize texture_size_ {QSize(1920, 1200)};
bool texture_dirty_{true};
GLuint texture_{2};
ignition::rendering::Image image_;
};
#endif // MINIMAL_EXAMPLE_H
main.cpp #include <QApplication>
#include <QDebug>
#include "minimal_example.h"
int main(int argc, char ** argv)
{
QApplication app(argc, argv);
IssueRenderWidget widget;
widget.show();
return app.exec();
}
CMakeLists.txt find_package(ignition-rendering6 REQUIRED)
find_package(ignition-common4 COMPONENTS profiler events av REQUIRED)
find_package(Qt5 COMPONENTS Core Widgets Gui OpenGL REQUIRED)
find_package(OpenGL REQUIRED)
QT5_WRAP_CPP(MINIMAL_EXAMPLE_WIDGET_headers_MOC minimal_example.h)
add_executable(${PROJECT_NAME}_minimal_example
${MINIMAL_EXAMPLE_WIDGET_headers_MOC}
main.cpp)
target_link_libraries(${PROJECT_NAME}_minimal_example PUBLIC
ignition-rendering6::ignition-rendering6
ignition-common4::ignition-common4
Qt5::Core Qt5::Widgets Qt5::Gui Qt5::OpenGL
${OPENGL_LIBRARIES})
target_include_directories(${PROJECT_NAME}_minimal_example PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include>")
install_targets(TARGETS
${PROJECT_NAME}_minimal_example) |
This was resolved by adding these lines. @chapulina I have little experience with opengl but learning more each day. Do you or anyone else know why these would be needed when using the QOpenglWidget but not in the glut example? I assuming it may be a configuration settings not exactly being the same but not sure where to start looking.
|
Hi @Levi-Armstrong , glad you found a workaround. Unfortunately I also don't have much experience there. Maybe one of the |
I haven't had time to look into this. My understanding is that since |
@iche033 Is it possible to when capturing the image from camera to get different formats? |
in ign-rendering6 (or above) and ogre2 render engine, you should be able to do:
and the |
Thanks I will try it and report back. @iche033 Another thing I had to do which was different from the glut example was set the matrix modes to identity. glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelZoom(1, -1);
glRasterPos2f(-1, 1);
glDrawPixels(imgw, imgh, GL_RGB, GL_UNSIGNED_BYTE, data); This was required if I added these two lines. Do you have an idea why this would be required with QtOpenGLWidget but not when using glut? glPixelZoom(1, -1);
glRasterPos2f(-1, 1); |
I'm not too sure why the behavior is different from glut. One guess is that the QtOpenGLWidget might also be changing opengl parameters. The two lines were there to flip the image when drawn otherwise it would be upside down.
ahh that's not great. I don't know why though. If you're ok with using |
Is the default format of the data the same when using capture between ogre, ogre2, and optix? |
format of the data captured from a camera? yes the should be the same format, PF_R8G8B8 |
huh, then I am not sure why it is having an issue when switching to ogre2 if the data is formatted the same. |
@iche033 Here is the video showing the behavior when adding object to the scene that contain transparency. Screencast.2022-11-08.16.23.33.mp4 |
Okay, so I have narrowed it down a little further. I decided to just load the image from a file and use
Screencast.2022-11-08.23.39.19.mp4 |
I also tried using Qt objects to use the camera texture id and blit. Which has its own issue where the upper right triangle is black but the lower right triangle looks fine. See video. Any thoughts on why this would be happening?
Screencast.2022-11-09.09.57.17.mp4 |
It sounds to me that the ogre camera is rendering correctly but it's just that there are issues when the images are displayed to the screen? Another thing to try is disable the selection buffer that the camera is using for mousing picking. This is only other thing that is rendering apart from the camera. You can disable the render update here and see if it makes any difference. Mouse picking and camera control may not work but see if you still get the green, blue colors.
I haven't used |
That is correct. I should have included the full paintGL function which essentially does the following.
|
Well after working on this off and on for six months I finally was able to get it working. All I had to do was take pieces from this demo Screencast.2022-11-10.21.19.58.mp4 |
awesome! |
If anyone is interested in a working example take a look here at tesseract_qt/rendering. Next step is to work on adding back the functionality for rendering on another thread. After I get everything working, I will create an example similar to the qml example to add to this repository. |
Are there any examples on how you might leverage this with QOpenglWidget?
The text was updated successfully, but these errors were encountered: