Reputation: 13
Basically I want a function that can take screenshot to a thumbnail in runtime.
here is my code run after RenderPipelineManager.endCameraRendering
in URP in 2022.3:
private void TakeScreenshot(int w, int h)
{
shouldTakeScreenshot = false;
RenderTexture rt = RenderTexture.GetTemporary(w, h, 16, RenderTextureFormat.ARGB32);
Camera.main.targetTexture = rt;
Texture2D t = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
//RenderTexture.active = rt;
//Graphics.CopyTexture(rt, t);
t.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
RenderTexture.ReleaseTemporary(Camera.main.targetTexture);
Camera.main.targetTexture = null;
//RenderTexture.active = null;
//t.Apply();
//ri.texture = t;
screenshotBytes = ImageConversion.EncodeToJPG(t, 25);
}
I had a fully working TakeScreenshot()
to take a Screen size Screenshot, the code is same as above without all the comment.
the main problem is:
without all the comment, it did output the size i want but it's not scaled like this
which it try to not release the RenderTexture by commenting
//RenderTexture.ReleaseTemporary(Camera.main.targetTexture);
//Camera.main.targetTexture = null;
the rendertexture in main cam seems correct, what should i do?
the other problems I'm experiencing is:
I saw so many solution, they all have RenderTexture.active = rt;
,
but once i uncomment it, it just a black screen, same as Graphics.CopyTexture(rt, t);
but it's gray.
Upvotes: 1
Views: 756
Reputation: 90813
Afaik without setting the RenderTexture
active the ReadPixels
will directly read from your screen instead.
The result you observed in the Inspector is actually only being rendered into the temporary render texture at the end of the frame after your code already finished.
Usually you need these additional steps:
ReadPixels
in order to read from the rt
instead of the screenso something like e.g.
private void TakeScreenshot(int w, int h)
{
shouldTakeScreenshot = false;
var rt = RenderTexture.GetTemporary(w, h, 16, RenderTextureFormat.ARGB32);
Camera.main.targetTexture = rt;
// Required to actually fill the rt
Camera.Render();
var t = new Texture2D(w, h, TextureFormat.ARGB32, false);
// Required in order to not read from screen but from rt
var previousRT = RenderTexture.active;
RenderTexture.active = rt;
t.ReadPixels(new Rect(0, 0, w, h), 0, 0);
RenderTexture.ReleaseTemporary(rt);
Camera.main.targetTexture = null;
RenderTexture.active = previousRT;
// Not sure if required if not to be displayed in the scene
// might be able to be omitted
t.Apply();
screenshotBytes = ImageConversion.EncodeToJPG(t, 25);
// Important! Without this your memory will bit by bit be filled
// as textures (as other UnityEngine.Object based types) are not GC collected
Destroy(t);
}
Might still want to performance check again whether ReadPixels
is faster than Graphics.CopyTexture(rt, t);
.
Upvotes: 1