- Home /
How can I get the RenderTexture OpenGL texture ID?
I need to render the output of the editor into an external Windows window(on Windows 7). We are using a projector plugged on the second screen and we need to render into fullscreen to test what we have done. Since Unity do not support fullscreen rendering into the editor, I am working on a plugin to render the output of the editor into a win32 window which will render the texture on every pixels of the second screen.
I am sharing the OpenGL context with the unity window and I need to get the texture ID of the screen RenderTexture to render this texture into an OpenGL quad in an another window.
I created an image effect to intercept the result of the rendering. And I'm using the source RenderTexture to get the native OpenGL ID of the texture. However, it does no seems to be an OpenGL texture id.
When I call glBindTexture(GL_TEXTURE_2D, textureIndex_) in C++, it returns this error: "Texture was previously created with a target that doesn't match that of target.". Which means that the ID returned by RenderTexture.GetNativeTextureID() is not a GL_TEXTURE_2D id. Considering that a RenderTexture contains a depth texture too, maybe it's a Frame Buffer Object?
All call are done in the rendering thread since I'm using GL.IssuePluginEvent() to create/destroy/update my own OpenGL win32 window.
I'm wondering if I'm doing something wrong? Because the texture id returned by the RenderTexture do not seem to be an OpenGL texture ID.
Thanks for any help =).
Answer by adx · Jul 26, 2012 at 01:36 PM
Hi
From my short observation RenderTexture.GetNativeTextureID() return texture_2d id attached to FBO.
What I need is to get Frame Buffer Object ID but no idea how to obtain it.
Why FBO id is better:[PBO for async glGetTexImage, random slowdowns..][1]
[1]: http://www.opengl.org/discussion_boards/showthread.php/165657-PBO-for-async-glGetTexImage-random-slowdowns
I try to implement DMA transfer from FBO and display it on desktop - (WinXP).
I have tested both: glReadPixels,glGetTexImage and was not able to achieve good performance with DMA and glGetTexImage.
I am able to transfer data by glReadPixels (~10% CPU usage) but for that I need FBO id.
This is my short test program - maybe it helps a little (warning! I am FBO,PBO,VBO noob)
int texture_id=0;
//public Texture2D tex;
public RenderTexture tex;
IEnumerator Start () {
texture_id=tex.GetNativeTextureID();
yield return StartCoroutine("CallPluginAtEndOfFrames");
}
private IEnumerator CallPluginAtEndOfFrames ()
{
while (true) {
// Wait until all frame rendering is done
yield return new WaitForEndOfFrame();
// Set time for the plugin
SetTimeFromUnity (Time.timeSinceLevelLoad);
// Issue a plugin event with arbitrary integer identifier.
// The plugin can distinguish between different
// things it needs to do based on this ID.
// For our simple plugin, it does not matter which ID we pass here.
GL.IssuePluginEvent (texture_id);
}
}
Plugin code
-----------
extern "C" void EXPORT_API BlitTexture(int textureID)
{
//this is called from issue plubin event
static int index = 0;
int nextIndex = 0; // pbo index used for next frame
static bool b=0;
int textureWidth,textureHeight=512;
if (b==0)
{
// get pointers to GL functions
glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB");
glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB");
glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB");
glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)wglGetProcAddress("glBufferSubDataARB");
glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB");
glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)wglGetProcAddress("glGetBufferParameterivARB");
glMapBufferARB = (PFNGLMAPBUFFERARBPROC)wglGetProcAddress("glMapBufferARB");
glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)wglGetProcAddress("glUnmapBufferARB");
glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)wglGetProcAddress("glBindFramebufferEXT");
// create 2 pixel buffer objects, you need to delete them when program exits.
// glBufferDataARB with NULL pointer reserves only memory space.
glGenBuffersARB(PBO_COUNT, pboIds);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[0]);
glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_READ_ARB);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[1]);
glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_READ_ARB);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
b=1;
freopen("debug.txt", "a", stdout);
printf("SetTexture id:%d\n" ,textureID);
printf("PBO ID:%d %d\n" ,pboIds[0],pboIds[1]);
}
BITMAPINFOHEADER bhi;
bhi.biSize=sizeof(BITMAPINFOHEADER);
bhi.biWidth=512;
bhi.biHeight=512;
bhi.biPlanes=1;
bhi.biBitCount=32;
bhi.biCompression = BI_RGB;
bhi.biSizeImage=bhi.biWidth*bhi.biHeight*4;
bhi.biClrUsed=0;
bhi.biClrImportant=0;
bhi.biXPelsPerMeter=1000;
bhi.biXPelsPerMeter=1000;
// increment current index first then get the next index
// "index" is used to read pixels from a framebuffer to a PBO
// "nextIndex" is used to process pixels in the other PBO
index = (index + 1) % 2;
nextIndex = (index + 1) % 2;
//glReadBuffer(textureID);
//glBindTexture(GL_TEXTURE_2D, textureID);
// Use offset instead of pointer.
// OpenGL should perform asynch DMA transfer, so glReadPixels() will return immediately.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 1); //<-how to get this id from unity???
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);
glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, PIXEL_FORMAT, GL_UNSIGNED_BYTE, 0);
//glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
// map the PBO that contain framebuffer pixels before processing it
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);
GLubyte* src = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
if(src )
{
HDC dc=GetDC(0);
SetDIBitsToDevice(dc,0,0,512,512,0,0,0,512,src,(BITMAPINFO*)&bhi,DIB_RGB_COLORS);
ReleaseDC(0,dc);
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); // release pointer to the mapped buffer
}
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
}
hi , adx Thank you I want to learn it where I can find and down this demo?
Answer by Kibsgaard · Jan 17, 2015 at 03:00 AM
A solution is to issue the plugin in the OnPostRender of the camera that renders to your RenderTexture. Then you don't need to call
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 1);
as the render texture is already bound.
Alternativly you can set it from Unity with RenderTexture.active before you issue the plugin
Answer by Varaughe · Feb 15, 2017 at 07:16 AM
Example for displaying the unity camera view into an external window (for both OSX and Windows) , you could check : https://www.youtube.com/watch?v=9VSn-UBrHe0 . Unfortunately , it has been declined (without explanation) by the unity asset store team .