【问题标题】:Convert Coin3D SoOffscreenRenderer to QImage and render with OpenGL将 Coin3D SoOffscreenRenderer 转换为 QImage 并使用 OpenGL 渲染
【发布时间】:2016-02-26 19:29:15
【问题描述】:

我正在尝试使用 SoOffscreenRendererQGLWidget 中显示带有 QT 的 Coin3D/Open Inventor 场景,我需要帮助将其转换为 QImage

到目前为止,我尝试的是将场景渲染到 SoOffscreenRenderer 并像这样获取缓冲区:

unsigned char * getCoinCubeImgBuffer(){
  // [...] create the scene, add lightning and camera

  SoOffscreenRenderer offscreenRenderer(vpRegion);
  offscreenRenderer.setComponents(
                      SoOffscreenRenderer::Components::RGB_TRANSPARENCY
                    );
  SbBool ok = offscreenRenderer.render(root);

  // to be sure that something is actually rendered
  // save the buffer content to a file
  SbBool ok = offscreenRenderer.render(root);
  qDebug() << "SbBool ok?" << ok;
  qDebug() << "wasFileWrittenRGB" << 
    offscreenRenderer.writeToRGB("C:/test-gl.rgb");
  qDebug() << "wasFileWrittenPS" << 
    offscreenRenderer.writeToPostScript("C:/test-gl.ps");


  unsigned char * imgbuffer = offscreenRenderer.getBuffer();
  return imgbuffer;
}

然后从缓冲区数据中创建一个QImage

QImage convertImgBuffer(){
  unsigned char *const imgBuffer = getCoinCubeImgBuffer();
  QImage img(imgBuffer, windowWidth, windowHeight, QImage::Format_ARGB32);

  // Important!
  img = img.rgbSwapped();

  QImage imgGL = convertToGLFormat(img);
  return imgGL;
}

这是正确的做法吗?

this question about drawing a QImage中所述,如果来源是图片,我可以绘制它。

e:为了确保我的缓冲区确实包含一个场景,我将缓冲区内容写入两个文件。例如,您可以使用 IrfanView 及其插件查看 .rgb 和 .ps 文件。

e2:刚刚想通了,我必须使用img.rgbSwapped()。现在它显示了黑白且没有闪电的场景。我会进一步调查。

e3:使用这样的代码,你需要以这种方式调整OpenGL调用以进行彩色渲染

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex.width(), 
    tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());

第一种格式是 GL_RGB,第二种是 GL_RGBA。立方体仍然是全黑的。

e4:这是我的场景中的一个错误,您必须在添加其余部分之前添加灯光,尤其是在添加相机之前。


所以现在我既可以使用 `QGLWidget` 的函数,如`bindTexture()`,也可以使用直接的 OpenGL 调用,但我不确定具体如何。如果有人能把我推向正确的方向,那就太好了。 我不能像这样使用OpenGL吗? glEnable(GL_TEXTURE_2D); glGenTextures(1, &offscreenBufferTexture); glBindTexture(GL_TEXTURE_2D, offscreenBufferTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imgGL.width(), imgGL.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, imgGL.bits()); 或者也许是`glDrawPixels()`? glDrawPixels(imgGL.width(), imgGL.height(), GL_RGBA, GL_UNSIGNED_BYTE,imgGL.bits());


我想出了如何使用 OpenGL 绘制 QImage,请参阅 this thread。所以似乎是缓冲区或它的转换有问题。

【问题讨论】:

    标签: c++ qt opengl openinventor


    【解决方案1】:

    这是正确渲染场景的结果代码。

    首先创建一个有效的场景

    void loadCoinScene(){
        // Init Coin
        SoDB::init();
        // The root node
        root = new SoSeparator;
        root->ref();
    
        // Add the light _before_ you add the camera
        SoDirectionalLight * light = new SoDirectionalLight;
        root->addChild(light);
    
        vpRegion.setViewportPixels(0, 0, coinSceneWidth, coinSceneHeight);
    
        SoPerspectiveCamera *perscam = new SoPerspectiveCamera();
        root->addChild(perscam);
    
        SbRotation cameraRotation = SbRotation::identity();
        cameraRotation *= SbRotation(SbVec3f(0, 1, 0), 0.4f);
        perscam->orientation = cameraRotation;
    
        SoCube * cube = new SoCube;
        root->addChild(cube);
        // make sure that the cube is visible
        perscam->viewAll(root, vpRegion);
    }
    

    然后将场景渲染到 Offscreen Buffer 并转换为QImage

    QImage getCoinCubeImgBuffer(){
        SoOffscreenRenderer offscreenRenderer(vpRegion);
        offscreenRenderer.setComponents(
          SoOffscreenRenderer::Components::RGB_TRANSPARENCY
        );
        offscreenRenderer.render(root);
    
        QImage img(offscreenRenderer.getBuffer(), coinSceneWidth, 
            coinSceneHeight, QImage::Format_ARGB32);
    
        // Important!
        return img.rgbSwapped();
    }
    

    如果您现在想使用 OpenGL 渲染 QImage,请使用我在 Render QImage with OpenGL 问题中的解决方案并将 loadTexture2() 方法更改为:

    QImage loadTexture2(GLuint &textureID){
        glEnable(GL_TEXTURE_2D); // Enable texturing
    
        glGenTextures(1, &textureID); // Obtain an id for the texture
        glBindTexture(GL_TEXTURE_2D, textureID); // Set as the current texture
    
        QImage im = getCoinCubeImgBuffer();
        // Convert to OpenGLs unnamed format
        // The resulting GL format is GL_RGBA
        QImage tex = QGLWidget::convertToGLFormat(im);
    
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex.width(), tex.height(), 0, 
            GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
    
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    
        glDisable(GL_TEXTURE_2D);
    
        return tex;
    }
    

    【讨论】:

      【解决方案2】:

      我认为不需要通过 QImage 提供纹理。以下是一个工作示例:

      #include <QApplication>
      #include <QGLWidget>
      #include <Inventor/SoInput.h>
      #include <Inventor/SoOffscreenRenderer.h>
      #include <Inventor/nodes/SoSeparator.h>
      
      static GLuint textureID(0);
      
      class GLWidget : public QGLWidget
      {
      public:
          explicit GLWidget() : QGLWidget() {}
          ~GLWidget() {}
      protected:
          void initializeGL() {
              glShadeModel(GL_FLAT);
              glEnable(GL_LIGHTING);
              glEnable(GL_LIGHT0);
              static GLfloat lightAmbient[4] = { 1.0, 1.0, 1.0, 1.0 };
              glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
          }
          void paintGL() {
              if (!textureID)
                  return;
              glClearColor(0.4f, 0.1f, 0.1f, 1.0f);
              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      
              glEnable(GL_TEXTURE_2D);
              glBindTexture(GL_TEXTURE_2D, textureID);
      
              glBegin(GL_QUADS);
                  glTexCoord2f(0,0); glVertex3f(-1, -1, -1);
                  glTexCoord2f(1,0); glVertex3f( 1, -1, -1);
                  glTexCoord2f(1,1); glVertex3f( 1,  1, -1);
                  glTexCoord2f(0,1); glVertex3f(-1,  1, -1);
              glEnd();
      
              glDisable(GL_TEXTURE_2D);
          }
          void resizeGL(int width, int height) {
              int side = qMin(width, height);
              glViewport((width - side) / 2, (height - side) / 2, side, side);
      
              glMatrixMode(GL_PROJECTION);
              glLoadIdentity();
              glOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 1000.0);
              glMatrixMode(GL_MODELVIEW);
          }
      };
      
      int main(int argc, char *argv[])
      {
          QApplication app(argc, argv);
      
          GLWidget glWidget;
          glWidget.show();
      
          static const char * inlineSceneGraph[] = {
              "#Inventor V2.1 ascii\n",
              "\n",
              "Separator {\n",
              "  PerspectiveCamera { position 0 0 5 }\n",
              "  DirectionalLight {}\n",
              "  Rotation { rotation 1 0 0  0.3 }\n",
              "  Cone { }\n",
              "  BaseColor { rgb 1 0 0 }\n",
              "  Scale { scaleFactor .7 .7 .7 }\n",
              "  Cube { }\n",
              "\n",
              "  DrawStyle { style LINES }\n",
              "  ShapeHints { vertexOrdering COUNTERCLOCKWISE }\n",
              "  Coordinate3 {\n",
              "    point [\n",
              "       -2 -2 1.1,  -2 -1 1.1,  -2  1 1.1,  -2  2 1.1,\n",
              "       -1 -2 1.1,  -1 -1 1.1,  -1  1 1.1,  -1  2 1.1\n",
              "        1 -2 1.1,   1 -1 1.1,   1  1 1.1,   1  2 1.1\n",
              "        2 -2 1.1,   2 -1 1.1,   2  1 1.1,   2  2 1.1\n",
              "      ]\n",
              "  }\n",
              "\n",
              "  Complexity { value 0.7 }\n",
              "  NurbsSurface {\n",
              "     numUControlPoints 4\n",
              "     numVControlPoints 4\n",
              "     uKnotVector [ 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 ]\n",
              "     vKnotVector [ 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 ]\n",
              "  }\n",
              "}\n",
              NULL
          };
      
          SoInput in;
          in.setStringArray(inlineSceneGraph);
      
          glWidget.resize(600, 600);
          SoOffscreenRenderer renderer(SbViewportRegion(glWidget.width(),
                                                        glWidget.height()));
          renderer.setComponents(SoOffscreenRenderer::RGB_TRANSPARENCY);
          renderer.setBackgroundColor(SbColor(.0f, .0f, .8f));
          SoSeparator *rootScene = SoDB::readAll(&in);
          rootScene->ref();
          renderer.render(rootScene);
          rootScene->unref();
      
          glEnable(GL_TEXTURE_2D); // Enable texturing
      
          glGenTextures(1, &textureID); // Obtain an id for the texture
          glBindTexture(GL_TEXTURE_2D, textureID); // Set as the current texture
      
          glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                       renderer.getViewportRegion().getViewportSizePixels()[0],
                       renderer.getViewportRegion().getViewportSizePixels()[1],
                       0, GL_BGRA, GL_UNSIGNED_BYTE, renderer.getBuffer());
      
          glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
          glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
      
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      
          glDisable(GL_TEXTURE_2D);
      
          return app.exec();
      }
      

      【讨论】:

        【解决方案3】:

        用SoWin渲染局部场景的简单例子,Coin3D(从here下载SoWin)

        SoSeparator * CreateScene(SoSeparator* root)
        {
            root->ref();
            root->setName("root_node");
            SoPerspectiveCamera * camera = new SoPerspectiveCamera;
            camera->setName("simple_camera");
            SbRotation cameraRotation = SbRotation::identity();
            cameraRotation *= SbRotation(SbVec3f(1, 0, 0), -0.4f);
            cameraRotation *= SbRotation(SbVec3f(0, 1, 0), 0.4f);
            camera->orientation = cameraRotation;
        
            SoCone* cone1= new SoCone();    
            cone1->setName("Cone1");
        
            SoBaseColor * color = new SoBaseColor;
            color->setName("myColor");
        
            root->addChild(camera);   
            root->addChild(cone1);    
            root->addChild(color);    
        
            return root;
        }
        

        渲染上面创建的场景

        void RenderLocal()
        {
        
            HWND window = SoWin::init("IvExample");
            if (window==NULL) exit(1);
            SoWinExaminerViewer * viewer = new SoWinExaminerViewer(window);
        
            SoSeparator * root = new SoSeparator;
            auto* data = CreateScene(root);
            data->getNumChildren();
        
            viewer->setSceneGraph(root);
            viewer->show();
            SoWin::show(window);
            SoWin::mainLoop();
            delete viewer;
            root->unref();
        
        }
        

        从 iv 文件渲染场景

        int RenderFile()
        {
        
         HWND window = SoWin::init("Iv");
            if (window==NULL) exit(1);
            SoWinExaminerViewer * viewer = new SoWinExaminerViewer(window);
        
             SoInput sceneInput;   
             if ( !sceneInput.openFile( "example.iv" ) )    
                 return -1;
             if ( !sceneInput.openFile(cPath) )    
                 return -1;
             SoSeparator *root =SoDB::readAll( &sceneInput );  
             root->ref();   
             viewer->setSceneGraph(root);  
        
             viewer->show();
             SoWin::show(window);
             SoWin::mainLoop();
             delete viewer;
          }
        

        【讨论】:

          猜你喜欢
          • 2013-12-13
          • 2014-06-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-15
          • 2018-08-27
          相关资源
          最近更新 更多