High Resolution screenshot in Mogre

TeaBag

25-11-2011 16:29:46

Hi,

I was trying to convert the Shoggoth code from the wiki to Mogre 1.7.3: http://www.ogre3d.org/tikiwiki/High+res ... creenshots

But I'm having some problems with the final display of the image. Basically I get some blocks

Can someone please take a look at my code? Probably someone will spot the problem right away.

Thank in advance.


public class ScreenshotManager
{
#region Fields

private string fileExtension;
private uint gridSize;
private uint windowWidth;
private uint windowHeight;
private bool disableOverlays;

// Temporary texture with current screensize
private TexturePtr tempTex;
private RenderTexture renderTexture;
private HardwarePixelBufferSharedPtr buffer;
// PixelBox for a large Screenshot if grid size is > 1
private PixelBox finalPicturePixelBox;

#endregion


public ScreenshotManager(RenderWindow renderWindow, int gSize, string fileExtension, bool disableOverlays)
{
this.gridSize = (uint) gSize;
this.fileExtension = fileExtension;
this.disableOverlays = disableOverlays;

windowWidth = renderWindow.Width;
windowHeight = renderWindow.Height;

tempTex = TextureManager.Singleton.CreateManual( "ScreenshotTexture",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
TextureType.TEX_TYPE_2D,
windowWidth,
windowHeight,
0,
PixelFormat.PF_B8G8R8,
(int)TextureUsage.TU_RENDERTARGET );

renderTexture = tempTex.GetBuffer().GetRenderTarget();

buffer = tempTex.GetBuffer();

//Create pixelbox
uint[] data = new uint[(windowWidth * gridSize) * (windowHeight * gridSize) * 3];
GCHandle gch = GCHandle.Alloc( data, GCHandleType.Pinned );
IntPtr dataPtr = gch.AddrOfPinnedObject();

finalPicturePixelBox = new PixelBox( windowWidth * gridSize, windowHeight * gridSize, 1, PixelFormat.PF_B8G8R8, dataPtr );
}

public void TakeScreenshot(Camera camera, string filename)
{
// Remove all viewports, so the added Viewport is the only one
renderTexture.RemoveAllViewports();
renderTexture.AddViewport( camera );

// set the viewport settings
Viewport viewport = renderTexture.GetViewport( 0 );
viewport.SetClearEveryFrame( true );
viewport.OverlaysEnabled = false;

// remind current overlay flag
bool enableOverlayFlag = camera.Viewport.OverlaysEnabled;

// we disable overlay rendering if it is set in config file and the viewport setting is enabled
if( disableOverlays && enableOverlayFlag )
camera.Viewport.OverlaysEnabled = false;

if( gridSize <= 1 )
{
// simple case where the contents of the screen are taken directly
// Also used when an invalid value is passed within gridSize
renderTexture.Update(); // render

// write the file to the harddisk
renderTexture.WriteContentsToFile( filename + "." + fileExtension );
}
else
{
// define the original frustum extents variables
float originalFrustumLeft;
float originalFrustumRight;
float originalFrustumTop;
float originalFrustumBottom;
camera.GetFrustumExtents( out originalFrustumLeft, out originalFrustumRight, out originalFrustumTop,
out originalFrustumBottom );

// compute the Stepsize for the grid
float frustumGridStepHorizontal = ( originalFrustumRight * 2 ) / gridSize;
float frustumGridStepVertical = ( originalFrustumTop * 2 ) / gridSize;

// process each grid
for( uint nbScreenshots = 0 ; nbScreenshots < (gridSize * gridSize) ; nbScreenshots++ )
{
int y = (int) ( nbScreenshots / gridSize );
int x = (int) ( nbScreenshots - y * gridSize );

// Shoggoth frustum extents setting
// compute the new frustum extents
float frustumLeft = originalFrustumLeft + frustumGridStepHorizontal * x;
float frustumRight = frustumLeft + frustumGridStepHorizontal;
float frustumTop = originalFrustumTop - frustumGridStepVertical * y;
float frustumBottom = frustumTop - frustumGridStepVertical;

// set the frustum extents value to the camera
camera.SetFrustumExtents( frustumLeft, frustumRight, frustumTop, frustumBottom );

// ignore time duration between frames
Root.Singleton.ClearEventTimes();
renderTexture.Update(); // render

// define the current
Box subBox = new Box( (uint) ( x * windowWidth ),
(uint) ( y * windowHeight ),
(uint) ( x * windowWidth + windowWidth ),
(uint) ( y * windowHeight + windowHeight ) );

// copy the contents from the temp buffer into the final picture PixelBox
// Place the tempBuffer content at the right position
buffer.BlitToMemory( finalPicturePixelBox.GetSubVolume( subBox ) );
}

// set frustum extents to previous settings
camera.ResetFrustumExtents();

unsafe
{
Image finalImage = new Image(); // declare the final Image Object
finalImage = finalImage.LoadDynamicImage( (byte*) finalPicturePixelBox.data.ToPointer(),
finalPicturePixelBox.box.Width,
finalPicturePixelBox.box.Height,
PixelFormat.PF_B8G8R8 );

// save the final image to a file
finalImage.Save( filename + "." + fileExtension );
}

}


// do we need to re-enable our overlays?
if( enableOverlayFlag )
camera.Viewport.OverlaysEnabled = true;

// reset time since last frame to pause the scene
Root.Singleton.ClearEventTimes();
}

smiley80

26-11-2011 19:39:01

using System;
using System.Runtime.InteropServices;
using Mogre;

public class ScreenshotManager
{
#region Fields

private string fileExtension;
private uint gridSize;
private uint windowWidth;
private uint windowHeight;
private bool disableOverlays;

// Temporary texture with current screensize
private TexturePtr tempTex;

#endregion

public ScreenshotManager(RenderWindow renderWindow, int gSize, string fileExtension, bool disableOverlays)
{
this.gridSize = (uint)gSize;
this.fileExtension = fileExtension;
this.disableOverlays = disableOverlays;

windowWidth = renderWindow.Width;
windowHeight = renderWindow.Height;

tempTex = TextureManager.Singleton.CreateManual("ScreenshotTexture",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
TextureType.TEX_TYPE_2D,
windowWidth,
windowHeight,
0,
PixelFormat.PF_B8G8R8,
(int)TextureUsage.TU_RENDERTARGET);


}

public void TakeScreenshot(Camera camera, string filename)
{
using (HardwarePixelBufferSharedPtr buffer = tempTex.GetBuffer())
{
using (RenderTexture renderTexture = buffer.GetRenderTarget())
{
//Create pixelbox
byte[] data = new byte[PixelUtil.GetMemorySize(windowWidth * gridSize, windowHeight * gridSize, 1, tempTex.Format)];
GCHandle gch = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
IntPtr dataPtr = gch.AddrOfPinnedObject();
PixelBox finalPicturePixelBox = new PixelBox(windowWidth * gridSize, windowHeight * gridSize, 1, tempTex.Format, dataPtr);

// Remove all viewports, so the added Viewport is the only one
renderTexture.RemoveAllViewports();
renderTexture.AddViewport(camera);

// set the viewport settings
Viewport viewport = renderTexture.GetViewport(0);
viewport.SetClearEveryFrame(true);
viewport.OverlaysEnabled = false;

// remind current overlay flag
bool enableOverlayFlag = camera.Viewport.OverlaysEnabled;

// we disable overlay rendering if it is set in config file and the viewport setting is enabled
if (disableOverlays && enableOverlayFlag)
camera.Viewport.OverlaysEnabled = false;

if (gridSize <= 1)
{
// simple case where the contents of the screen are taken directly
// Also used when an invalid value is passed within gridSize
renderTexture.Update(); // render

// write the file to the harddisk
renderTexture.WriteContentsToFile(filename + "." + fileExtension);
}
else
{
// define the original frustum extents variables
float originalFrustumLeft;
float originalFrustumRight;
float originalFrustumTop;
float originalFrustumBottom;
camera.GetFrustumExtents(out originalFrustumLeft, out originalFrustumRight, out originalFrustumTop,
out originalFrustumBottom);

// compute the Stepsize for the grid
float frustumGridStepHorizontal = (originalFrustumRight * 2) / gridSize;
float frustumGridStepVertical = (originalFrustumTop * 2) / gridSize;

// process each grid
for (uint nbScreenshots = 0; nbScreenshots < (gridSize * gridSize); nbScreenshots++)
{
int y = (int)(nbScreenshots / gridSize);
int x = (int)(nbScreenshots - y * gridSize);

// Shoggoth frustum extents setting
// compute the new frustum extents
float frustumLeft = originalFrustumLeft + frustumGridStepHorizontal * x;
float frustumRight = frustumLeft + frustumGridStepHorizontal;
float frustumTop = originalFrustumTop - frustumGridStepVertical * y;
float frustumBottom = frustumTop - frustumGridStepVertical;

// set the frustum extents value to the camera
camera.SetFrustumExtents(frustumLeft, frustumRight, frustumTop, frustumBottom);

// ignore time duration between frames
Root.Singleton.ClearEventTimes();
renderTexture.Update(); // render

// define the current
Box subBox = new Box((uint)(x * windowWidth),
(uint)(y * windowHeight),
0,
(uint)(x * windowWidth + windowWidth),
(uint)(y * windowHeight + windowHeight),
0);

// copy the contents from the temp buffer into the final picture PixelBox
// Place the tempBuffer content at the right position
buffer.BlitToMemory(finalPicturePixelBox.GetSubVolume(subBox));
}

// set frustum extents to previous settings
camera.ResetFrustumExtents();

unsafe
{
Image finalImage = new Image(); // declare the final Image Object
finalImage = finalImage.LoadDynamicImage((byte*)finalPicturePixelBox.data.ToPointer(),
finalPicturePixelBox.box.Width,
finalPicturePixelBox.box.Height,
tempTex.Format);

// save the final image to a file
finalImage.Save(filename + "." + fileExtension);
finalImage.Dispose();
}
}

// do we need to re-enable our overlays?
if (enableOverlayFlag)
camera.Viewport.OverlaysEnabled = true;

// reset time since last frame to pause the scene
Root.Singleton.ClearEventTimes();
}
finally
{
gch.Free();
}
}
}
}
}


It seems it doesn't like that 'subBox' has a depth of 1. Also your 'data' array was too large (uint8 -> byte).
I've moved the memory allocation to the method. That way it has to do it every time, but at least it frees the memory when it's done.
You should also add a 'Dispose' method that destroys 'tempTex'.

Beauty

27-11-2011 11:34:32

It's nice that you ported the code.
If you have a well working code, please leave a note here. Then I will add the code to the wiki.

TeaBag

28-11-2011 09:06:28

Hi,

Thanks smiley80 for your corrections.

Before, I had a screenshot that had all the different sub cells but they were in a strange order. With your solution, if I choose a gridSize > 1, I have a completely black image instead.

The only thing I noticed that is weird is that when creating the tempTex, it is used a PixelFormat.PF_B8G8R8, but when it gets to the TakeScreenshot method, it has a PixelFormat.PF_X8B8G8R8... it shouldn't make a difference, I think.

Do you have an idea on what could be the cause of this black image?

smiley80

01-12-2011 15:09:17

Yeah, I also get a black image when I use DirectX, OpenGL works fine, though. Not sure why yet.