Skip to content
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

Open
Levi-Armstrong opened this issue Feb 15, 2022 · 21 comments
Open

Example on how to leverage this with QOpenglWidget? #561

Levi-Armstrong opened this issue Feb 15, 2022 · 21 comments
Labels
enhancement New feature or request

Comments

@Levi-Armstrong
Copy link
Contributor

Are there any examples on how you might leverage this with QOpenglWidget?

@Levi-Armstrong Levi-Armstrong added the enhancement New feature or request label Feb 15, 2022
@Levi-Armstrong
Copy link
Contributor Author

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 this->dataPtr->renderer.Render(); just uses the scene capture method to create an image. The saved image in the temp directory looks good. @chapulina do you know who might be able to shed some light on what I am doing wrong?

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();
}
};

image

@Levi-Armstrong
Copy link
Contributor Author

Levi-Armstrong commented Mar 20, 2022

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)

@Levi-Armstrong
Copy link
Contributor Author

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.

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
  glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);

@chapulina
Copy link
Contributor

Hi @Levi-Armstrong , glad you found a workaround. Unfortunately I also don't have much experience there. Maybe one of the ign-rendering maintainers can pitch in if they have time.

@iche033
Copy link
Contributor

iche033 commented Apr 8, 2022

I haven't had time to look into this. My understanding is that since GL_UNPACK_ALIGNMENT defaults to 4 and we're using RGB image format here (3 bytes) with resizable image width, I think it makes sense to set it to 1 when calling glDrawPixels as that should work for tightly packed image data with no padding. You may not have to set GL_UNPACK_ALIGNMENT if the data is RGBA I think.

@Levi-Armstrong
Copy link
Contributor Author

@iche033 Is it possible to when capturing the image from camera to get different formats?

@iche033
Copy link
Contributor

iche033 commented Apr 8, 2022

in ign-rendering6 (or above) and ogre2 render engine, you should be able to do:

camera->SetImageFormat(PF_R8G8B8A8);

and the Image created by the camera should be RGBA. Then just change GL_RGB to GL_RGBA when calling glDrawPixels. See if that works

@Levi-Armstrong
Copy link
Contributor Author

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);

@Levi-Armstrong
Copy link
Contributor Author

Another interesting thing is if I switch from ogre to ogre2 I end up with the following but using the glut example every works fine.

ogre2:
image

ogre1:
image

@iche033
Copy link
Contributor

iche033 commented Apr 18, 2022

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?

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.

Another interesting thing is if I switch from ogre to ogre2 I end up with the following but using the glut example every works
fine.

ahh that's not great. I don't know why though. If you're ok with using ogre, I think you can stick with RGB format and call glPixelStorei(GL_UNPACK_ALIGNMENT, 1); as you don't really need RGBA format for displaying the result to screen

@Levi-Armstrong
Copy link
Contributor Author

Levi-Armstrong commented Apr 19, 2022

Is the default format of the data the same when using capture between ogre, ogre2, and optix?

@iche033
Copy link
Contributor

iche033 commented Apr 19, 2022

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

@Levi-Armstrong
Copy link
Contributor Author

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.

@Levi-Armstrong
Copy link
Contributor Author

@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

@Levi-Armstrong
Copy link
Contributor Author

Okay, so I have narrowed it down a little further. I decided to just load the image from a file and use glDrawPixels which works fine. Then is just enabled calling capture on the camera but not use the data and interestingly the green and blue showed up over the image that is loading from a file. In video you can see that I use the mouse to manipulate the camera in the scene, but I am only drawing a static image. This indicates to me that something in render engine is using the texture id that glDrawPixels uses but not sure how best to resolve this. @iche033 Any thoughts?

   ignition::common::Image image("/tmp/ign_image.png");
   unsigned char *data = nullptr;
   unsigned int cnt = 0;
   image.Data(&data, cnt);
Screencast.2022-11-08.23.39.19.mp4

@Levi-Armstrong
Copy link
Contributor Author

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?

  makeCurrent();
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  glBindTexture(GL_TEXTURE_2D, this->dataPtr->renderer.texture_id);
  this->dataPtr->texture_blitter.bind(GL_TEXTURE_2D);
  const QRect targetRect(QPoint(0, 0), size());
  QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, QRect(QPoint(0, 0), this->dataPtr->renderer.textureSize));
  target.translate(0, 0, -1); // If all zeros the scene is randomly visible.
  this->dataPtr->texture_blitter.blit(this->dataPtr->renderer.texture_id, target, QOpenGLTextureBlitter::OriginTopLeft);
  this->dataPtr->texture_blitter.release();
  doneCurrent();
Screencast.2022-11-09.09.57.17.mp4

@iche033
Copy link
Contributor

iche033 commented Nov 9, 2022

This indicates to me that something in render engine is using the texture id that glDrawPixels uses but not sure how best to resolve this. @iche033 Any thoughts?

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 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?

I haven't used QOpenGLWidget / QOpenGLTextureBlitter before. A quick look at the doc and examples, it seems fine. Just checking that your this->dataPtr->renderer.texture_id is set to the GLId that you get from RenderTextureGLId?

@Levi-Armstrong
Copy link
Contributor Author

I haven't used QOpenGLWidget / QOpenGLTextureBlitter before. A quick look at the doc and examples, it seems fine. Just checking that your this->dataPtr->renderer.texture_id is set to the GLId that you get from RenderTextureGLId?

That is correct. I should have included the full paintGL function which essentially does the following.

  makeCurrent();
  this->dataPtr->renderer.camera->Capture();
  this->dataPtr->renderer.texture_id = this->dataPtr->renderer.camera->RenderTextureGLId();
 doneCurrent();

  makeCurrent();
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  glBindTexture(GL_TEXTURE_2D, this->dataPtr->renderer.texture_id);
  this->dataPtr->texture_blitter.bind(GL_TEXTURE_2D);
  const QRect targetRect(QPoint(0, 0), size());
  QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, QRect(QPoint(0, 0), this->dataPtr->renderer.textureSize));
  target.translate(0, 0, -1); // If all zeros the scene is randomly visible.
  this->dataPtr->texture_blitter.blit(this->dataPtr->renderer.texture_id, target, QOpenGLTextureBlitter::OriginTopLeft);
  this->dataPtr->texture_blitter.release();
  doneCurrent();

@Levi-Armstrong
Copy link
Contributor Author

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 simple_demo_qml around using shared context and using QOffscreenSurface to have it render here then use the QOpenGLTextureBlitter render it to the widget and everything is now working. I will spend time cleaning things up and creating a demo to add here.

Screencast.2022-11-10.21.19.58.mp4

@iche033
Copy link
Contributor

iche033 commented Nov 11, 2022

awesome!

@Levi-Armstrong
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants