Asked by:
Better Performance For BMP In Picturbox

Question
-
Hello everybody!
That's the first time i ask something about C# and i need it for a project at the university.
I have to visualize a bike jumping over a ramp, so i need a frame rate which looks fluently. My Problem is that i only reach about 10 fps. I was searching for about 4 or 5 hours for a solution, but i don't get one which i can use/understand. I'm nearly a beginner to this program, so i hope somebody of you can help me.
Program:
I have two pictureboxes, one for the background and one for the bike. i set the background as the parent of the bike and made the background of Bike transparent. Both pictureboxes have the same size and position. My Bike is a png and the visualization works fine. But if the bike is moving, i only get low fps and that's really annoying.
private void timer_Tick(object sender, EventArgs e) { picBike.Invalidate(); tTimer++; } public void picBackground_Paint(object sender, PaintEventArgs e) { Graphics z = e.Graphics; z.SmoothingMode = SmoothingMode.AntiAlias; float Breite = X; // X-Koordinate in mm float Höhe = maxY - minY; // Y-Koordinate in mm Matrix myMatrix = new Matrix(); // Matrix für Koordinatentransformation myMatrix.Scale(picBackground.ClientSize.Width / Breite, picBackground.ClientSize.Height / Höhe); // Koordinatensystemgröße transformieren myMatrix.Translate(0, maxY, MatrixOrder.Prepend); // Koordinatenursprung transformieren z.Transform = myMatrix; // Koordinatensystem transformieren Pen blackPen = new Pen(Color.Black, 3); // Stift Schwarz AbsprungwinkelGrad = (double)numAngle.Value; // Rampenabsprungwinkel in Grad AbsprungwinkelRadiant = AbsprungwinkelGrad * Math.PI / 180; // Rampenabsprungwinkel in Rad Rampenradius = (double)numRadius.Value / 1000; // Radius in m XRampengröße = 2 * Rampenradius - Rampenradius * (1 - Math.Sin(AbsprungwinkelRadiant)); // Rampenlänge in m // Rechtecksfläche für Rampe Rectangle rect = new Rectangle((int)(XRampenende * 1000) - (int)(XRampengröße * 1000), -(int)(Rampenradius * 1000 * 2), (int)(Rampenradius * 1000 * 2), (int)(Rampenradius * 1000 * 2)); // Ellipsenstart- und Endpunkt float startAngle = 90; float sweepAngle = -(float)AbsprungwinkelGrad; // Ellipsenzeichnung z.DrawArc(blackPen, rect, startAngle, sweepAngle); z.DrawLine(blackPen, 0, 0, X, 0); // Landerampe double xl = BsX[(int)tEnd]; double yl = BsY[(int)tEnd]; z.DrawLine(blackPen, (float)((xl * 1000 + Bikelänge / 2 * 1000 * Math.Cos(Bikewinkelfalsch[(int)tEnd] * Math.PI / 180)) - 2000), (float)((-yl * 1000) + 2000 * Math.Sin(Bikewinkelfalsch[(int)tEnd] * Math.PI / 180)), (float)(xl * 1000 + yl * 1000 / (-Math.Tan(Bikewinkelfalsch[(int)tEnd] * Math.PI / 180)) + Bikelänge / 2 * 1000 * Math.Cos(Bikewinkelfalsch[(int)tEnd] * Math.PI / 180)), (float)0); } private void picBike_Paint(object sender, PaintEventArgs e) { Graphics z = e.Graphics; z.SmoothingMode = SmoothingMode.AntiAlias; float Breite = X; // X-Koordinate in mm float Höhe = maxY - minY; // Y-Koordinate in mm Matrix myMatrix = new Matrix(); // Matrix für Koordinatentransformation myMatrix.Scale(picBike.ClientSize.Width / Breite, picBike.ClientSize.Height / Höhe); // Koordinatensystemgröße transformieren myMatrix.Translate(0, maxY, MatrixOrder.Prepend); // Koordinatenursprung transformieren z.Transform = myMatrix; // Koordinatensystem transformieren Pen blackPen = new Pen(Color.Black, 3); // Bikevisualisierung imgBike = Backflip.Properties.Resources.Projekt_Bike; Bitmap bmp = new Bitmap((int)(Bikelänge * 1000), (int)(Bikehöhe * 1000)); int newWidth = (int)Math.Sqrt(bmp.Height * bmp.Height + bmp.Width * bmp.Width); int newHeigth = (int)Math.Sqrt(bmp.Height * bmp.Height + bmp.Width * bmp.Width); Bikewinkelrichtig = Bikewinkelfalsch[(int)tTimer]; Bikewinkelrichtig %= 360; // Bikedrehung kann nicht mehr über 360 Grad Bitmap MyreturnBitmap = new Bitmap(newWidth, newHeigth); Graphics graphics = Graphics.FromImage(MyreturnBitmap); //graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;//Drawing2D.InterpolationMode.NearestNeighbor graphics.TranslateTransform(newWidth / 2, newHeigth / 2); graphics.RotateTransform(-(float)Bikewinkelrichtig); graphics.TranslateTransform(-(int)(Bikelänge * 1000) / 2, -(int)(Bikehöhe * 1000) / 2); graphics.DrawImage(imgBike, 0, 0, (int)(Bikelänge * 1000), (int)(Bikehöhe * 1000)); z.TranslateTransform(-(MyreturnBitmap.Width / 2), -(MyreturnBitmap.Height / 2)); z.DrawImage(MyreturnBitmap, (float)BsX[(int)tTimer] * 1000 + bmp.Width / 2, -(float)BsY[(int)tTimer] * 1000 - bmp.Height / 2, MyreturnBitmap.Width, MyreturnBitmap.Height); z.DrawRectangle(blackPen, (float)BsX[(int)tTimer] * 1000 + (MyreturnBitmap.Width / 2 - imgBike.Width / 2), -(float)Bikehöhe * 1000 - (float)BsY[(int)tTimer] * 1000 + (MyreturnBitmap.Height / 2 - imgBike.Height / 2), 100, 100); GC.Collect(); }
If you need the variables and comments in English, please tell me and i will change them.
Thank you in advance.
- Moved by CoolDadTx Tuesday, June 12, 2018 1:40 PM Winforms related
Tuesday, June 12, 2018 11:35 AM
All replies
-
If you want to do smooth animations, you must not use GDI+ (even with double-buffering, not very good)
You must use DirectX (Direct2D)
I did some tests with P/Invoke for the Direct2D interfaces and the animations are perfect in C#, like in C++
You can also use a wrapper DLL like d2dsharp (you can compile and test the samples)
- Edited by Castorix31 Tuesday, June 12, 2018 1:20 PM
- Proposed as answer by Stanly Fan Monday, June 18, 2018 6:54 AM
Tuesday, June 12, 2018 1:18 PM -
Thank you for your respond.
I forgot to write, that i don't have much knowledge about the theory. The Program i'm writing now is way more complex than the one we did in the lectures.
I would be happy, if you can explain me the GDI+ in a simple and short way, because i never heard of this and how i can change the code to use Direct2D.Tuesday, June 12, 2018 3:23 PM -
Hello,
In case you did not know, calling GC.Collect() is a performance hit. I have never need to manually
force GC activity as works well on its own. Others may have different opinions. The following link to
my OneDrive has an example of animation using Bitmap images, InvadersGame . This example is from
my 2D animation project wrapper. You may find the example useful.
Thanks :)
Tuesday, June 12, 2018 6:46 PM -
Thanks for your reply.
If i don't use the GC.Collect() i have a ram usage up to 2GB and the program crashes after about 10 seconds.
Nice game, but it's only the .exe and without the code i can't learn from it.Wednesday, June 13, 2018 8:24 AM -
I made a test by loading this sprite sheet on a background image : CSharp_Direct2D.exe
Only tested on Windows 10, with .NET 4.5.2, and the animation is smooth even without graphic card on my PC.
It it works, I could post the C# code, but it is a "draft code" atm...
Wednesday, June 13, 2018 11:32 AM -
I'm using Windows 10 and 4.6.1, so i think it would work fine for me too.
If you could post the code would be really cool, even it's a draft code. I think that would help me much.
Wednesday, June 13, 2018 2:46 PM -
I'm using Windows 10 and 4.6.1, so i think it would work fine for me too.
If you could post the code would be really cool, even it's a draft code. I think that would help me much.
I uploaded the VS 2015 test project (I have let most of useless/test code in comments) : CSharp_Direct2D.zip
The skeleton of the code is adapted from MS Direct2D samples in C++ (like function CreateDeviceResources())
The drawing is simple and done in OnPaint() : first the backround (m_pD2DBitmapBackground) is drawn, then the sprite (m_pD2DBitmap)
Both D2DBitmaps are created in Form1_Load() with a custom function, CreateD2DBitmapFromURL() (which must be improved, it was just to load bitmaps (.png) from URLs for quick testing)- Edited by Castorix31 Wednesday, June 13, 2018 4:01 PM
- Proposed as answer by Stanly Fan Thursday, June 14, 2018 1:26 AM
Wednesday, June 13, 2018 3:58 PM -
Castorix31,
That was a wonderful example, nice work! Could you share the methodology regarding
the graphics code, like DirectX or GDI, implementations? My example only used a 2 frame
cut sheet for invader animation. I did not use a background image, so that the code can
directly draw onto Form via CreateGraphics method. What object was used for the bird?
However, I would of had the bird face direction of movement. Just my thoughts :)
Thanks :)
Note:
Runs fine for me, Win7 x64, Net 4.6.1, Intel Q6600, 8GB RAM, nVidia GTX 710 2GB
Wednesday, June 13, 2018 4:21 PM -
Thanks for the code and maybe it will help some other people in the future with a similar problem. But it's to hard for me to understand the code. Most of it i've never seen and the code has with the class 10x more lines than my whole program.Thursday, June 14, 2018 7:02 PM
-
Most of the code is in fact just declarations, not needed in C++ because they are in the headers
I just followed SDK samples and MSDN which explains the basics for Direct2D : Getting Started with Direct2D
- Proposed as answer by Stanly Fan Friday, June 15, 2018 1:14 AM
Thursday, June 14, 2018 8:16 PM