Jump to content

About to pull out my hair


Recommended Posts

I'm having a very strange problem with Texture2D.  I'm trying to save the image of a window to a file.  First, here is the code:

Spoiler

        void OnGUI()
        {
            graphWindow.OnGUI();
            if (graphWindow.saveScreen)
            {
                graphWindow.saveScreen = false;
                StartCoroutine(ScreenshotEncode());
            }
        }

        IEnumerator ScreenshotEncode()
        {
            // wait for graphics to render
            yield return new WaitForEndOfFrame();

            // create a texture to pass to encoding
            // First texture will capture the entire screen
            // Second texture is the destination for the final image
            // GraphWindow.wnd_rect is the Rect of the window which is being captured (obtained from GUILayout.Window)
            Texture2D texture = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
            Texture2D destTexture = new Texture2D((int)GraphWindow.wnd_rect.width, (int)GraphWindow.wnd_rect.height, TextureFormat.RGB24, false);

            // put buffer into texture
#if false
            // This would read the pixels of the desired Rect and put directly into destTexture
            destTexture.ReadPixels(GraphWindow.wnd_rect, 0, 0);
#else
            // Read the entire screen
            texture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);

            // Now copy the texture of the wnd_rect to the destTexture
            int x = (int)GraphWindow.wnd_rect.x;
            int y = (int)GraphWindow.wnd_rect.y;
            Graphics.CopyTexture(texture, 0, 0, x,y, (int)GraphWindow.wnd_rect.width, (int)GraphWindow.wnd_rect.height,
                destTexture, 0, 0, 0, 0);
#endif

            byte[] bytes = destTexture.EncodeToPNG();
            string filePath = KSPUtil.ApplicationRootPath + "Screenshots/";
            Log.Info("filePath: " + filePath);
            FileInfo file = new System.IO.FileInfo(filePath);

            const string fname = "ResonantOrbit";
            int i = 0;
            while (File.Exists(filePath + fname + i.ToString() + ".png"))
                i++;
            File.WriteAllBytes(filePath + fname + i.ToString() + ".png", bytes);

            bytes = texture.EncodeToPNG();
            File.WriteAllBytes(filePath + fname+ "Screenshot" + i.ToString() + ".png", bytes);

            DestroyObject(texture);
            Destroy(destTexture);
            Log.Info("Exiting coroutine");
        }

 

This is a case of a picture is worth a thousand words.  I've tried many different variations, all with the same results.  The really wierd thing is that if I set y to a constant (ie: 200), then it will always copy from the vertical height of 200.

First test:

oj4QpS0.png

and this is the screenshot saved at the same time:

pVXjFJW.png

 

Second test, I moved the window a bit:

a03PWKE.png

and the screenshot:

uARRDZZ.png

 

Link to comment
Share on other sites

You've nearly got it. Your issue is that your window rect is in screen space (0,0 = top left) while ReadPixels (and CopyTexture) expects pixel space (0,0 = bottom left)

Convert to pixel space by inverting the y coordinate (Screen.height - y) and subtracting out the window height to get the bottom-left corner of the window

[KSPAddon(KSPAddon.Startup.MainMenu, false)]
class CaptureWindowScreenshot : MonoBehaviour
{
    private Rect _windowRect = new Rect(Screen.width * 0.5f, Screen.height * 0.5f - 200, 200f, 50f);
    private readonly GUILayoutOption[] _defaultOptions = new GUILayoutOption[0];
    private GUI.WindowFunction _windowFunc;
    private bool _capture = false;

    private void Awake()
    {
        _windowFunc = DrawWindow;
    }

    private void OnGUI()
    {
        _windowRect = KSPUtil.ClampRectToScreen(GUILayout.Window(GetInstanceID(), _windowRect, _windowFunc, "Test Window", _defaultOptions));

        if (_capture && Event.current.type == EventType.Repaint)
        {
            _capture = false;
            StartCoroutine(Capture());
        }
    }

    private IEnumerator Capture()
    {
        yield return new WaitForEndOfFrame();

        var pixelRect = _windowRect; // copy values

        pixelRect.y = Mathf.Max(Screen.height - _windowRect.y - _windowRect.height, 0f);

        var captureTex = new Texture2D(Mathf.CeilToInt(pixelRect.width), Mathf.CeilToInt(pixelRect.height));

        captureTex.ReadPixels(pixelRect, 0, 0, false);

        captureTex.SaveToDisk("window.png"); // your preferred method here

        Destroy(captureTex);
    }

    private void DrawWindow(int winid)
    {
        for (int i = 0; i < 5; ++i)
            GUILayout.Label("Text goes here", _defaultOptions);

        GUILayout.Space(5f);

        if (GUILayout.Button("Capture this window", _defaultOptions))
            _capture = true;

        GUI.DragWindow();
    }
}

 

Edited by xEvilReeperx
added example code
Link to comment
Share on other sites

Feel free to take a look at the KittopiaTech code, I have a basic planet thumbnail generator there. I cannot guarantee proper lighting, it seems to work fine just after the main menu scene was loaded, so KittopiaTech generates them there and caches them.

https://github.com/Kopernicus/KittopiaTech/blob/master/src/UI/PlanetSelector.cs#L131-L168

https://github.com/Kopernicus/KittopiaTech/blob/master/src/RuntimePreviewGenerator.cs

Solid bodies and gas planets work fine, Stars are very... white

yXNFaDE.png

Link to comment
Share on other sites

I'll try it, but a problem is that it's looking for "ScaledSpaceOnDemand", which I'm guessing is from Kopernicus???

Seems to work, except all the planets are extremely dark, as if there was no lighting.

I copied your code exactly, and am saving it to a file in my tests.

The only change was disabling that code for the ScaledSpaceOnDemand.

Any ideas?

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...