Kean Walmsley

July 2009

Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Twitter Updates

    follow me on Twitter



    « Adding XData to AutoCAD entities using .NET | Main | Taking a snapshot of the AutoCAD model using .NET »

    April 05, 2007

    Rendering AutoCAD models offscreen using .NET

    This question came up in an internal discussion, and I thought I'd share the code provided by our Engineering team with you (with a few minor additions from my side, of course).

    The idea is to render a 3D scene off-screen (i.e. save to file the rendered image not visible in the editor). In the below code, we do zoom to the extents of the 3D model that gets created, just to show it's there, but the rendering activity itself is not performed by the 3D view that is used to generate the graphics for AutoCAD's editor window.

    A 3D model does need to be loaded in the editor for this to work, so I decided to add a simple sphere to the modelspace and set its material to one that renders nicely (Sitework.Paving - Surfacing.Riverstone.Mortared). The code doesn't import the material programmatically, so you'll want to make sure it's there in the drawing to get the full effect of the rendering (by dragging the material into the drawing view from the materials tool palette, for instance), or to change the code to point to one that exists in the active drawing.

    Here's the C# code:

    using Autodesk.AutoCAD.ApplicationServices;

    using Autodesk.AutoCAD.DatabaseServices;

    using Autodesk.AutoCAD.EditorInput;

    using Autodesk.AutoCAD.Runtime;

    using Autodesk.AutoCAD.GraphicsSystem;

    using Autodesk.AutoCAD.Interop;

    using System.Drawing;


    namespace OffscreenRendering

    {

      public class Commands

      {

        [CommandMethod("OSR")]

        static public void OffscreenRender()

        {

          CreateSphere();

          RenderToFile("c:\\sphere.png");

        }


        static public void CreateSphere()

        {

          Document doc =

            Application.DocumentManager.MdiActiveDocument;

          Database db = doc.Database;

          Editor ed = doc.Editor;


          Transaction tr =

            doc.TransactionManager.StartTransaction();

          using (tr)

          {

            BlockTable bt =

              (BlockTable)tr.GetObject(

                db.BlockTableId,

                OpenMode.ForRead

              );

            BlockTableRecord btr =

              (BlockTableRecord)tr.GetObject(

                bt[BlockTableRecord.ModelSpace],

                OpenMode.ForWrite

              );

            Solid3d sol = new Solid3d();

            sol.CreateSphere(10.0);


            const string matname =

              "Sitework.Paving - Surfacing.Riverstone.Mortared";

            DBDictionary matdict =

              (DBDictionary)tr.GetObject(

                db.MaterialDictionaryId,

                OpenMode.ForRead

              );

            if (matdict.Contains(matname))

            {

              sol.Material = matname;

            }

            else

            {

              ed.WriteMessage(

                "\nMaterial (" + matname + ") not found" +

                " - sphere will be rendered without it.",

                matname

              );

            }

            btr.AppendEntity(sol);


            tr.AddNewlyCreatedDBObject(sol, true);

            tr.Commit();

          }

          AcadApplication acadApp =

            (AcadApplication)Application.AcadApplication;

          acadApp.ZoomExtents();

        }


        static public void RenderToFile(string filename)

        {

          Document doc =

            Application.DocumentManager.MdiActiveDocument;

          Editor ed = doc.Editor;

          int vpn =

            System.Convert.ToInt32(

              Application.GetSystemVariable("CVPORT")

            );

          View gsv =

            doc.GraphicsManager.GetGsView(vpn, true);

          using (View view = gsv.Clone(true, true))

          {

            Device dev =

              doc.GraphicsManager.CreateAutoCADOffScreenDevice();

            using (dev)

            {

              dev.OnSize(doc.GraphicsManager.DisplaySize);

              dev.DeviceRenderType = RendererType.FullRender;

              dev.Add(view);

              using (Bitmap bitmap = view.RenderToImage())

              {

                bitmap.Save(filename);

                ed.WriteMessage(

                  "\nRendered image saved to: " +

                  filename

                );

              }

            }

          }

        }

      }

    }

    And here's the resized contents of the file created at c:\sphere.png by the OSR command:

    Offscreen_rendered_sphere

    TrackBack

    TrackBack URL for this entry:
    http://www.typepad.com/services/trackback/6a00d83452464869e200d834961f4d53ef

    Listed below are links to weblogs that reference Rendering AutoCAD models offscreen using .NET:

    Comments

    Hi Kean,
    Which version of AutoCAD/ObjectARX is needed to run this example?

    Thanks for sharing with us your knowledge ;-)

    Regards,

    Rubén Dopico

    Hi Rubén,

    My apologies - I keep forgetting to put that information in my posts <sigh>.

    This code uses API functionality that was introduced in AutoCAD 2007.

    Regards.

    Kean

    Your work looks great! I had a question...I am rendering an interior scene, and I can't seem to get it really real looking any suggestions?

    Sorry, Melissa - I'm really not a rendering expert. I'm sure someone on the discussion groups (http://discussion.autodesk.com) will be able to help.

    I see comments that some of the code you used includes items from autocad 2007, is the autocad.interop namespace available for 2006? If so it might explain some problems i am having.

    The Interop namespace is needed when you're working with AutoCAD's COM interface - these have been in the product for a long time, so I doubt this is the issue you're facing.

    Regards,

    Kean

    I’m interested in porting your C# code to VBA. Is it possible?

    Hi Roberto,

    To the best of my knowledge, the Graphics System has not been exposed through COM. So an ObjectARX or .NET component will be needed to implement this function (which can then be called from VBA, should you so wish).

    Regards,

    Kean

    Verify your Comment

    Previewing your Comment

    This is only a preview. Your comment has not yet been posted.

    Working...
    Your comment could not be posted. Error type:
    Your comment has been posted. Post another comment

    The letters and numbers you entered did not match the image. Please try again.

    As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

    Having trouble reading this image? View an alternate.

    Working...

    Post a comment

    Feed & Share

    Search