Save a jpg image of my scene
#1
Is it possible to save a jpg image of the a scene?
#2
To render the 3D scene to a bitmap you can use the Camera.RenderToBitmap method to get a bitmap. You can specify many parameters (size of bitmap, DPI settings and anti-aliasing).

See the Utilities/RenderToBitmap sample in the Ab3d.PowerToys samples project:

   

The sample shows how to save to png file. To save to jpg file just replace the PngBitmapEncoder with the JpegBitmapEncoder (note that there you can also specify the QualityLevel) in the SaveBitmap method.


When using DXEngine to render the scene, then use DXViewportView.RenderToBitmap method instead of the method on Camera (see DXEngineOther/RenderToBitmap.xaml sample)
Andrej Benedik
#3
Thanks!  I tried what you suggested and it worked great.

I'm using a button to save the image and it works well.  However, I have to add another related feature and I'm having some problems.

The scene has a building with several floors.  I need to save a separate image showing the building with just one floor, then 2 floors, then 3 floors, etc.  I need to do this automatically without having the user press a button for each floor.  I tried two different approaches and both failed.

First, I tried to just draw the image with one floor and immediately save the image.  I get the following error: "Cannot render to bitmap because TargetViewport3D is null"

Then, I figured I needed to wait for the image to be rendered, so I added a timer to wait a few seconds after I draw the image before I try to save it.  It does save without an error, but I get a blank jpg for all floors I'm trying to save.

Can you give me some advice on how to do what I need to do?
#4
The "Cannot render to bitmap because TargetViewport3D is null" is thrown because the TargetViewport3D on the camera is not set. 

If you do not manually set the TargetViewport3D, then the code in the camera class tries to find the Viewport3D in the Loaded event. It is recommended to manually set the TargetViewport3D - this can be done in code or in XAML with using binding (for example: TargetViewport3D="{Binding ElementName=MainViewport}").

For a complete sample please check the RenderOfflineViewportButton_OnClick method in the RenderToBitmapSample sample in Ab3d.PowerToys samples project.


To make a simple demonstration on how to create a sequence of bitmaps with changes the camera and object, you can add the following code to the end of the RenderOfflineViewportButton_OnClick method:


Code:
           for (int i = 1; i < 5; i++)
           {
               targetPositionCamera.Heading = i * 20;
               boxVisual3D.Transform = new ScaleTransform3D(1, (double)i / 4, 1);

               var bitmap = RenderToBitmap(targetPositionCamera);

               using (var fileStream = new FileStream($"c:\\temp\\bitmap_{i}.png", FileMode.Create))
               {
                   BitmapEncoder encoder = new PngBitmapEncoder();
                   encoder.Frames.Add(BitmapFrame.Create(bitmap));
                   encoder.Save(fileStream);
               }
           }

You will also need to update the RenderToBitmap to return BitmapSource object (and you can also comment calling the SaveBitmap method).

Note that this method renders does not render a teapot that is shown in the sample application but a custom 3D scene where the Viewport3D and its objects are created in code.
Andrej Benedik
#5
Thanks again!  I've set the TargetViewport3D and I'm now able to save the images in a loop.  Unfortunately, the images are distorted as shown below:

[Image: https://i.imgur.com/WcyF8tZ.jpg]

I don't have this problem when saving a single image using a button after displaying it my app. Do you have any idea what might be causing this type of distortion?  There's no difference on how I'm rendering the images from one scenario to the other except that one is in a loop that renders multiple images and the other just renders one image.
#6
Hm, it is hard to say what causes that distortion.

It looks like a MatrixCamera would be used and that an invalid matrix would be set. But I can hardly imagine how this could happen when using standard cameras. Anyway, you can try calling Refresh on the camera.

The sample code that I have posted works fine. Maybe you can check what are the differences between my and your code. If you change many things between rendering, try commenting some changes and see if it will work correctly with minimal changes between rendering. Then uncomment some things back and see what is causing the problem. I am also curious what is causing this.
Andrej Benedik
#7
Thanks, I just upgraded to the latest version of the PowerToys and the problem was fixed.
  


Forum Jump:


Users browsing this thread:
1 Guest(s)