I'm using CefSharp in WPF application in offscreen-mode.
Inside browser WebGL 3D model. At some points of model must be "billboard" but it must be WPF object in 2D space of WPF.
At each frame render I calculate projection of 3D point to 2D screen coords and send callback to WPF with 2D coords.
Visually 2D object of WPF moved on 1-2 frame faster than 3D model. It's strange because I'm catching onRender event of CEF and set billboards coords after browser render.
How I can synchronize render of 3D model and 2D billboards in WPF?
The culprit may be the fact that a WPF application does not have a predictable refresh rate. It redraws the UI based on under-the-hood heuristics influenced by your hardware and the current state of the OS. WPF cannot be forced to redraw at will unless you work around it with DirectDraw. Read in more detail here: https://rhnatiuk.wordpress.com/2008/12/21/wpf-video-playback-problems/
If you have continuous motion rendering within a WPF application, such as video, animation effects, or a browser with a WebGL-rendered moving object, you cannot reliably frame-sync it for screenshot purposes. I tried to run video in a WPF CefSharp app and the performance (perceived and measured) was abysmal on every (even high-end) computer I could find.
You can try to port your application into WinForms to benefit from constant frame rates. In WinForms, you would have to grab screenshots of the form or of the browser control which is messy but should be doable.
Related
Hello: I am trying to create an app which will display a moving sphere. App will vary speed and direction. I've tried Adobe Flash but cannot get it smooth. Smoothness is essential in this case. So I am trying C#.
Initially, I can see that this can be implemented by:
1) Creating a PictureBox of a sphere, and using a Timer, change its coordinates. or
2) Using the this.paint function to draw a filled circle, and somehow, with a timer, erasing and redrawing it.
Can someone recommend the best path to take? I'll have a main menu where the user will chose speed/direction/how many etc... and then simply show the "game window" with the moving spheres. Any guidance would be much appreciated.
This is to be displayed on a PC only.
Thanks
-Ed
I just answered a similar question here.
NOTE: Depending on your needs, it is possible to achieve smooth animations under winforms (under certain conditions) though you are responsible for everything. wpf provides an animation framework but wpf is perhaps a milestone harder.
It probably does not matter should you pursue winforms first or WPF. You arguably could learn the basics under winforms then move over to wpf. wpf may require you to learn quite a bit before you can do anything.
Summary
Essentially what this does is to create an offscreen bitmap that we will draw into first. It is the same size as the UserControl. The control's OnPaint calls DrawOffscreen passing in the Graphics that is attached to the offscreen bitmap. Here we loop around just rendering the tiles/sky that are visible and ignoring others so as to improve performance.
Once it's all done we zap the entire offscreen bitmap to the display in one operation. This serves to eliminate:
Flicker
Tearing effects (typically associated with lateral movement)
There is a Timer that is scheduled to update the positions of all the tiles based on the time since the last update. This allows for a more realistic movement and avoids speed-ups and slow-downs under load. Tiles are moved in the OnUpdate method.
If you note in the code for Timer1OnTick I call Invalidate(Bounds); after animating everything. This does not cause an immediate paint rather Windows will queue a paint operation to be done at a later time. Consecutive pending operations will be fused into one. This means that we can be animating positions more frequently than painting during heavy load. Animation mechanic is independent of paint. That's a good thing, you don't want to be waiting for paints to occur. xna does a similar thing
Please refer to my full SO answer complete with sample code
Here are a few hints to get you going:
First you will need to come to a decision about which platform to target: WPF or Winforms.
Then you should know what to move across what; a nice Bitmap or just a circle across an empty background or a Bitmap or a Form with controls on it.
In Winforms both your approaches will work, esp. if you set a circular region see here for an example of that. (The part in the fun comment!)
And yes, a Timer is the way to animate the sphere. Btw, a Panel or even a Label can display an Bitmap just as well as a PictureBox.
For smooth movements make sure to set the Form.Doublebuffered=true, if you move across a Form. If you move across any other control (except a PictureBox or a Label) you will need to subclass it to get access to the DoubleBuffered property!
It is often also a good idea to keep the Location of a moving item in a variable as a PointF and use floats for its speed because this way you can fine grain the speed and Location changes and also the Timer Intervals!
In my WinRT app I need to draw about 3000 objects on a canvas, where I can translate and zoom the view. Unfortunatley, after adding about 1500 lines to my canvas my Windows 8 App always crashes. What could be the best practice to achieve this?
One solution could be rendering everything on an image (how do I do this?). But then I loose comfort of easy access and editing of every element.
Also my scale and translate is very slow. But since I also need a big overview, it makes no sense to put only the objects of the visible area in the canvas, since on minimum zoom it's still everything and zoomed it's still very laggy cause of add and remove operations.
There are a couple of different things you should employ to have a smooth UX:
Use a Quadtree, whenever you add a shape to your canvas you also put it on your Quadtree. This will be helpful when you will zoom on a portion of the image: you will know what objects are in this portion of the image; you will render them again (against using a cached/pixellated version).
To overcome the potentially lengthy drawing process you could do the following:
display the portion of the cached image overview at the right scale
use a progress indicator to let know the user that the program is working render this portion
when the faint rendering is done, blit it on the screen
A concrete example: Google Maps does that.
I am encountering a problem where a WPF application runs with a very low frame rate when a D3D application is running at the same time.
The situation is as follows: The first application is a Winforms form that renders 3D graphics using SlimDX and D3D10. The application doesn't run in fullscreen mode, but in a maximized window. This is very smooth and fast.
The second application consists of a WPF window that renders a ScatterView with some images. The WPF window is transparent (AllowsTransparency="True" with a transparent background). The general idea here is that the WPF window should look like it is composited on top of the 3D scene.
However, as soon as the D3D10 application is running, the performance of the WPF app deteriorates to as low as 1-2 fps (as measured by the WPF Performance Tool). That's not because my computer hardware is not capable of rendering both applications: the D3D10 app is always rendering the 3D scene very smoothly, and GPU and CPU utilization does not max out when I have both applications running. Even when I give the WPF app a higher process priority, the rendering performance stays at 1-2 fps.
I have also tried to combine both applications into a single process and using a D3DImage and using a shared D3D10 surface (with a D3D9Ex device) to feed it into the D3DImage. Furthermore I tried using an InteropBitmap and writing the frame data into it. All of those solutions work and produce a D3D10 scene with some WPF controls on top of it, but none of them make WPF run smoothly.
The idea of using two different application processes was my final idea to decouple the WPF rendering stack from any eventual performance impacts that may arise from having D3D10 render in the same process.
I have an application which runs fullscreen on a high resolution display (1920x1080).
About 25% of the screen is a StackPanel that scrolls images across the screen.
(the X position is animated with double animation)
The scroll is very laggy and jumpy, and with visible tearing.
This is running on a brand new high-end gaming laptop, running Win7 64bit.
I don't understand why the performance is so poor. Am I doing something wrong? Does this kind of animation run on the CPU or GPU? Is there a smarter way to scroll images across the screen?
WPF can be hardware-accelerated, but only on newer video card drivers. Some of the onboard, out of box drivers, will default back to software rendering, which can feel really slow and clunky. As for the tearing, that's a normal video card setting, called V-Sync. I would try updating the video card drivers to a proprietary driver (nVidia, AMD, etc.), and enabling vertical sync on the card.
You can check to see if it falls into software, or hardware rendering using the methods explained here.
If that doesn't resolve the issue, the only other possibility I can think of is your animation/rendering is not synced to the GUI.
See this msdn article for more details.
A trick that I've seen that can get around this issue is to place a 3D object on your page, view it side on and rotate it e.g. for 4 images have a cube with an image set to each side.
Yes the rotation still requires GPU and processor time but it is taken care of internally by the WPF animation and so doesn't require interaction with code behind once set rolling.
When you create a form in .Net it appears as a dialog box in a portrait layout.
No one normally likes to read sideways, or upside down, but I have a very valid reason to rotate the form.
Anyone knows how to do it on Windows Vista with C#?
Does it have to be in WinForms? This is very easy to do in WPF, using rotation transforms. Unfortunately, the WindowsFormsHost integration with WPF does not allow rotation transforms.
EDIT
I understand, now, that the form in question is out of the control of the poster. Writing the control in WPF won't fix the problem.
This would be a bit of extra work, but if you mainly just need the contents of the form to be rotated (and not the entire window including title bar, window controls etc., which I've never seen before), you could instead make an entirely owner-drawn usercontrol that was rotated 90 degrees, and drop it on an ordinary form. You wouldn't even have to adjust your drawing of everything, since you could do a RotateTransform on your Graphics object and then draw everything normally.
Or if you need the entire form rotated, you could make the form borderless and then do basically the same thing, drawing the title bar and windows controls yourself also.
Update: here's a link to an MSDN article that shows how to rotate the entire screen in C#:
http://msdn.microsoft.com/en-us/library/ms812499.aspx
This is for regular Windows (not Windows Mobile), so it should work for your porpoises, although it will rotate all of Windows and not just your application's form. Depending on how fast this works and your overall needs, you could rotate the screen 90 degrees when your application gets the focus, and then rotate it back to normal when your app loses focus.
Update 2: I just reread your question and comments. You're talking about rotating the window of a separate application in a separate process, so WPF will definitely not help you here. The MSDN link might be what you need. In your application, you would rotate the screen 90 degrees, then start the other application in a separate process. This would work best if you could force the separate application's window to be maximized, which you can do by P/Invoking the FindWindow and SendMessage APIs (you could also make the window always on top, which would put your computer into a sort of kiosk mode for this application). There's a version of the Process code that basically makes starting another application a blocking call, which means your app will wait for the shelled application to close before resuming. Once the app closes, you can put the screen back to its normal orientation.