Hamdi
Hamdi

Reputation: 197

Converting to a Render texture from Rect2d

I am generating a texture2D from the code given below. But instead of Rect, I want to transfer the contents of my Render Texture onto Texture2D. As my render texture is attached to a secondary camera.

I want to Copy the contents to the Texture2D I am generating inside the code. How do I achieve this?

public RenderTexture rt;
Texture2D mTexture;
Rect mRect;

void Start () {
 //Create a rectangle width and height of the screen
 mRect = new Rect (0, 0, Screen.width, Screen.height);
 //Create a texture the size of the rectangle you just created
 mTexture = new Texture2D ((int) mRect.width, (int) mRect.height, TextureFormat.BGRA32, false); //Get RenderTexture contents
}

void Update()
{
  StartCoroutine (GetBytes_RT());
}

IEnumerator GetBytes_RT() {
 yield return new WaitForEndOfFrame ();
 //Read the Pixels inside the Rectangle
 mTexture.ReadPixels (mRect, 0, 0);
 //Apply the Pixels read from the rectangle to the texture
 mTexture.Apply ();
 // Get the Raw Texture data from the the from the texture and apply it to an array of bytes
 byte[] bytes = mTexture.GetRawTextureData ();
 // Make enough space for the bytes array
 int size = Marshal.SizeOf (bytes[0]) * bytes.Length;
}

Upvotes: 1

Views: 374

Answers (1)

derHugo
derHugo

Reputation: 90629

See ReadPixels

This will copy a rectangular pixel area from the currently active RenderTexture or the view (specified by the source parameter) into the position defined by destX and destY. Both coordinates use pixel space - (0,0) is lower left.

So before reading you would also set the RenderTexture.active otherwise it just reads from the entire screen output

// Store the current RenderTexture (if any at all)
var beforeActiveRenderTexture = RenderTexture.active;

// Make your RenderTexture the active one
RenderTexture.active = rt;

// Now read from the active RenderTexture
mTexture.ReadPixels (mRect, 0, 0);
mTexture.Apply();

// Restore whatever was the previous state
RenderTexture.active = beforeActiveRenderTexture;
    
byte[] bytes = mTexture.GetRawTextureData ();
    
int size = Marshal.SizeOf (bytes[0]) * bytes.Length;

In general instead of starting a new routine every frame and using class fields I personally would rather use something like

// Yes if you use this return type Untiy automatically runs it as a Coroutine
IEnumerator Start () 
{    
    var rect = new Rect (0, 0, rt.width, rt.height);     
    var texture = new Texture2D (rect.width, rect.height, TextureFormat.BGRA32, false);

    // Yes this is fine as long as you yield somewhere inside
    while(true)
    {
        yield return new WaitForEndOfFrame ();
        
        var beforeActiveRenderTexture = RenderTexture.active;

        RenderTexture.active = rt;

        texture.ReadPixels (rect, 0, 0);
        texture.Apply();

        RenderTexture.active = beforeActiveRenderTexture;
    
        var bytes = texture.GetRawTextureData();
    
        var size = Marshal.SizeOf (bytes[0]) * bytes.Length;
    }
}

Upvotes: 1

Related Questions