我目前正在开展一个项目,将物理模拟转换为iPhone本身的视频。
为此,我目前正在使用两个不同的循环。第一个循环在块中运行,其中AVAssetWriterInput对象轮询EAGLView以获取更多图像。 EAGLView提供存储它们的数组中的图像。
另一个循环是实际模拟。我已经关闭了模拟计时器,并且每次都使用预先指定的时间差来调用tick。每次调用tick时,我都会在交换缓冲区后在EAGLView的交换缓冲区方法中创建一个新图像。然后将此图像放在AVAssetWriter轮询的数组中。
还有一些杂项代码可以确保数组不会太大
所有这一切都很好,但非常慢。
我在做什么,从概念上讲,导致整个过程比它可能更慢?另外,有没有人知道从Open GL获取图像比glReadPixels更快的方法?
答案 0 :(得分:3)
视频内存的设计使其写入速度快,阅读速度慢。这就是我对纹理进行渲染的原因。这是我为将场景渲染为纹理而创建的整个方法(有一些自定义容器,但我认为用自己的容器替换它们非常简单):
-(TextureInf*) makeSceneSnapshot {
// create texture frame buffer
GLuint textureFrameBuffer, sceneRenderTexture;
glGenFramebuffersOES(1, &textureFrameBuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, textureFrameBuffer);
// create texture to render scene to
glGenTextures(1, &sceneRenderTexture);
glBindTexture(GL_TEXTURE_2D, sceneRenderTexture);
// create TextureInf object
TextureInf* new_texture = new TextureInf();
new_texture->setTextureID(sceneRenderTexture);
new_texture->real_width = [self viewportWidth];
new_texture->real_height = [self viewportHeight];
//make sure the texture dimensions are power of 2
new_texture->width = cast_to_power(new_texture->real_width, 2);
new_texture->height = cast_to_power(new_texture->real_height, 2);
//AABB2 = axis aligned bounding box (2D)
AABB2 tex_box;
tex_box.p1.x = 1 - (GLfloat)new_texture->real_width / (GLfloat)new_texture->width;
tex_box.p1.y = 0;
tex_box.p2.x = 1;
tex_box.p2.y = (GLfloat)new_texture->real_height / (GLfloat)new_texture->height;
new_texture->setTextureBox(tex_box);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, new_texture->width, new_texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, sceneRenderTexture, 0);
// check for completness
if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
new_texture->release();
@throw [NSException exceptionWithName: EXCEPTION_NAME
reason: [NSString stringWithFormat: @"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)]
userInfo: nil];
new_texture = nil;
} else {
// render to texture
[self renderOneFrame];
}
glDeleteFramebuffersOES(1, &textureFrameBuffer);
//restore default frame and render buffers
glBindFramebufferOES(GL_FRAMEBUFFER_OES, _defaultFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _colorRenderbuffer);
glEnable(GL_BLEND);
[self updateViewport];
glMatrixMode(GL_MODELVIEW);
return new_texture;
}
当然,如果你一直在做快照,那么你最好只创建一次纹理框架和渲染缓冲区(并为它们分配内存)。
答案 1 :(得分:1)
要记住的一件事是GPU正在从CPU异步运行,因此如果您在完成渲染后立即尝试执行glReadPixels,则必须等待命令刷新到GPU并在可以之前渲染读回来。
不是同步等待,而是将快照渲染到纹理队列中(使用像Max提到的FBO)。等到你在前一帧中的一个之前渲染了几帧之前。我不知道iPhone是否支持围栏或同步对象,但如果是这样,你可以在读取像素之前检查渲染是否完成。
答案 2 :(得分:1)
您可以尝试使用CADisplayLink对象来确保您的绘图速率和捕获率与设备的屏幕刷新率相对应。通过刷新和捕获每个设备屏幕刷新次数太多次,可能会减慢运行循环的执行时间。
根据应用程序的目标,您可能没有必要捕获您呈现的每个帧,因此在选择器中,您可以选择是否捕获当前帧。
答案 3 :(得分:0)
虽然这个问题并不新鲜,但还没有回答,所以我想我会投入。
glReadPixels确实非常慢,因此不能用于从OpenGL应用程序录制视频而不会对性能产生不利影响。
我们确实找到了一种解决方法,并创建了一个名为Everyplay的免费SDK,可以将基于OpenGL的图形记录到视频文件中,而不会造成性能损失。您可以在https://developers.everyplay.com/
查看