Преобразование Coin3D SoOffscreenRenderer в QImage и рендеринг с OpenGL


Я пытаюсь отобразить сцену Coin3D/Open Inventor с QT в QGLWidget, используя SoOffscreenRenderer, и мне нужна помощь в преобразовании ее в 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;
}
Будет ли это правильным способом сделать это?

Как описано в этот вопрос о рисовании QImage, я могу нарисовать его, если источником является изображение.

E: Чтобы убедиться, что мой буфер действительно содержит сцену, я записываю содержимое буфера в два файла. Вы можете посмотреть .файлы rgb и. ps, например, с IrfanView плюс его плагины.

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.ширина(), имггл.height (), 0, GL_RGBA, GL_UNSIGNED_BYTE, имггл.биты()); Или, может быть, " glDrawPixels ()"? glDrawPixels (imgGL.width (), imgGL.height (), GL_RGBA, GL_UNSIGNED_BYTE, imggl_.биты());


Я понял, как нарисовать QImage с помощью OpenGL, см. этот поток. Так что, похоже, есть проблема с буфер или его преобразование.

3 3

3 ответа:

Вот полученный код, который правильно отображает сцену.

Сначала создайте допустимую сцену

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

Затем визуализируйте сцену в закадровый буфер и преобразуйте ее в 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();
}

Если теперь вы хотите отрисовать QImage с помощью OpenGL, используйте мое решение из моего рендеринга QImage с помощью 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;
}

Я не думаю, что есть необходимость кормить текстуру через 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();
}

Простой пример рендеринга локальной сцены с помощью SoWin, Coin3D (скачать 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;
  }