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:


Subscribe via RSS
Hi Kean,
Which version of AutoCAD/ObjectARX is needed to run this example?
Thanks for sharing with us your knowledge ;-)
Regards,
Rubén Dopico
Posted by: Rubén Dopico | April 11, 2007 at 12:13 PM
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
Posted by: Kean | April 11, 2007 at 02:32 PM
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?
Posted by: melissa | April 27, 2007 at 05:28 AM
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.
Posted by: Kean | April 27, 2007 at 05:33 AM
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.
Posted by: Jason | July 26, 2007 at 04:56 PM
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
Posted by: Kean | July 27, 2007 at 09:34 AM
I’m interested in porting your C# code to VBA. Is it possible?
Posted by: Roberto | September 26, 2007 at 04:33 PM
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
Posted by: Kean | September 27, 2007 at 02:33 PM