Конвертируйте 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.width (),
imgGL.height (), 0, GL_RGBA, GL_UNSIGNED_BYTE,
imgGL.bits ());

Или, может быть, `glDrawPixels ()`?

glDrawPixels (imgGL.width (), imgGL.height (), GL_RGBA,
GL_UNSIGNED_BYTE, imgGL.bits ());

Я понял, как нарисовать 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;
}
0

Другие решения

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

Простой пример рендеринга локальной сцены с помощью 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;
}
0
По вопросам рекламы [email protected]