Hi All

I am attempting to capture an area of the screen and save it as a Texture2D. This is a 2D app so uses an Orthographic camera (No need to worry about perspective). I have managed to create a GUI.Box at the exact place I want the texture grab to occur but cant now work out how to actually get the pixels from the Rect of the GUI.Box as a texture.

I know I have to use a RenderTexture but not sure how I can convert GUI space to a coordinate system that works with Texture2D.ReadPixels. Any hints please?

Many thanks
Geoff

public IEnumerator grabTexture() {	

yield return new WaitForEndOfFrame();


   // aMesh is a planar object used for selection, the user moves it around before a capture is performed.
	
    Bounds b = aMesh.renderer.bounds; 
    Camera cam = Camera.main;
 
    // All 8 vertices of the bounds
    pts[0] = cam.WorldToScreenPoint (new Vector3 (b.center.x + b.extents.x, b.center.y + b.extents.y, b.center.z + b.extents.z));
    pts[1] = cam.WorldToScreenPoint (new Vector3 (b.center.x + b.extents.x, b.center.y + b.extents.y, b.center.z - b.extents.z));
    pts[2] = cam.WorldToScreenPoint (new Vector3 (b.center.x + b.extents.x, b.center.y - b.extents.y, b.center.z + b.extents.z));
    pts[3] = cam.WorldToScreenPoint (new Vector3 (b.center.x + b.extents.x, b.center.y - b.extents.y, b.center.z - b.extents.z));
    pts[4] = cam.WorldToScreenPoint (new Vector3 (b.center.x - b.extents.x, b.center.y + b.extents.y, b.center.z + b.extents.z));
    pts[5] = cam.WorldToScreenPoint (new Vector3 (b.center.x - b.extents.x, b.center.y + b.extents.y, b.center.z - b.extents.z));
    pts[6] = cam.WorldToScreenPoint (new Vector3 (b.center.x - b.extents.x, b.center.y - b.extents.y, b.center.z + b.extents.z));
    pts[7] = cam.WorldToScreenPoint (new Vector3 (b.center.x - b.extents.x, b.center.y - b.extents.y, b.center.z - b.extents.z));
 
    //Convert to GUI Space so can draw box around area to capture (for testing mostly)
    for (int i=0;i<pts.Length;i++) pts_.y = Screen.height-pts*.y;*_

//Calculate the min and max positions
Vector3 min = pts[0];
Vector3 max = pts[0];
for (int i=1;i<pts.Length;i++) {
min = Vector3.Min (min, pts*);*
max = Vector3.Max (max, pts*);*
}

//Construct a rect
ScrRect = Rect.MinMaxRect (min.x,min.y,max.x,max.y);

* // Note: GUI.Box(ScrRect,“Captured Data”) works great from this Rect *

* // Invert the Y for ScreenSpace not GUI space*
* ScrRect.y = Screen.height - ScrRect.y;*

* // Grab texture from Rect*

* // This is a factor that enlarges the snapshot’s resolution. It sets the resolution of the rendertexture to a multiple of the Screen’s resolution.*
// If you don’t want that, just set it to 1.
int superSamplingFactor = 1;

Texture2D snapShot = new Texture2D((int)ScrRect.width * superSamplingFactor, (int)ScrRect.height * superSamplingFactor, TextureFormat.ARGB32, false);

RenderTexture snapShotRT = new RenderTexture(Screen.width * superSamplingFactor, Screen.height * superSamplingFactor, 24, RenderTextureFormat.ARGB32); // We’re gonna render the entire screen into this
RenderTexture.active = snapShotRT;
Camera.main.targetTexture = snapShotRT;
Camera.main.Render();

Rect lassoRectSS = new Rect(ScrRect.xMin * superSamplingFactor, ScrRect.yMin * superSamplingFactor, ScrRect.width * superSamplingFactor, ScrRect.height * superSamplingFactor);

snapShot.ReadPixels(lassoRectSS, 0, 0);
snapShot.Apply();
RenderTexture.active = null;
Camera.main.targetTexture = null;

// This is another planar mesh in the view so I can see the captured image
* display.material.mainTexture = snapShot;*

}

You have to render the camera manually into a RenderTexture, as you have correctly guessed, and then read out the pixels into a normal texture afterwards using Texture2D.ReadPixels. I implemented pretty much exactly what you’re requesting a while ago, and did it like this (simplified for demonstration here):

    // This is a factor that enlarges the snapshot's resolution. It sets the resolution of the rendertexture to a multiple of the Screen's resolution.
    // If you don't want that, just set it to 1.
    int superSamplingFactor = 3;

    Texture2D snapShot = new Texture2D((int)LassoRect.width * superSamplingFactor, (int)LassoRect.height * superSamplingFactor, TextureFormat.ARGB32, false);

    RenderTexture snapShotRT = new RenderTexture(Screen.width * superSamplingFactor, Screen.height * superSamplingFactor, 24, RenderTextureFormat.ARGB32); // We're gonna render the entire screen into this
    RenderTexture.active = snapShotRT;
    YourCamera.targetTexture = snapShotRT;
    YourCamera.Render();

    Rect lassoRectSS = new Rect(LassoRect.xMin * superSamplingFactor, LassoRect.yMin * superSamplingFactor, LassoRect.width * superSamplingFactor, LassoRect.height * superSamplingFactor);

    snapShot.ReadPixels(lassoRectSS, 0, 0);
    snapShot.Apply();
    RenderTexture.active = null;
    YourCamera.targetTexture = null;

The variable called LassoRect is the rectangle the user has selected on the screen. You mentioned you had that already? It’s the same Rect you use to draw that GUI.Box. It doesn’t matter if the camera called YourCamera is orthographic or perspective - the Texture2D will contain exactly the portion of the screen the user selected, as it would’ve been rendered to the screen by YourCamera.