Skip to content

Instantly share code, notes, and snippets.

@yorikvanhavre
Last active June 5, 2020 12:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yorikvanhavre/e9722c280118b1ef141c4061d9d2dd8a to your computer and use it in GitHub Desktop.
Save yorikvanhavre/e9722c280118b1ef141c4061d9d2dd8a to your computer and use it in GitHub Desktop.
FreeCAD offline rendering example
#!/usr/bin/python3
"""
This is a test file to test offline rendering functionality. It takes a FreeCAD file (colors.FCStd in
the examples below) and will produce colors.obj, colors.mtl, colors.dae, colors.ifc, colors.stp
and colors.png files in the same directory. It also saves a copy of the colors.FCStd file with
colors preserved.
Instructions:
- make sure you have the latest version of FreeCAD installed
- make sure you have the pivy (python bindongs for coin3D) package installed
- make sure FreeCAD is importable from python (use the commented line below if needed)
- on linux, the X server must have indirect rendering enabled in order to be able to do
offline PNG rendering. Unfortunatley, this is turned off by default on most recent
distros. The easiest way I found is to edit (or create if inexistant) /etc/X11/xorg.conf
and add this:
Section "ServerFlags"
Option "AllowIndirectGLX" "on"
Option "IndirectGLX" "on"
EndSection
(if your xorg.conf already has a "ServerFlags" section, just add the two options in it).
There might be other ways for other distros though, google for "enable indirect glx"
with your distro name and version
"""
import os # builtin python lib
import sys # builtin python lib
# if needed, uncomment and set the path to your FreeCAD.so (or FreeCAD.pyd on windows) below:
# sys.path.append("/path/to/FreeCAD.so")
# Another way, more system-independent, is to symlink your FreeCAD.so file to
# .local/lib/Python3.7/site-packages (user-wide) or
# /usr/lib/python3.7/dis-packages (system-wide)
# (using your version of python3 instead of 3.7 in the links above if applicable)
import FreeCAD # main freecad lib, to be imported before any other FreeCAD component (will add their paths to sys)
import importOBJ # builtin FreeCAD exporter
import importDAE # builtin FreeCAD exporter
import importIFC # builtin FreeCAD exporter
import importWebGL # builtin FreeCAD exporter
import Import # builtin FreeCAD exporter (step & iges)
import OfflineRenderingUtils # the offline rendering utilities module
# build full filepaths (not 100% required, relative paths work in python too, but always safer)
freecadFile = os.path.join(os.getcwd(),"colors.FCStd")
baseFileName = os.path.splitext(freecadFile)[0]
# extract the original xml file for verification later
OfflineRenderingUtils.extract(freecadFile,"GuiDocument.xml",os.path.join(os.path.dirname(freecadFile),"GuiDocument.xml"))
# open FreeCAD file
doc = FreeCAD.open(freecadFile)
# build color dict
# setting nodiffuse=True (optional) discards per-face colors, and only sets one color per object
# only the STEP exporter accepts per-face colors. The others would consider the first color in the per-face colors list as
# the object color, which might be not what we want, so it's best to turn it off here.
colors = OfflineRenderingUtils.getColors(freecadFile,nodiffuse=True)
# get the camera data from the file (used in some functions below)
camera = OfflineRenderingUtils.getCamera(freecadFile)
# export to OBJ
importOBJ.export(doc.Objects,baseFileName+".obj",colors=colors)
# export to DAE
importDAE.export(doc.Objects,baseFileName+".dae",colors=colors)
# export to IFC
importIFC.export(doc.Objects,baseFileName+".ifc",colors=colors)
# export to WebGL
importWebGL.export(doc.Objects,baseFileName+".html",colors=colors,camera=camera)
# export to STEP
# The STEP exporter accepts different kind of data than the above
# exporters. Use the function below to reformat it the proper way
stepdata = OfflineRenderingUtils.getStepData(doc.Objects,colors)
Import.export(stepdata,baseFileName+".stp")
# export to PNG
scene = OfflineRenderingUtils.buildScene(doc.Objects,colors)
OfflineRenderingUtils.render(baseFileName+".png",scene,camera,width=800,height=600)
# view the scene in a standalone coin viewer (optional, just for fun)
#OfflineRenderingUtils.viewer(scene)
# file saving with a color dictionary
OfflineRenderingUtils.save(doc,filename=baseFileName+"_nochange.FCStd",colors=colors,camera=camera)
# file saving reusing a full GuiDocument dictionary
guidata = OfflineRenderingUtils.getGuiData(freecadFile)
# let's the colros of the "Cube" object to yellow
cubecolors = guidata["Cube"]["DiffuseColor"]["value"]
cubecolors = [(1.0,1.0,0.0) for color in cubecolors]
guidata["Cube"]["DiffuseColor"]["value"] = cubecolors
# also change ShapeColor because the test below will discard diffuse colors
guidata["Cube"]["ShapeColor"]["value"] = (1.0,1.0,0.0)
# save the file
changedFile = baseFileName+"_changed.FCStd"
OfflineRenderingUtils.save(doc,filename=changedFile,guidata=guidata)
# make another PNG to check the changed color
colors = OfflineRenderingUtils.getColors(changedFile,nodiffuse=True)
scene = OfflineRenderingUtils.buildScene(doc.Objects,colors)
OfflineRenderingUtils.render(baseFileName+"_changed.png",scene,camera,width=800,height=600)
# extract the modified xml file for verification later
OfflineRenderingUtils.extract(changedFile,"GuiDocument.xml",os.path.join(os.path.dirname(changedFile),"GuiDocument_changed.xml"))
# create diff between the two xml files
os.system("diff GuiDocument.xml GuiDocument_changed.xml > changed.diff")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment