Figured it out. Noesis flips the texture Y in NoesisView.
Unfortunately, it doesn't respect my app's choice when I set noesisView.RenderFlags = Noesis.View.RenderFlagsFlipY;
So I had to add this hacky code

In NoesisView.cs before UpdateSettings():
View.RenderFlags? _renderFlagsOverride = null;
public void OverrideRenderFlags(View.RenderFlags? newRenderFlags)
{
_renderFlagsOverride = newRenderFlags;
LateUpdate();
}
private void UpdateSettings()
...
Also change the last line of UpdateSettings():
if (_renderFlagsOverride.HasValue)
{
_uiView.SetFlags(_renderFlagsOverride.Value);
}
else
{
_uiView.SetFlags(renderFlags);
}
then call Noesis to draw a frame (because it doesn't update immediately), then render to texture:
/// <summary>
/// Add ability to take screenshots with Noesis by pressing ` key
/// </summary>
public class ScreenGrabber : MonoBehaviour
{
Camera _camera;
NoesisView _noesisView;
public string OutputPng = @"D:\@Niko\Projects\Fantasia\Assets\TestScreenshots\test.png";
public int Width = 4096;
public int Height = 3072;
// Use this for initialization
void Start()
{
_camera = GetComponent<Camera>();
_noesisView = GetComponent<NoesisView>();
}
int _framesToScreenshot = -1;
bool _savedEnablePostProcess;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.BackQuote)) // if "`"
{
_framesToScreenshot = 1;
_savedEnablePostProcess = _noesisView.EnablePostProcess;
_noesisView.EnablePostProcess = true;
_noesisView.OverrideRenderFlags(Noesis.View.RenderFlags.FlipY);
}
if (_framesToScreenshot >= 0)
{
_framesToScreenshot--;
}
if (_framesToScreenshot == 0)
{
TakeScreenshot(_camera, _noesisView, Width, Height, OutputPng);
Application.OpenURL(OutputPng);
_noesisView.EnablePostProcess = _savedEnablePostProcess;
_noesisView.OverrideRenderFlags(null);
}
}
private static RenderTexture CreateRenderTexture(int width, int height, RenderTextureFormat format = RenderTextureFormat.ARGB32)
{
RenderTexture result = new RenderTexture(width, height, 0, format, RenderTextureReadWrite.Linear);
result.useMipMap = false;
result.antiAliasing = 1;
result.Create();
if (!result.IsCreated())
{
throw new Exception("NOOO!!");
}
return result;
}
private static void TakeScreenshot(Camera camera, NoesisView noesis, int width, int height, string outputFilePath)
{
// create a clone of noesis to render to a temp texture
//GameObject noesisObject = new GameObject("NoesisOnly");
//Camera noesisCamera = noesisObject.AddComponent<Camera>();
//noesisCamera.clearFlags = CameraClearFlags.SolidColor;
//noesisCamera.backgroundColor = new UnityEngine.Color(0.0f, 0.0f, 0.0f, 0.0f);
//noesisCamera.renderingPath = RenderingPath.Forward;
//noesisCamera.depthTextureMode = DepthTextureMode.None;
//noesisCamera.opaqueSortMode = UnityEngine.Rendering.OpaqueSortMode.NoDistanceSort;
//noesisCamera.transparencySortMode = TransparencySortMode.Orthographic;
//noesisCamera.clearStencilAfterLightingPass = false;
//noesisCamera.hdr = false;
//noesisCamera.useOcclusionCulling = false;
//noesisCamera.cullingMask = 0;
//noesisCamera.targetTexture = CreateRenderTexture(width, height);
//NoesisView noesisClone = noesisObject.AddComponent<NoesisView>();
////noesisClone.Xaml = noesis.Xaml;
//noesisClone.Xaml = (NoesisXaml)UnityEngine.Resources.Load("ScoreWindow1");
//Debug.Log(noesisClone.Xaml);
//noesisClone.LoadXaml(true); // CRASH!!!
//noesisClone.EnablePostProcess = true;
//noesisClone.AntiAliasingMode = Noesis.View.AntialiasingMode.MSAA;
//noesisClone.TessellationQuality = Noesis.View.TessellationQuality.High;
//noesisClone.RenderFlags = Noesis.View.RenderFlags.FlipY
//noesisCamera.Render(); // CRASH!!!
// render to texture
RenderTexture sceneNoNoesisTexture = CreateRenderTexture(width, height);
RenderTexture savedTexture = camera.targetTexture;
camera.targetTexture = sceneNoNoesisTexture;
camera.Render();
camera.targetTexture = savedTexture;
// copy to Texture2D
RenderTexture savedRenderTexture = RenderTexture.active;
RenderTexture.active = sceneNoNoesisTexture;
Texture2D screenshot = new Texture2D(width, height, TextureFormat.ARGB32, mipmap: false);
screenshot.ReadPixels(new Rect(0, 0, width, height), 0, 0);
screenshot.Apply();
RenderTexture.active = savedRenderTexture;
// write to file
byte[] bytes = screenshot.EncodeToPNG();
System.IO.File.WriteAllBytes(outputFilePath, bytes);
Debug.Log("Saved screenshot to " + outputFilePath);
}
}
Hope this helps someone else. Ideally the RenderFlags should be respected or even better no FlipY when rendering to texture.