Skip to content

Commit

Permalink
Added ground plane option and image render sizes settable in prefs
Browse files Browse the repository at this point in the history
  • Loading branch information
yorikvanhavre committed Jun 28, 2019
1 parent ab218af commit 5309d85
Show file tree
Hide file tree
Showing 7 changed files with 355 additions and 36 deletions.
1 change: 1 addition & 0 deletions InitGui.py
Expand Up @@ -95,6 +95,7 @@ def QT_TRANSLATE_NOOP(scope, text):
commands = Render.RenderCommands
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench","Render"),commands)
self.appendMenu(QT_TRANSLATE_NOOP("Workbench","&Render"),commands)
FreeCADGui.addIconPath(Render.iconpath)
FreeCADGui.addPreferencePage(Render.prefpage,"Render")
Log ('Loading Render module...done\n')

Expand Down
107 changes: 92 additions & 15 deletions Render.py
Expand Up @@ -30,15 +30,24 @@
from PySide import QtCore, QtGui
def translate(context, text):
if sys.version_info.major >= 3:
return QtGui.QApplication.translate(context, text, None, QtGui.QApplication.UnicodeUTF8)
if hasattr(QtGui.QApplication,"UnicodeUTF8"):
return QtGui.QApplication.translate(context, text, None, QtGui.QApplication.UnicodeUTF8)
else:
return QtGui.QApplication.translate(context, text, None)
else:
return QtGui.QApplication.translate(context, text, None, QtGui.QApplication.UnicodeUTF8).encode("utf8")
if hasattr(QtGui.QApplication,"UnicodeUTF8"):
return QtGui.QApplication.translate(context, text, None, QtGui.QApplication.UnicodeUTF8).encode("utf8")
else:
return QtGui.QApplication.translate(context, text, None).encode("utf8")
else:
def translate(context,txt):
return txt
def QT_TRANSLATE_NOOP(scope, text):
return text




class RenderProjectCommand:


Expand All @@ -59,7 +68,7 @@ def Activated(self):
project.Label = self.renderer + " Project"
project.Renderer = self.renderer
ViewProviderProject(project.ViewObject)
filename = QtGui.QFileDialog.getOpenFileName(FreeCADGui.getMainWindow(),'Select template','*.*')
filename = QtGui.QFileDialog.getOpenFileName(FreeCADGui.getMainWindow(),'Select template',os.path.join(os.path.dirname(__file__),"templates"),'*.*')
if filename:
project.Template = filename[0]
project.ViewObject.Proxy.setCamera()
Expand Down Expand Up @@ -174,14 +183,39 @@ class Project:

def __init__(self,obj):

obj.addProperty("App::PropertyString", "Renderer", "Render", QT_TRANSLATE_NOOP("App::Property","The name of the raytracing engine to use"))
obj.addProperty("App::PropertyBool", "DelayedBuild", "Render", QT_TRANSLATE_NOOP("App::Property","If true, the views will be updated on render only"))
obj.addProperty("App::PropertyFile", "Template", "Render", QT_TRANSLATE_NOOP("App::Property","The template to be use by this rendering"))
obj.addProperty("App::PropertyString", "Camera", "Render", QT_TRANSLATE_NOOP("App::Property","The camera data to be used"))
obj.addProperty("App::PropertyFileIncluded", "PageResult", "Render", QT_TRANSLATE_NOOP("App::Property","The result file to be sent to the renderer"))
obj.addExtension("App::GroupExtensionPython", self)
obj.DelayedBuild = True
obj.Proxy = self
self.setProperties(obj)

def setProperties(self,obj):

if not "Renderer" in obj.PropertiesList:
obj.addProperty("App::PropertyString","Renderer","Render", QT_TRANSLATE_NOOP("App::Property","The name of the raytracing engine to use"))
if not "DelayedBuild" in obj.PropertiesList:
obj.addProperty("App::PropertyBool","DelayedBuild","Render", QT_TRANSLATE_NOOP("App::Property","If true, the views will be updated on render only"))
obj.DelayedBuild = True
if not "Template" in obj.PropertiesList:
obj.addProperty("App::PropertyFile","Template","Render", QT_TRANSLATE_NOOP("App::Property","The template to be use by this rendering"))
if not "Camera" in obj.PropertiesList:
obj.addProperty("App::PropertyString","Camera","Render", QT_TRANSLATE_NOOP("App::Property","The camera data to be used"))
if not "PageResult" in obj.PropertiesList:
obj.addProperty("App::PropertyFileIncluded", "PageResult","Render", QT_TRANSLATE_NOOP("App::Property","The result file to be sent to the renderer"))
if not "Group" in obj.PropertiesList:
obj.addExtension("App::GroupExtensionPython", self)
if not "RenderWidth" in obj.PropertiesList:
obj.addProperty("App::PropertyInteger","RenderWidth","Render", QT_TRANSLATE_NOOP("App::Property","The width of the rendered image in pixels"))
obj.RenderWidth = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Render").GetInt("RenderWidth",800)
if not "RenderHeight" in obj.PropertiesList:
obj.addProperty("App::PropertyInteger","RenderHeight","Render", QT_TRANSLATE_NOOP("App::Property","The height of the rendered image in pixels"))
obj.RenderHeight = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Render").GetInt("RenderHeight",600)
if not "GroundPlane" in obj.PropertiesList:
obj.addProperty("App::PropertyBool","GroundPlane","Render", QT_TRANSLATE_NOOP("App::Property","If true, a default ground plane will be added to the scene"))
obj.GroundPlane = False
obj.setEditorMode("PageResult",2)
obj.setEditorMode("Camera",2)

def onDocumentRestored(self,obj):

self.setProperties(obj)

def execute(self,obj):

Expand Down Expand Up @@ -229,6 +263,48 @@ def writeObject(self,obj,view):
else:
return renderer.writeObject(view)

def writeGroundPlane(self,obj):

result = ""
bbox = FreeCAD.BoundBox()
for view in obj.Group:
if view.Source and hasattr(view.Source,"Shape") and hasattr(view.Source.Shape,"BoundBox"):
bbox.add(view.Source.Shape.BoundBox)
if bbox.isValid():
import Part
margin = bbox.DiagonalLength/2
p1 = FreeCAD.Vector(bbox.XMin-margin,bbox.YMin-margin,0)
p2 = FreeCAD.Vector(bbox.XMax+margin,bbox.YMin-margin,0)
p3 = FreeCAD.Vector(bbox.XMax+margin,bbox.YMax+margin,0)
p4 = FreeCAD.Vector(bbox.XMin-margin,bbox.YMax+margin,0)

# create temporary object. We do this to keep the renderers code as simple as possible:
# they only ned to deal with one type of object: RenderView objects
dummy1 = FreeCAD.ActiveDocument.addObject("Part::Feature","renderdummy1")
dummy1.Shape = Part.Face(Part.makePolygon([p1,p2,p3,p4,p1]))
dummy2 = FreeCAD.ActiveDocument.addObject("App::FeaturePython","renderdummy2")
View(dummy2)
dummy2.Source = dummy1
ViewProviderView(dummy2.ViewObject)
FreeCAD.ActiveDocument.recompute()

if obj.Renderer:
try:
renderer = importlib.import_module("renderers."+obj.Renderer)
except ImportError:
FreeCAD.Console.PrintError(translate("Render","Error importing renderer")+" "+str(obj.Renderer))
else:
r = renderer.writeObject(dummy2)
if r:
result = r

# remove temp objects
FreeCAD.ActiveDocument.removeObject(dummy2.Name)
FreeCAD.ActiveDocument.removeObject(dummy1.Name)
FreeCAD.ActiveDocument.recompute()

return result

def render(self,obj,external=True):

if obj.Renderer:
Expand All @@ -253,6 +329,8 @@ def render(self,obj,external=True):
renderobjs += self.writeObject(obj,view)
else:
renderobjs += view.ViewResult
if hasattr(obj,"GroundPlane") and obj.GroundPlane:
renderobjs += self.writeGroundPlane(obj)

if "RaytracingCamera" in template:
template = re.sub("(.*RaytracingCamera.*)",cam,template)
Expand All @@ -276,10 +354,8 @@ def render(self,obj,external=True):
FreeCAD.Console.PrintError(translate("Render","Error importing renderer")+" "+str(obj.Renderer))
return ""
else:
try:
return renderer.render(obj,external)
except:
FreeCAD.Console.PrintError(translate("Render","Error while executing renderer")+" "+str(obj.Renderer))
return renderer.render(obj,external)
# FreeCAD.Console.PrintError(translate("Render","Error while executing renderer")+" "+str(obj.Renderer))


class ViewProviderProject:
Expand Down Expand Up @@ -402,7 +478,7 @@ def getIcon(self):
RenderCommands = []
Renderers = os.listdir(os.path.dirname(__file__)+os.sep+"renderers")
Renderers = [r for r in Renderers if not ".pyc" in r]
Renderers = [r for r in Renderers if not "__init__" in r]
Renderers = [r for r in Renderers if not "__" in r]
Renderers = [os.path.splitext(r)[0] for r in Renderers]
for renderer in Renderers:
FreeCADGui.addCommand('Render_'+renderer, RenderProjectCommand(renderer))
Expand All @@ -413,4 +489,5 @@ def getIcon(self):
RenderCommands.append('Render_Render')

# This is for InitGui.py because it cannot import os
iconpath = os.path.join(os.path.dirname(__file__),"icons")
prefpage = os.path.join(os.path.dirname(__file__),"ui","RenderSettings.ui")
116 changes: 116 additions & 0 deletions icons/preferences-render.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 26 additions & 5 deletions renderers/Appleseed.py
Expand Up @@ -31,7 +31,7 @@
# A render engine module must contain the following functions:
#
# writeCamera(camdata): returns a string containing an openInventor camera string in renderer format
# writeObject(viewobj): returns a string containing a RaytracingView object in renderer format
# writeObject(view): returns a string containing a RaytracingView object in renderer format
# render(project,external=True): renders the given project, external means if the user wishes to open
# the render file in an external application/editor or not. If this
# is not supported by your renderer, you can simply ignore it
Expand All @@ -42,7 +42,11 @@
# An icon under the name Renderer.svg (where Renderer is the name of your Renderer


import tempfile,FreeCAD,os,math
import tempfile
import FreeCAD
import os
import math
import re


def writeCamera(camdata):
Expand Down Expand Up @@ -96,7 +100,7 @@ def writeCamera(camdata):
up = rot.multVec(FreeCAD.Vector(0,1,0))
up = str(up.x)+" "+str(up.y)+" "+str(up.z)
pos = str(pos.x)+" "+str(pos.y)+" "+str(pos.z)
print("cam:",pos," : ",tpos," : ",up)
#print("cam:",pos," : ",tpos," : ",up)
cam = """
<camera name="camera" model="thinlens_camera">
<parameter name="film_width" value="0.032" />
Expand Down Expand Up @@ -232,6 +236,23 @@ def render(project,external=False):

if not project.PageResult:
return

if hasattr(project,"RenderWidth") and hasattr(project,"RenderHeight"):
# change image size in template
f = open(project.PageResult,"r")
t = f.read()
f.close()
res = re.findall("<parameter name=\"resolution.*?\/>",t)
if res:
t = t.replace(res[0],"<parameter name=\"resolution\" value=\""+str(project.RenderWidth)+" "+str(project.RenderHeight)+"\" />")
fp = tempfile.mkstemp(prefix=project.Name,suffix=os.path.splitext(project.Template)[-1])[1]
f = open(fp,"w")
f.write(t)
f.close()
project.PageResult = fp
os.remove(fp)
FreeCAD.ActiveDocument.recompute()

p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Render")
if external:
rpath = p.GetString("AppleseedStudioPath","")
Expand All @@ -240,10 +261,10 @@ def render(project,external=False):
rpath = p.GetString("AppleseedCliPath","")
args = p.GetString("AppleseedParameters","")
if not rpath:
raise
FreeCAD.Console.PrintError("Unable to locate Appleseed executable. Please set the correct path in Edit -> Preferences -> Render")
return
if args:
args += " "
import os
os.system(rpath+" "+args+project.PageResult)
return

Expand Down

0 comments on commit 5309d85

Please sign in to comment.