- Home /
Texture2d.readPixels not working with iOS 6
I've made an iOS app with Unity 3.5.6 and QCAR for iPad. The app uses readPixels to take a screenshot of the AR scene and has worked great unless I try it on an iPad with iOS 6, then it only makes a black texture. I get the warning mentioned in the Unity 3.5.6 change log saying "ReadPixels was called to read pixels from system frame buffer, while not inside drawing frame." , but I get this error on an iOS 5.x device too and readpixels takes the screenshot. I'm calling readpixels in OnGUI() when a button is clicked, and use a co-routine to wait for the end of the current frame. I've tried it without the co-routine, with the co-routine between readPixels and Apply(), and tried calling readPixels in Update(), which captured only the background, no AR elements. Anyone else dealt with this?
void OnGUI(){
GUI.Box(new Rect(0, Screen.height - 125, Screen.width, 150), bottomBar, bottom);
// make screen capture button
if(GUI.Button(new Rect(309, 910, 150, 100),cameraBtn,cameraIcon)){
audio.Play();
CaptureImage();
clicked = true;
Application.LoadLevel("Preview");
}
// alert box
if(clicked){
GUI.Box(new Rect( 282, 425, 204, 80), alert, alertGS);
} // end alert box
}// end OnGUI()
void CaptureImage(){
clicked = true;
// wait for end of current frame
StartCoroutine(waitForEnd());
// create texture to hold image
tex = new Texture2D(width, height, TextureFormat.RGB24, false);
// capture the image
tex.ReadPixels(new Rect(0, 125, width, height), 0,0);
tex.Apply();
Application.LoadLevel("Preview");
} // end CaptureImage
IEnumerator waitForEnd(){
yield return new WaitForEndOfFrame();
} // end waitForEnd
Please tell me one thing that, have you change the Application. Application.targetFrameRate for the device?
@DeveshPandey: no I did not change the target frame rate.
then O$$anonymous$$, but how can this code works without saving the texture. You need to write/save the texture after tex.Apply(); and then LoadLevel("preview"). http://docs.unity3d.com/Documentation/ScriptReference/Texture2D.EncodeToPNG.html
For this app I call Texture2d.EncodeToPNG in another script in another scene. It's called right before I create the request (WWW) to upload the screenshot and user info. This app uploads the screenshot to a server and does not save it because it is part of a display/attraction in a retail store and has already taken over 10k pics in 2 months.
Can you use Application.CaptureScreenshot() for your purposes ins$$anonymous$$d?
Answer by Paulius-Liekis · Nov 06, 2012 at 09:45 AM
CaptureImage supposed to be coroutine.
You need to change `StartCoroutine(waitForEnd());` to `yield return StartCoroutine(waitForEnd());`, otherwise it doesn't wait for waitForEnd to finish and just continues on. Also you don't need waitForEnd at all, you can simply call WaitForEndOfFrame directly from CaptureImage.
Code:
IEnumerator CaptureImage(){
clicked = true;
// wait for end of current frame
yield return new WaitForEndOfFrame();
// create texture to hold image
tex = new Texture2D(width, height, TextureFormat.RGB24, false);
// capture the image
tex.ReadPixels(new Rect(0, 125, width, height), 0,0);
tex.Apply();
Application.LoadLevel("Preview");
} // end CaptureImage
Also be careful when pasting Javascrip coroutine example code into C# code, that's how you end up with StartCoroutine instead of yield return StartCoroutine. Javascript does some thing behind your back (I don't like it :))
Thanks for responding. I tried this but no luck with iOS6, works with iOS 5. It might work with a regular Unity app, but with this QCAR app it just gives me an empty texture, just blue screen where the image should be. BTW, that's not JavaScript, it's from the Unity docs. Apparently there is an iOS 6 bug with glReadPixels, looking for a way around it.
Answer by cfdevdan · Nov 07, 2012 at 09:37 PM
It seems that this is an iOS 6 bug. There have been a few bug reports generated about it and it is discussed on the Apple Developer Forums. The suggested fix is to use retained backing on the EAGLView. I ended up changing the boolean in the drawableProperties of the CAEAGLLayer in AppController.mm from FALSE to TRUE. See below. Apple cautions that this fix can affect performance but I don't see any problems and several others have fixed the bug with this without issue.
layer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
// change FALSE to TRUE
[NSNumber numberWithBool:TRUE], kEAGLDrawablePropertyRetainedBacking,
colorFormat, kEAGLDrawablePropertyColorFormat, nil ];