Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
RENDER TO BITMAP WORKAROUND
#1
Hello

I have an scenario where the Scene exists but the SceneView may not
The Scene contains everything needed like 3D geometry or lights but the camera

I then need to render a snapshot

I know I can easily do this in the SceneView control, but this control may not exists at the time I request the screenshoot

So, in the Scene I am creating a new SceneView, add this instance to it, add the camera and then render to bitmap, but I am getting null

As library is protected, I cannot step into the RenderToBitmap method to undersrand why is this happening

This is so far my method defined in a custom class that inherits from Ab4d.SharpEngine.Scene:

private bool TakeScreenShot(ref WriteableBitmap? writeableBitmap)
{
    var sceneView = new SharpEngineSceneView(this, "SceneView")
    {
      BackgroundColor = Avalonia.Media.Colors.Transparent
    };
    var targetPositionCamera = new TargetPositionCamera
    {
      Attitude = this.dataContext.LastCameraAttitude ?? -30f,
      Distance = this.dataContext.LastCameraDistance ?? 500f,
      FieldOfView = this.dataContext.LastCameraFieldOfView.HasValue ? (float)this.dataContext.LastCameraFieldOfView.Value : 45f,
      Heading = this.dataContext.LastCameraHeading ?? -40f,
      IsAutomaticFarPlaneDistanceCalculation = false,
      IsAutomaticNearPlaneDistanceCalculation = false,
      MaxFarPlaneDistance = float.NaN,
      MinNearPlaneDistance = 0f,
      ProjectionType = this.dataContext.IsPerspectiveProjection ? ProjectionTypes.Perspective : ProjectionTypes.Orthographic,
      ShowCameraLight = ShowCameraLightType.Never,
      TargetPosition = this.dataContext.LastCameraTargetPosition ?? new Vector3(0f, 0f, 0f),
      ViewWidth = 500
    };
    sceneView.
SceneView.Camera = targetPositionCamera;

    return sceneView.RenderToBitmap(ref writeableBitmap);
}


Any tip why I'm not getting what I need?
#2
Question 
I guess the issue is related to the fact that the newly created SceneView is not in the visual tree of controls, so...

Is there a way I can render a snapshot in this situation?
#3
If the SharpEngineSceneView is not shown, then its size is not defined. If you want to render it, you need to manually set its size by setting Width and Height properties before calling RenderToBitmap method.

Even better for your use case is to create the SceneView objects (generic SharpEngine objects) instead of SharpEnginSceneView object (Avalonia specific).

For example:

Code:
var sceneView = new SceneView(_scene, "SceneView");
sceneView.Initialize(gpuDevice, width: 512, height: 512, dpiScaleX: 1, dpiScaleY:1, multisampleCount: 4, supersamplingCount: 4);

var rawImageData = sceneView.RenderToRawImageData(renderNewFrame, format: _sceneView.Format);

// By default SharpEngine renders to BGRA, but when using Avalonia it rendered to RGBA because this is required for shared texture
var pixelFormat = rawImageData.Format == Ab4d.Vulkan.Format.B8G8R8A8Unorm ? PixelFormat.Bgra8888 : PixelFormat.Rgba8888;

if (writeableBitmap != null &&
    (writeableBitmap.PixelSize.Width != rawImageData.Width || writeableBitmap.PixelSize.Height != rawImageData.Height))
{
    writeableBitmap.Dispose();
    writeableBitmap = null;
}

writeableBitmap ??= new WriteableBitmap(new PixelSize(rawImageData.Width, rawImageData.Height), new Avalonia.Vector(96, 96), pixelFormat, AlphaFormat.Premul);


// Copy data from rawImageData to WriteableBitmap
using (var lockedFramebuffer = writeableBitmap.Lock())
{
    var imageDataArray = rawImageData.Data;

    if (rawImageData.Stride == lockedFramebuffer.RowBytes)
    {
        // If the size of one row is the same, then we can simply copy all the data at once
        Marshal.Copy(imageDataArray, 0, lockedFramebuffer.Address, imageDataArray.Length);
    }
    else
    {
        // If size of row is different, then we need to copy row by row

        int sourceIndex = 0;
        IntPtr destinationPtr = lockedFramebuffer.Address;
        int rowSize = Math.Min(lockedFramebuffer.RowBytes, rawImageData.Stride);

        for (int y = 0; y < rawImageData.Height; y++)
        {
            Marshal.Copy(imageDataArray, sourceIndex, destinationPtr, rowSize);

            sourceIndex += rawImageData.Stride;
            destinationPtr += lockedFramebuffer.RowBytes;
        }
    }
}
Andrej Benedik
#4
Thanks a lot

That did the trick
  


Forum Jump:


Users browsing this thread:
1 Guest(s)