我尝试过使用土壤和恶魔图像库,但创建的屏幕截图是完全黑色的图像。对于魔鬼,我使用了此处找到的功能用openGL截屏并将其保存为png,但图像仍然是黑屏。
关于保存屏幕截图或导出 opengl 输出的任何想法?
我尝试过使用土壤和恶魔图像库,但创建的屏幕截图是完全黑色的图像。对于魔鬼,我使用了此处找到的功能用openGL截屏并将其保存为png,但图像仍然是黑屏。
关于保存屏幕截图或导出 opengl 输出的任何想法?
尝试这个:
#include <vector>
#include <GL/glut.h>
#include <SOIL/SOIL.h>
using namespace std;
bool save = false;
void display()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( -2, 2, -2, 2, -1, 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3ub( 255, 0, 0 );
glBegin( GL_QUADS );
glVertex2i( -1, -1 );
glVertex2i( 1, -1 );
glVertex2i( 1, 1 );
glVertex2i( -1, 1 );
glEnd();
if( save )
{
int w = glutGet( GLUT_WINDOW_WIDTH );
int h = glutGet( GLUT_WINDOW_HEIGHT );
vector< unsigned char > buf( w * h * 3 );
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
glReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &buf[0] );
int err = SOIL_save_image
(
"img.bmp",
SOIL_SAVE_TYPE_BMP,
w, h, 3,
&buf[0]
);
save = false;
}
glutSwapBuffers();
}
void keyboard( unsigned char key, int x, int y )
{
if( key == 's' )
{
save = true;
glutPostRedisplay();
}
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutKeyboardFunc( keyboard );
glutMainLoop();
return 0;
}
从 OpenGL 渲染中保存屏幕截图时最大的问题是,常规系统窗口(通常用作 OpenGL 的绘图画布)的帧缓冲区是非常不可靠的数据源。如果它(部分)被其他窗口遮挡,则某些部分可能根本不包含任何定义的数据。缓冲区交换后,后台缓冲区的内容未定义,等等。
一些基本规则:
如果从常规窗口捕获屏幕截图,请从任一窗口捕获它们
绘制完成后但缓冲区交换之前的后台缓冲区(glReadPixels 意味着管道中所有绘制操作的刷新和完成,因为它引入了一个同步点)
缓冲区交换后的前缓冲区
要获得可靠的 OpenGL 渲染捕获,您应该渲染到帧缓冲区对象。那里的图像定义明确,不会在窗口失效和动画循环或其他奇怪情况之间的一些难以跟踪和调试的竞争条件下“消失”。要显示图片,然后从 FBO 到主帧缓冲区。
虽然 genpfault 的回答很好地完成了这项工作,但它让我找到了一个更清洁的解决方案:
if (!SOIL_save_screenshot("screenshot.bmp",
SOIL_SAVE_TYPE_BMP, 0, 0, width, height)) {
// Handle error here
}
这样您就不必设置缓冲区、调用glReadPixels
等。SOIL 可以自动为您处理所有这些!
另请注意,根据 genpfault 对 pslayer89 评论的响应,您需要添加SOIL_FLAG_INVERT_Y
到第二个参数中传递的标志(除非您已经使用投影/模型矩阵反转 Y 轴)。