We develop an application on Unity3D which shall take the image from the screen and transfer it to Texture2D.
We have difficulties with performance on everage (feeble) devices.
The code is given below. We do a screenshot, then we read pixels (ReadPixels) - here the problem arises, an app runs terribly slow.
We tried to take the texture from the camera, but it doesn’t work because our scanner works in parallel with Kudan, and in turn it blocks access to the camera. Then we tried to limit the area of screen to scan (by taking for scanning a small window, but not full screen) - but there wasn’t visible increase in the performance.
Can anyone help with this?
Here is our code:
IEnumerator DecodeScreen()
{
yield return new WaitForEndOfFrame();
RenderTexture RT = new RenderTexture(Screen.width, Screen.height,24);
Texture2D screen = new Texture2D(RT.width, RT.height, TextureFormat.RGB24, false, false);
screen.ReadPixels(new Rect(0, 0, RT.width, RT.height), 0, 0);
screen.Apply();
Debug.Log(resultText.text);
GetComponent().targetTexture = null;
Destroy(RT);
}
There are few ways to improve this code or optional way to convert RenderTexture
to Texture2D
.
1.Declare WaitForEndOfFrame
as a variable outside the function so that you don't have to do that each time that function is called.
2.You are creating a new Texture2D
each time you call that function. Do that once in the Start
function then re-use it. You can freely resize the Texture if RenderTexture
width or height changes.
3.You are also creating new RenderTexture
each time you call that function too.
It's faster to use RenderTexture.GetTemporary
to get temporary RenderTexture
. When you are done using it, you can RenderTexture.ReleaseTemporary
to release it.
Texture2D screen = null;
WaitForEndOfFrame frameEndWait = new WaitForEndOfFrame();
void Start()
{
screen = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false, false);
}
IEnumerator DecodeScreen()
{
yield return frameEndWait;
RenderTexture RT = RenderTexture.GetTemporary(Screen.width, Screen.height, 24);
//Resize only when Texture2D is null or when its size changes
if (screen == null || screen.width != RT.width || screen.height != RT.height)
{
screen.Resize(RT.width, RT.height, TextureFormat.RGB24, false);
//screen = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false, false);
}
screen.ReadPixels(new Rect(0, 0, RT.width, RT.height), 0, 0);
screen.Apply();
RenderTexture.ReleaseTemporary(RT);
}
Here are other options you have:
Use Native plugins with C++:
Send RenderTexture.GetNativeTexturePtr()
to a native side of your C++ then create a OpenGL texture from that and load it from C# with pointer using the Texture2D.CreateExternalTexture
function and keep updating it with the Texture2D.UpdateExternalTexture
function.
The fastest way to do this is to abandon RenderTexture
. Use OpenGL glReadPixels
function to take screenshot from C++ side then send the image to Unity with pointer and load it with the Texture2D.CreateExternalTexture
function and keep updating it with the Texture2D.UpdateExternalTexture
function. You can modify the mouse pixel code from my other post and make it do this.