- Home /
RenderTexture to Texture2D
In the following piece of code that is supposed to take a screenshot, I don't understand why we need to call screenShot.ReadPixels to get Texture2D. A RenderTexture is already a texture, do we really need to use a time consuming operation like ReadPixel to turn it into a Texture2D? Can't we directly render a camera into a Texture2D? (In Cocos2d, there is a class called CCRenderTexture that extends CCTexture and that can be used to render scenes into. So there must be a way to do so, at least with OpenGL.)
public static void ScreenShot() {
RenderTexture rt = new RenderTexture((int)Futile.screen.pixelWidth, (int)Futile.screen.pixelHeight, 24);
Futile.instance.camera.targetTexture = rt;
Texture2D screenShot = new Texture2D((int)Futile.screen.pixelWidth, (int)Futile.screen.pixelHeight, TextureFormat.RGB24, false);
Futile.instance.camera.Render();
RenderTexture.active = rt;
screenShot.ReadPixels(new Rect(0, 0, (int)Futile.screen.pixelWidth, (int)Futile.screen.pixelHeight), 0, 0);
Futile.instance.camera.targetTexture = null;
RenderTexture.active = null;
//DestroyImmediate(rt);
var bytes = screenShot.EncodeToPNG();
System.IO.File.WriteAllBytes(Application.dataPath + "/screenshots/screen" + System.DateTime.Now.ToString("dd-MM-yyyy_HH-mm-ss") + ".png", bytes);
}
Answer by Eric5h5 · Jan 25, 2013 at 03:23 AM
You can't render a camera into a Texture2D; you can only render it into a RenderTexture. A RenderTexture is a Texture, but it's not a Texture2D. Both RenderTexture and Texture2D inherit from Texture. The RenderTexture is not accessible from main memory, so yes you do need to convert it.
How disappointing it is. $$anonymous$$y tests with RenderTextures give horrible performances, it's not usable on every frame. $$anonymous$$aybe I'm doing something wrong, I hope so.
A render texture can be assigned directly to a material (http://docs.unity3d.com/Documentation/Components/class-RenderTexture.html), so the bits stay in GPU memory. When you transfer data from GPU to CPU there will always be a performance hit.
RenderTexture has very fast performance. You don't need to convert to a Texture2D normally.
Thx Eric and Dave, that was my error. Now that I'm using RenderTexture directly in the $$anonymous$$aterial, it runs smooth.
ReadPixels shouldn't be costly, it's performed entirely on GPU, AFAI$$anonymous$$ (not copying data to the CPU/memory). Recalculating mip-maps adds some cost, so disable it if you don't need it.
I can concur with that. Its the "GetPixels" that is costly.
I just noticed that ReadPixels also does Gfx.ReadBackImage which seems slow. I am going to try Graphics.CopyTexture and tell you how it performs
Answer by Wolfram · Jan 25, 2013 at 12:52 PM
Simply use Application.CaptureScreenshot.
I didn't really want to make a screenshot, just understanding why rendering into a RenderTexture is so slow in Unity whereas it was so smooth with Cocos2d (direct OpenGL calls).
Answer by atrajano · Jun 21, 2019 at 06:49 AM
I find the EncodeToPNG very slow. What you can do is get the color32 and use System.Graphics to render it for you.
Answer by Pangamini · Jun 21, 2019 at 08:51 AM
I've just done a little research (coz i needed a similar thing) ReadPixels() does a GPU->CPU readback, which is very slow. Now depending on what you need, you can either
Use the RenderTexture directly in your further rendering. This is NOT suitable if you want to hold some game state data in there, as the renderTexture content can be lost by GPU/Driver on some events (screen resize, etc)
Use Graphics.CopyTexture(). This happens entirely on GPU, but you will not be able to read pixels to the CPU from this texture, nor call Apply() after other modifications - the GPU memory will be overwritten by outdated content. If you really need to read back the pixels at some time (eg. I do it when I do the savegame) You can do:
This:
bool[] data = new bool[ra.width * ra.height]; // Copying the m_revealedArea to itself using temporary RT // m_revealedArea is filled by Graphics.CopyTexture() which only affects GPU memory. GetPixels32() would not return the actual content. // Blitting the m_revealedArea to the tempRT allows us to do ReadPixels() in the other direction and finally alling the GetPixels32() var tempRT = RenderTexture.GetTemporary(m_revealedArea.width, m_revealedArea.height, 0, RenderTextureFormat.ARGB32); try { Graphics.Blit(m_revealedArea, tempRT); RenderTexture.active = tempRT; m_revealedArea.ReadPixels(new Rect(0, 0, tempRT.width, tempRT.height), 0, 0); m_revealedArea.Apply(); } finally { RenderTexture.ReleaseTemporary(tempRT); } Color32[] color = m_revealedArea.GetPixels32();
Your answer
Follow this Question
Related Questions
Texture2D saves as PNG correctly but doesn't display properly in RawImage 1 Answer
Taking Non Power of Two Resolution Screen Shots 0 Answers
Call camera.Render() twice: RenderTexture contents differs from ReadPixels() 1 Answer
How can I save the Bild from a Camera, which not main camera is. 1 Answer
Get RenderTexture 1 Answer