WPF 2D Physics!

UPDATES:

– ClickOnce demo available here! (.NET 3.5 SP1 required).
– VS2008 source on CodePlex.

Pavan Podila recently posted about a really cool video on YouTube.  It shows a guy using a SMART Board (or similar) to draw a 2D scene and visualize it in a simulated physics environment.

I’m as much of a geek as Pavan about this kind of stuff, so I thought I’d try to integrate a Physics engine with WPF.  After way too much googling and prototyping, I finally settled on using the Newton Game Dynamics engine.  It’s written in C++, but the demos and flexibility of the thing just blew me away.  I found a pretty good .NET wrapper for it by a guy called flylio (I’ve found & fixed a couple of bugs in it that I’ll need to tell him about).

So far I’ve got some randomly generated static platforms, with random shapes dropped from the top of the screen.  It’s really cool and disturbingly addictive to watch them bounce and roll about.

Some notes:

  • Newton is a 3D physics engine but I needed to get it to work well in 2D (I tried 2D engines but none of them came close to Newton for accuracy, speed or stability).  After some disappointing tests (involving an ‘invisible wall’ behind and in front of the scene) I settled instead on attaching a handler to Newton’s ‘body matrix changed’ event.  In it I just cleared the Z values and crossed my fingers.  It worked!
  • Newton can work with primitive objects like cylinders, cones, boxes etc. as well as arbitrary convex hulls (nicely represented as "vertex clouds").  This is great combined with WPF, because it means ‘real’ shapes can be used to represent round primitives (better to have a single-sided ellipse than a 30+ sided polygon).
  • WPF data binding rocks.  The whole scene is just an <ItemsControl> with a <Canvas> inside it (using <ItemsPanelTemplate>) bound to an ObservableCollection.  The actual bodies are defined as <DataTemplate> elements.
  • The shapes all look awesome thanks to WPF’s anti-aliasing!

 

Next I’ll try to add a block car with lumpy wheels, just like the video!

Obviously this is only half what I want to achieve.  Getting a designer for this stuff working in WPF should be an interesting ride!

UPDATE: Removed dependency on XNA Framework.  Now has a car!  Click the image above for demo.

40 Comments

  1. […] That was a fantastic lecture by the way, and it’s awesome to see the code up. It’s all here There’s also, on the WPF front, is a very cool little WPF/C# 2d physics engine here at Chris Cavanaghs blog that replicates the SMART board sample up on youtube that has a guy drawing a picture of a car and sending it off on his way, google for it since I can’t be bothered to find the link right now. It does however turn pictures in gravitationally accurate (somewhat at least) objects in physical space. Go WPF. […]

    Reply

  2. […] WPF and Physics Chris Cavanagh has posted some great code on using a physics engine with WPF. It’s an interesting and elegant example demonstrating a few things: A series of objects making use the wrapped physics engine Chris has chosen. The use of data templates and binding to represent the objects on screen and the use of matrix transforms for rendering based on updates from the the physics code. The interception of the CompositionTarget.Rendering event to perform the physics updates (which results in UI updates owing to the binding) Take a look at a screen shot: Extremely smart, and the first example I’ve seen of such stuff. So who’s building the ‘Asteroids’ clone?   Technorati Tags: WPF – Physics Filed under: WPF […]

    Reply

  3. […] Diciembre 19, 2007. Productos mejor vendidos vs productos de nicho. Meshups. Multipoint. En The Long Tail, Chris Anderson trata de demostrar que en la era de Internet hay 2 productos por su nivel ventas: los best-sellers y los de nicho; los primeros crean una curva estadĆ­stica muy importante pero los segundos mayor a lo largo del tiempo – “la cola larga”. Recomienda como crear flexibilidad en precios, servicios y entrega utilizando mercadotecnia innovadora. Lee Gomes del WSJ quiere desbancar esa teoria, cita datos muy interesante de como los productos mejor vendidos continuan representando el 80% o mĆ”s de las ventas o del acceso: El 10% de top videos de TouTube representa el 79% de las reproducciones totales. 50 titulos de los 60,000 de netflix o 1% del inventario generan el 30% de las rentas. Hay que seguir la conversaciĆ³n. Hablando de desarrollo de software, IBM tiene un artĆ­culo muy divertido sobre programaciĆ³n de Meshups y Borland anuncia de nuevos su lĆ­nea Turbo recordando su conferencia de 1996. Aunque hay eventos que a uno lo hacen dudar mucho del rumbo real de todo esto: Google mata su interfaz programĆ”tica de bĆŗsqueda. En lo referente a InnovaciĆ³n, todavia se puede hacer mucho en un programa de 640kb, ver esta demo de WPF 2D Physics. (TambiĆ©n visite esta demo de WPF/E). El 23 de noviembre pasado comentĆ© del Multipoint, vea ahora el video en Channel 9. Lea finalmente esta trĆ”gica historia. […]

    Reply

  4. You should search for Shawn Van Ness’s Physics Illustrator, he’s a pm over on Tablet and he wrote something for Tablet a few years back that is amazing…

    Reply

  5. TheExpressionist – Yeah I saw that :o) Pretty cool if I had a tablet PC! (could download source, compile and run on XP sans pen though). Should ask him to do a PocketPC version :o)

    What’d be really sweet is a simplified Javascript physics engine tied to WPF/E…

    Reply

  6. Excellent stuff!

    I’ve just written a 2D rigid body simulator with OpenGL visualization in OCaml. I’m going to port it to .NET and F# for my book “F# for Scientists”. I’ll put the source up ASAP.

    Reply

  7. Hey Jon that sounds cool! Let me know when you’ve got it working in .NET (or if you need some help with it); I’d love to try it out :o)

    Did you see my other post on ‘XBAP 2D Physics’? Basically using a simple 2D engine (called Flade); might be useful to you. I’ll get the source posted soon. Flade is written in Actionscript, so it’s quite tempting to port it to Javascript and drive a WPF/E demo with it… ;o)

    Reply

  8. i was wondering if you or anyone else who reads this and knows more of what’s going on could explain the ‘body matrix changed’ event? specifically, i’m looking to do 2d physics as well, with the additional excercise of having some objects with a specifically set rotational component, and leaving the position to the physics engine. would you mind sharing your insight with this event callback method?

    thanks,
    chris.

    Reply

  9. well, i’m still a bit unsure about whether or not i can even do what i’m looking towards doing using newton.

    i need to be able to use the collision event, keep the positional offsets from newton, and disregard any rotational changes it does.

    i’m also using a c# wrapper, which also makes it that much more tricky to see where exactly i put the callback.. from a ‘Body’ object, i can set up events to be triggered at Transformed, AutoActivated, or ForceCallback. only Transformed has any positional or quaternion rotation associated with it, and from resetting these, i see no effect.. from the documentation, this is an event to be used for updating other objects after collision.. i need to be able to pretty much intercept the collision right as it’s being written.

    is the callback you mention even inside the Body, or is it somewhere else entirely?

    Reply

  10. Chris – Not sure this is what you’re after, but here’s all I did:

    ///
    /// Handle Matrix changed callback
    ///
    /// Body
    /// Event arguments
    void Body_SetTransform( object sender, CSetTransformEventArgs e )
    {
    Matrix3D m = Matrix;
    Matrix = new Matrix3D( (float)m.M11, (float)m.M12, 0, 0, (float)m.M21, (float)m.M22, 0, 0, 0, 0, 1, 0, (float)m.OffsetX, (float)m.OffsetY, 0, 0 );
    OnPropertyChanged( “DisplayMatrix” );
    }

    I just replaced the matrix with a new one and it did the trick. The OnPropertyChanged call just marks the DisplayMatrix DependencyPropertyas changed (you’ll need to do something similar if you’re using WPF databinding).

    Reply

  11. awesome, that’s all i needed.. i was trying to figure out how to do it from the library as-is with some arcane callback, instead of going into the wrapper source directly and making the modifications.

    that’s the thing with black boxes i’ve found.. i usually don’t even consider something inside the box being malleable. definitely something i have to change my perspective of.

    thanks chris.

    Reply

  12. Chris – Don’t be afraid to rip apart my code šŸ™‚ It could definitely use some refactoring; there’s some functionality in the demo that really should be in its own assembly. The only bit that shouldn’t need any change is the NewtonWrapper (apart from bugs or just bits of Newton functionality it’s not exposing). Let me know how it works out šŸ™‚

    Reply

  13. Hi Chris – This is a very cool project (the one where you drop the cars). I saw Mark Miller playing with it at the MVP Summit in Seattle and thought it rocked. I see in the comments that others have asked for the source code for this, but don’t see a link for it. Could you e-mail me a link of where to get the code for this? Thanks…

    Reply

  14. […] A very funny WPF 2D application by Chris Cavanagh that itegrates the Newtown Dynamics Physics Engine. The app is very simple but really addictive. It presents a physical environment to you with a couple of obstacles. The only thing you can do is drop stuff into the screen and watch gravity fool around. Nice! WPF 2D Physics […]

    Reply

  15. The examples again. *sigh*
    I’m a knob.

    <ModelVisual3D newton:World.Body=”ConvexBody3D”>
    <ModelVisual3D.Content>
    or

    <ModelVisual3D>
    <newton:World.Body>
    <newton:ConvexBody3D x:Name=”_yellowCube” Mass=”0.1″ ApplyForce=”_yellowCube_ApplyForce”/>
    </newton:World.Body>

    Reply

  16. Leslie – Your WPF extensions look extremely cool šŸ™‚ The lunar lander demo confirms I’d make a lousy astronaut (something I’ve long suspected). Any plans to make a Silverlight version? šŸ™‚ (BulletX is an ok engine to use, but it has a couple annoying bugs… Howabout a soft-body lander using Wallaber’s JelloPhysics library?).

    Reply

  17. What I’d like to do is use a Soft and Rigid body combination.
    My plan was to make the physics library generic enough to have separate implementations of different physics engines. One day I’m sure. I chose Newton because it is a mature, solid, many featured engine. (Which helped naught for my lander skills as well. *sigh* it too far to long for me to stop breaking the legs off. And I wrote the stoopid thing. In fact I had to make it easier…..hehehe)

    Anyhoo, I’m sure someone can implement the soft body model extension now that I’ve shown how it’s done. šŸ˜‰

    Reply

  18. Hi!
    Downloaded and tried to run but i’m getting:

    Failed object initialization (ISupportInitialize.EndInit). Exception has been thrown by the target of an invocation. Error at object ‘bodies’ in markup file ‘WPFPhysics1;component/window1.xaml’ Line 16 Position 5.

    I converted both projects to VS2008.

    Reply

    1. I am getting the same error, I created a new .sln in Visual Studio 2010 and added both the NewtonDynamics project and the WPFPhysics1 project.

      The full exception is here:

      System.Windows.Markup.XamlParseException occurred
      Message=Failed object initialization (ISupportInitialize.EndInit). Exception has been thrown by the target of an invocation. Error at object ‘bodies’ in markup file ‘WPFPhysics1;component/window1.xaml’ Line 16 Position 5.
      Source=PresentationFramework
      LineNumber=16
      LinePosition=5
      NameContext=Resources
      StackTrace:
      at System.Windows.Markup.XamlParseException.ThrowException(String message, Exception innerException, Int32 lineNumber, Int32 linePosition, Uri baseUri, XamlObjectIds currentXamlObjectIds, XamlObjectIds contextXamlObjectIds, Type objectType)
      at System.Windows.Markup.XamlParseException.ThrowException(ParserContext parserContext, Int32 lineNumber, Int32 linePosition, String message, Exception innerException)
      at System.Windows.Markup.BamlRecordReader.ElementEndInit(Object& element)
      at System.Windows.Markup.BamlRecordReader.ReadElementEndRecord(Boolean fromNestedBamlRecordReader)
      at System.Windows.Markup.BamlRecordReader.ReadRecord(BamlRecord bamlRecord)
      at System.Windows.Markup.BamlRecordReader.ReadElement(Int64 startPosition, XamlObjectIds contextXamlObjectIds, Object dictionaryKey)
      at System.Windows.ResourceDictionary.CreateObject(Int32 valuePosition, Object key)
      at System.Windows.ResourceDictionary.RealizeDeferContent(Object key, Object& value, Boolean& canCache)
      at System.Windows.ResourceDictionary.GetValueWithoutLock(Object key, Boolean& canCache)
      at System.Windows.ResourceDictionary.GetValue(Object key, Boolean& canCache)
      at System.Windows.FrameworkElement.FindResourceOnSelf(Object resourceKey, Boolean allowDeferredResourceReference, Boolean mustReturnDeferredResourceReference)
      at System.Windows.Markup.BamlRecordReader.FindResourceInParserStack(Object resourceNameObject, Boolean allowDeferredResourceReference, Boolean mustReturnDeferredResourceReference)
      at System.Windows.Markup.BamlRecordReader.FindResourceInParentChain(Object resourceNameObject, Boolean allowDeferredResourceReference, Boolean mustReturnDeferredResourceReference)
      at System.Windows.StaticResourceExtension.ProvideValueInternal(IBamlReader bamlReader, Object targetObject, Object targetProperty, Boolean allowDeferredReference)
      at System.Windows.StaticResourceExtension.ProvideValue(IServiceProvider serviceProvider)
      at System.Windows.Markup.BamlRecordReader.ProvideValueFromMarkupExtension(MarkupExtension markupExtension, Object obj, Object member)
      at System.Windows.Markup.BamlRecordReader.BaseReadOptimizedMarkupExtension(Object element, Int16 attributeId, PropertyDefinition propertyDefinition, Object value)
      at System.Windows.Markup.BamlRecordReader.ReadPropertyWithExtensionRecord(BamlPropertyWithExtensionRecord bamlPropertyRecord)
      at System.Windows.Markup.BamlRecordReader.ReadRecord(BamlRecord bamlRecord)
      at System.Windows.Markup.BamlRecordReader.Read(Boolean singleRecord)
      at System.Windows.Markup.TreeBuilderBamlTranslator.ParseFragment()
      at System.Windows.Markup.TreeBuilder.Parse()
      at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
      at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
      at WPFPhysics1.Window1.InitializeComponent() in c:\research\downloaded_source\WPF2DPhysics-49966\WPFPhysics1\Window1.xaml:line 1
      at WPFPhysics1.Window1..ctor() in C:\research\downloaded_source\WPF2DPhysics-49966\WPFPhysics1\Window1.xaml.cs:line 25
      InnerException: System.Reflection.TargetInvocationException
      Message=Exception has been thrown by the target of an invocation.
      Source=PresentationFramework
      StackTrace:
      at System.Windows.Data.ObjectDataProvider.CreateObjectInstance(Exception& e)
      at System.Windows.Data.ObjectDataProvider.QueryWorker(Object obj)
      at System.Windows.Data.DataSourceProvider.EndInit()
      at System.Windows.Markup.BamlRecordReader.ElementEndInit(Object& element)
      InnerException: System.BadImageFormatException
      Message=An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
      Source=NewtonDynamics
      StackTrace:
      at NewtonDynamics.Newton.NewtonCreate(AllocMemory pAllocMemory, FreeMemory pFreeMemory)
      at NewtonDynamics.CWorld..ctor() in C:\research\downloaded_source\WPF2DPhysics-49966\NewtonDynamics\Wrapper\CWorld.cs:line 39
      at WPFPhysics1.Bodies..ctor(Double worldWidth, Double worldHeight) in C:\research\downloaded_source\WPF2DPhysics-49966\WPFPhysics1\Bodies.cs:line 21
      InnerException:

      Reply

      1. OK, I fixed it. VS2010 was a red herring, the key is to compile in x86 rather than 64 bit (“Any CPU” on my machine is 64, hence the problem).

        Sorry about the long previous post–hopefully this will help others who are interested in examining this very cool demo project.

  19. Chris,

    This is a real great demo to kick start the WPF and NewtonDynamics learning process.

    I have been making some enhancements to make the demo even more fun. The 2 that I have completed till now are:

    1) Click to remove a body from the world
    2) Click and “push” the body in any given direction

    I can send you the code if you think others would be interested.

    The main challenge for me (being new to C#, NewtonDynamics and WPF) was to get to the Newton Body object from the WPF Visual Object. Once I put that in place, it indeed was rather simple.

    Reply

  20. Rohit – I’d love you see the enhancements you’ve made! I’d happily post something about it. I’d recommend setting up a quick project for it on CodePlex, then use TortoiseSVN to get it up there (let me know if you need any help).

    You’ll probably also enjoy using Walaber’s “soft body physics” engine I’ve used a few times:

    https://chriscavanagh.wordpress.com/2008/06/24/silverlight-soft-body-physics/

    Once you see jello rolling around your screen, you’ll be hooked šŸ™‚

    Reply

  21. Almost there, but I am getting an authentication failure when I try to import my source code into CodePlex. Checked and double check passwords.

    The CodePlex server was down for a little bit earlier today. I will try again tomorrow.

    Reply

  22. Guys,
    It may be cool to look at, but have you ever taken a look at the amount of CPU this small demo chews up? I have a Core 2 Duo machine where I am running this demo on. I noticed that if I keep on dropping rectangles, after some time, the whole animation becomes sluggish. The task manager shows the demo taking 66% CPU even when it was not the main window. That’s too much CPU for a small animation demo like this.

    Reply

Leave a comment