OpenGL:将纹理复制到主内存

时间:2018-02-16 15:04:39

标签: c++ opengl-es opengl-es-2.0 unity5

对于Unity中的项目,我正在尝试编写本机(C ++)插件,我的目标是将纹理数据导入主系统内存。我知道Unity提供了类似的功能,已经实现了这个功能(Texture2D.GetRawTextureData())。调用此函数的不幸副作用是每次调用时都会分配一大块内存,而且我每次都会运行此调用,这会经常触发垃圾回收(读取:每帧)

所以我在这里尝试编写一个使用预先分配的缓冲区的类似函数,将缓冲区的地址传递给C ++插件并将纹理数据复制到此处。但是,返回的纹理数据全部为黑色(因此所有值都设置为0)。我做错了什么,或者在检索这些数据时忘了考虑什么?

Unity(C#)中调用插件的代码如下:

private Texture2D tempTexture = null;
private byte[] textureBuffer = null;
private IntPtr textureHandle;

public void StartStream(StreamerOptions options)
{
    ...
    tempTexture = new Texture2D(options.width, options.height, TextureFormat.RGBA32, false);
    textureBuffer = new byte[options.width * options.height * 4];
    textureHandle = tempTexture.GetNativeTexturePtr();
    ...
}

private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
    if (IsStreaming)
    {
        Graphics.Blit(source, destination, material, 0);
        tempTexture.ReadPixels(new Rect(0, 0, attachedCamera.targetTexture.width, attachedCamera.targetTexture.height), 0, 0, false);
        tempTexture.Apply();
    }
}

private void OnPostRender()
{
    if (IsStreaming)
    {
        FetchTexture(textureHandle, textureBuffer);
        pipe.Write(textureBuffer);
        // pipe.Write(tempTexture.GetRawTextureData());
    }
}

在函数OnPostRender中,我调用插件来获取纹理数据。检索OpenGL的C ++代码如下:

void RenderAPI_OpenGLCoreES::FetchTextureData(void *textureHandle, uint8_t *textureData)
{
    GLuint glTextureName = static_cast<GLuint>(reinterpret_cast<intptr_t>(textureHandle));
    glBindTexture(GL_TEXTURE_2D, glTextureName);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_BYTE, textureData);
}

1 个答案:

答案 0 :(得分:0)

使用Unity Answers上的解决方案回答我自己的问题: https://answers.unity.com/questions/1305191/glreadpixels-from-a-rendertexture.html

我使用示例unity native-plugin项目作为基础并开始剥离我不需要的功能。

最重要的部分是初始化GLEW子系统。

glewExperimental = GL_TRUE;
glewInit();
glGetError(); // Clean up error generated by glewInit

之后,我可以使用链接答案中的代码开始读取纹理数据:

void RenderAPI_OpenGLCoreES::ReadPixels(void *data, int textureWidth, int textureHeight)
{
   int currentFBORead;
   int currentFBOWrite;
   glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &currentFBORead);
   glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &currentFBOWrite);

   glBindFramebuffer(GL_READ_FRAMEBUFFER, currentFBOWrite);
   glReadPixels(0, 0, textureWidth, textureHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
   glBindFramebuffer(GL_READ_FRAMEBUFFER, currentFBORead);
}