Преобразование 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: это была ошибка в моей сцене, вы должны добавить свет, прежде чем добавить остальное, и особенно прежде, чем добавить камеру.
Я понял, как нарисовать QImage с помощью OpenGL, см. этот поток. Так что, похоже, есть проблема с буфер или его преобразование.
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; }