Monthly Archives: October 2016

Post Mortem: Building a Business Class 3D Application in Firemonkey

Introduction

For my day job, I recently had the chance to build a business class 3D application in Delphi with Firemonkey.  For proprietary reasons, I cannot give you a lot of details about the program, but the purpose was to provide a 3D editor where users could assemble 3D object files into a larger project. I thought my lessons learned for using Firemonkey to build a 3D application were interesting enough to share here).  The basic requirements were:

  • Scan a directory of 3D objects files and XML files (that contained metadata about the object files).
  • Provide a list of these objects that users could drag-and-drop or somehow add to a larger project.
  • Provide a cross-platform editor for assembling 3D object files into a larger project.  The user should be able to move, rotate, and align 3D Objects, as well as be able to change their colors, labels, and opacities.
  • Export some project information in a variety of formats (Excel/csv and PDF were specifically mentioned)
  • Works on Windows and Mac (Linux would have been nice but fortunately was not necessary)

The short answer is that it is just barely possible to build a real business class 3D application with Firemonkey.  You need customers who are flexible in their requirements and willing to work around, or live with, the defects in the 3D part of the Firemonkey framework.  For the long answer, keep reading.

What went right

Delphi.  Delphi is an amazingly mature product with a rich and powerful language.  Its libraries for everything between XML support to visual components like TListBox are incredibly complete and mature.  Between the productivity that Delphi gives a developer (specifically in developing the GUI) and my 20 years of experience of working in Delphi, I managed to build the application in a fraction of the time expected and with tons more features than expected.  I was given 9 months to build a prototype application. Instead, I just released the first feature complete, beta version of the production application.  I had a prototype in 2 months that was so good that it blew my customers and colleagues socks off and was directed to go forward in making this the production application.  I was consistently ahead of schedule and adding more features than expected.

Firemonkey on Windows.  Firemonkey, at least the non-3D portion of it, has matured nicely and was able to give most features I needed out of the box.  It worked well with only small problems and bugs.  (The TWebBrowser that I used for displaying the XML files was one glaring exception.  Until the Delphi Berlin 10.1 Update, I could not use Delphi Berlin at all because of bugs in this component).  Finally, I will say that I would not have wanted to use FMX before Seattle, certainly no earlier than XE8.  The speed of the compiled application was adequate, at least on Windows, and the compile-debug cycle on Windows is, as always with Delphi, amazing (I also work on a large Visual Studio C++ project and I often forget what I was working on by the time the darn thing finishes compiling).  The size of the application exe, while large, was reasonable and did not bother my customers.

For exporting, Delphi TStrings class makes it ridiculously easy to make comma-separated files.  Unfortunately, for PDF, Delphi does not have anything that can create PDFs out of the box.  We ended up purchasing TMS Software’s Rich Editor product.  This worked relatively well for us – we were able to add RTF and HTML export as a bonus easily.  Unfortunately, its PDF export is buggy.  We have a bug report in with them and hopefully that will be fixed soon.

Firemonkey 3D Framework.  The Firemonkey 3D framework is something that belongs in both what went right and in what went wrong.  I had the most problems, whether limitations or bugs, with the FMX 3D framework, but ultimately, it barely, just barely, was good enough for the business class 3D application I had to make.  I would not recommend doing 3D in FMX for better than business class applications.  Even with business class 3D applications, it will not necessarily work for all cases and you definitely need flexible customers.  You need to compare your requirements with what FMX 3D framework provides.  For example, if I had needed to modify and save the 3D object files, the project would have had to been abandoned.

But what it did do, it did just good enough.  And, like all things Delphi, it was easy to put something together quickly that visually looked very professional.

What went wrong

Firemonkey 3D Framework.  As I mentioned in the what went right section, the Firemonkey 3D Framework deserves top-billing in what went wrong.  I had the most problems, whether limitations or bugs, with the FMX 3D framework.

The biggest problem was its limited 3D format support.  The customer wanted to read 3D STEP files, but this is not possible in Delphi.  Thankfully, they were willing to accept converting the files to something the FMX 3D framework can read: OBJs or DAEs.  Unfortunately, reading .OBJs, while good on Windows, is really sllooooooooooooww on Mac.  My tests had the Mac version reading OBJs 5-10 times slower than on a Windows machine.   I also never did figure out how to read textures for the OBJs (thankfully, this was not required).  Loading DAEs is actually fast enough on Windows and Mac.  Unfortunately, Delphi’s DAE importer does not support trifolds or tristrips in the DAE file.  As this is what the converter programs were producing, we could not use DAEs (I managed to hack the importer enough to load trifolds and test the speed of loading DAEs, but the surface normals were all scrambled).

The next biggest problem was the opacity of 3D objects.  As reported by Eric Grange 5 years ago,

FireMonkey (as of now) doesn’t support rendering semi-transparent objects in 3D.

FireMonkey only supports blending of semi-transparent objects (either through the Opacity property or because of their texture, for instance a semi-transparent PNG image), but blending alone is not enough to get it right in 3D with a Z-Buffer(which is what FMX, and most 3D apps are using).

Thankfully, this was not a showstopper with the application, though it easily could have been.  Opacity was a nice-to-have, not required.  My customers were willing to live with the problem.

Finally, the FireMonkey 3D framework is just buggy and limited, probably the most buggy portion of the FMX libraries.  For example, if you load a 3D object into a TModel3D that is parented to the viewport, the 3D object loads correctly.  However, if you do the same thing where the TModel3D.Parent is nil, the scale of the 3D object is all wrong.  Changing the parent later will not correct it.  I also never figured out how to get the size of the mesh from the file and adjust the control.  The mesh would always resize to the dimensions of the control, distorting its appearance..  Luckily, I could impose a requirement on the XML files that they would provide the width, height, and depth of the 3D object.  I could first adjust the control size of the TModel3D based on the XML and then load the 3D object file.

Other problems?  Collision detection is limited in Firemonkey 3D.  You can do bounding box collision detection but nothing more precise.  A final minor gripe is that I wish that there was a 3D manipulator control that I could attach to a 3D model.  For example, arrows for dragging the control along an axis and rings to rotate the object.  Again, luckily, for now, my customers were content with using sliders to change the location and rotation.  Perhaps in the future I will add this myself, but this is, to my mind, a basic control that should be added to the Firemonkey 3D framework.

Firemonkey on Mac.  Firemonkey on Mac does not nearly have the maturity of the Windows side.  Partly, I am sure that this is due to the awkwardness of debugging Mac applications.  It is much slower to deploy and debug applications in Mac.  In general, Firemonkey on Mac worked but there were times when it stalled the project.  It is best to test your cross-platform application early and often.  It will not just work, at least to a professional level  The biggest problem I encountered is the slow loading of OBJ files.  Another minor problem is with shortcuts.  There is no way to set both platforms shortcuts easily.  It would be nice if there was an option to automatically convert Ctrl+ from windows to Cmd+ on Mac.  As it was, I IFDEFed Mac code to override the shortcuts on the actions on form creation.

Conclusion

In conclusion, it is possible to create business class 3D applications with Delphi and Firemonkey.  However, you need to be very aware of the limitations imposed and how it will impact fulfilling your requirements.  Be aware that the 3D framework is the orphaned stepchild of the Firemonkey framework.  It is difficult to see any improvements in the 3D portion of the architecture since Firemonkey was launched 5 years ago.  It is obvious in my mind that 3D was a marketing checkbox and that this part of the framework was allowed to languish afterwards. You cannot count on updates to fix missing features from Embarcadero/Idera.

That said, if you can live with the 3D support as it is now and it fulfills your requirements (or you have flexible customers), the Firemonkey framework has matured greatly in other areas in the past few years.  That, combined with the awesome force multiplier that is the regular Delphi development, means that you can create quickly and easily powerful, cross-platform, business class 3D applications.

Views expressed are my own and do not necessarily reflect  those of my employer, or anyone else.

That is all for today.  Happy CodeSmithing!