MtsBlend: better integration

metadata
Wenzel Jakob 2010-11-11 17:24:29 +01:00
parent afdbd4540a
commit 364d9bb13f
13 changed files with 573 additions and 138 deletions

View File

@ -31,29 +31,10 @@ bl_addon_info = {
"category": "Render"}
if "bpy" in locals():
reload(render)
reload(ui)
else:
import bpy
from bpy.props import *
from render_mitsuba import render
from render_mitsuba import ui
from .core import RENDERENGINE_mitsuba
def register():
Scene = bpy.types.Scene
Scene.mts_path = bpy.props.StringProperty(
name = "mts_path",
description="Full path to the 'mitsuba' executable",
default = "", subtype = "FILE_PATH", maxlen=1024)
Scene.mts_gui = bpy.props.BoolProperty(
name = "mts_gui",
description="Should the Mitsuba user interface be launched?",
default = False)
RENDERENGINE_mitsuba.install()
def unregister():
del Scene.mts_path
if __name__ == "__main__":
register()
RENDERENGINE_mitsuba.uninstall()

View File

@ -0,0 +1,145 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# System libs
import os, time, threading, subprocess, sys, copy
# Blender libs
import bpy
# Framework libs
from extensions_framework.engine import engine_base
from extensions_framework import util as efutil
# Mitsuba-related classes
from mitsuba.properties.engine import mitsuba_engine
from mitsuba.operators import MITSUBA_OT_preset_engine_add, EXPORT_OT_mitsuba
from mitsuba.outputs import MtsLog, MtsFilmDisplay
from mitsuba.export.film import resolution
from mitsuba.ui import render_panels
def compatible(mod):
mod = __import__(mod)
for subclass in mod.__dict__.values():
try:
subclass.COMPAT_ENGINES.add('mitsuba')
except:
pass
del mod
import properties_render
properties_render.RENDER_PT_render.COMPAT_ENGINES.add('mitsuba')
properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('mitsuba')
properties_render.RENDER_PT_output.COMPAT_ENGINES.add('mitsuba')
del properties_render
compatible("properties_data_mesh")
compatible("properties_data_camera")
class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base):
bl_idname = 'mitsuba'
bl_label = 'Mitsuba'
property_groups = [
('Scene', mitsuba_engine)
]
render_lock = threading.Lock()
def process_wait_timer(self):
# Nothing to do here
pass
def render(self, scene):
if scene is None:
bpy.ops.ef.msg(msg_type='ERROR', msg_text='Scene to render is not valid')
return
with self.render_lock: # just render one thing at a time
scene_path = efutil.filesystem_path(scene.render.filepath)
if os.path.isdir(scene_path):
self.output_dir = scene_path
else:
self.output_dir = os.path.dirname(scene_path)
if self.output_dir[-1] != '/':
self.output_dir += '/'
efutil.export_path = self.output_dir
os.chdir(self.output_dir)
if scene.render.use_color_management == False:
MtsLog('WARNING: Colour Management is switched off, render results may look too dark.')
MtsLog('MtsBlend: Current directory = "%s"' % self.output_dir)
output_basename = efutil.scene_filename() + '.%s.%05i' % (scene.name, scene.frame_current)
export_result = bpy.ops.export.mitsuba(
directory = self.output_dir,
filename = output_basename,
scene = scene.name
)
if 'CANCELLED' in export_result:
return False
if scene.mitsuba_engine.export_mode == 'render':
(mts_path, tail) = os.path.split(bpy.path.abspath(scene.mitsuba_engine.binary_path))
mtsgui_binary = os.path.join(mts_path, "mtsgui")
mitsuba_binary = os.path.join(mts_path, "mitsuba")
env = copy.copy(os.environ)
mts_render_libpath = os.path.join(mts_path, "src/librender")
mts_core_libpath = os.path.join(mts_path, "src/libcore")
mts_hw_libpath = os.path.join(mts_path, "src/libhw")
env['LD_LIBRARY_PATH'] = mts_core_libpath + ":" + mts_render_libpath + ":" + mts_hw_libpath
MtsLog("MtsBlend: Launching renderer ..")
if scene.mitsuba_engine.render_mode == 'gui':
subprocess.Popen(
[mtsgui_binary, efutil.export_path],
env = env,
cwd = self.output_dir
)
elif scene.mitsuba_engine.render_mode == 'cli':
(output_image, _) = os.path.splitext(efutil.export_path)
self.output_file = output_image + ".png"
mitsuba_process = subprocess.Popen(
[mitsuba_binary, efutil.export_path, '-o', output_image],
env = env,
cwd = self.output_dir
)
framebuffer_thread = MtsFilmDisplay({
'resolution': resolution(scene),
'RE': self,
})
framebuffer_thread.set_kick_period(scene.mitsuba_engine.refresh_interval)
framebuffer_thread.start()
while mitsuba_process.poll() == None and not self.test_break():
self.render_update_timer = threading.Timer(1, self.process_wait_timer)
self.render_update_timer.start()
if self.render_update_timer.isAlive(): self.render_update_timer.join()
# If we exit the wait loop (user cancelled) and luxconsole is still running, then send SIGINT
if mitsuba_process.poll() == None and scene.luxrender_engine.binary_name != 'luxrender':
# Use SIGTERM because that's the only one supported on Windows
luxrender_process.send_signal(subprocess.signal.SIGTERM)
# Stop updating the render result and load the final image
framebuffer_thread.stop()
framebuffer_thread.join()
framebuffer_thread.kick(render_end=True)

View File

@ -0,0 +1,56 @@
class MtsAdjustments:
def __init__(self, target_file):
self.target_file = target_file
def export_worldtrafo(self, adjfile, trafo):
adjfile.write('\t\t<transform name="toWorld">\n')
adjfile.write('\t\t\t<matrix value="')
for j in range(0,4):
for i in range(0,4):
adjfile.write("%f " % trafo[i][j])
adjfile.write('"/>\n\t\t</transform>\n')
def export_lamp(self, adjfile, lamp, idx):
if lamp.data.type == 'POINT':
adjfile.write('\t<luminaire id="%s-light" type="point">\n' % lamp.data.name)
mult = lamp.data.energy * lamp.data.distance * lamp.data.distance / 2
self.export_worldtrafo(adjfile, lamp.matrix_world)
adjfile.write('\t\t<rgb name="intensity" value="%f %f %f"/>\n'
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult))
adjfile.write('\t</luminaire>\n')
elif lamp.data.type == 'AREA':
adjfile.write('\t<shape type="obj">\n')
size_x = lamp.data.size
size_y = lamp.data.size
if lamp.data.shape == 'RECTANGLE':
size_y = lamp.data.size_y
path = os.path.join(os.path.join(self._temp_dir, 'meshes'), "_area_luminaire_%d.obj" % idx)
adjfile.write('\t\t<string name="filename" value="%s"/>\n' % path)
self.export_worldtrafo(adjfile, lamp.matrix_world)
adjfile.write('\n\t\t<luminaire id="%s-light" type="area">\n' % lamp.data.name)
mult = lamp.data.energy * lamp.data.distance * lamp.data.distance / (size_x * size_y)
adjfile.write('\t\t\t<rgb name="intensity" value="%f %f %f"/>\n'
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult))
adjfile.write('\t\t</luminaire>\n')
adjfile.write('\t</shape>\n')
objFile = open(path, 'w')
objFile.write('v %f %f 0\n' % (-size_x/2, -size_y/2))
objFile.write('v %f %f 0\n' % ( size_x/2, -size_y/2))
objFile.write('v %f %f 0\n' % ( size_x/2, size_y/2))
objFile.write('v %f %f 0\n' % (-size_x/2, size_y/2))
objFile.write('f 4 3 2 1\n')
objFile.close()
def export(self, scene):
adjfile = open(self.target_file, 'w')
adjfile.write('<adjustments>\n');
idx = 0
for obj in scene.objects:
if obj.type == 'LAMP':
self.export_lamp(adjfile, obj, idx)
idx = idx+1
adjfile.write('</adjustments>\n');
adjfile.close()

View File

@ -0,0 +1,10 @@
def resolution(scene):
'''
scene bpy.types.scene
Calculate the output render resolution
Returns tuple(2) (floats)
'''
xr = scene.render.resolution_x * scene.render.resolution_percentage / 100.0
yr = scene.render.resolution_y * scene.render.resolution_percentage / 100.0
return xr, yr

View File

@ -0,0 +1,172 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# System Libs
import os, copy, subprocess
# Blender Libs
import bpy
from presets import AddPresetBase
# Extensions_Framework Libs
from extensions_framework import util as efutil
from mitsuba.outputs import MtsLog
from mitsuba.export import MtsAdjustments
def try_preset_path_create(preset_subdir):
target_path = os.path.join(bpy.utils.preset_paths('')[0], preset_subdir)
if not os.path.exists(target_path):
os.makedirs(target_path)
class MITSUBA_MT_base(object):
preset_operator = "script.execute_preset"
def draw(self, context):
try_preset_path_create(self.preset_subdir)
return bpy.types.Menu.draw_preset(self, context)
class MITSUBA_OT_preset_base(AddPresetBase):
def execute(self, context):
try_preset_path_create(self.preset_subdir)
return super().execute(context)
class MITSUBA_MT_presets_engine(MITSUBA_MT_base, bpy.types.Menu):
bl_label = "Mitsuba Engine Presets"
preset_subdir = "mitsuba/engine"
class MITSUBA_OT_preset_engine_add(MITSUBA_OT_preset_base, bpy.types.Operator):
'''Save the current settings as a preset'''
bl_idname = 'mitsuba.preset_engine_add'
bl_label = 'Add Mitsuba Engine settings preset'
preset_menu = 'MITSUBA_MT_presets_engine'
preset_values = [
'bpy.context.scene.mitsuba_engine.%s'%v['attr'] for v in bpy.types.mitsuba_engine.get_exportable_properties()
]
preset_subdir = 'mitsuba/engine'
class MitsubaCheckOp(bpy.types.Operator):
bl_idname = 'mts.check'
bl_label = 'Check scene'
def reportWarning(self, msg):
self.report({'WARNING'}, msg)
print("MtsBlend: %s" % msg)
def _check_lamp(self, lamp):
hasErrors = False
if lamp.type == 'POINT' and lamp.falloff_type != 'INVERSE_SQUARE':
self.reportWarning('Point light "%s" needs to have inverse square falloff' % lamp.name)
hasErrors = True
if hasErrors:
self.reportWarning('Encountered one or more problems -- check the console')
else:
self.report({'INFO'}, "No problems found")
def execute(self, context):
scene = bpy.data.scenes[0]
for obj in scene.objects:
if obj.type == 'LAMP':
self._check_lamp(obj.data)
return {'FINISHED'}
class EXPORT_OT_mitsuba(bpy.types.Operator):
bl_idname = 'export.mitsuba'
bl_label = 'Export Mitsuba Scene (.xml)'
filename = bpy.props.StringProperty(name='Target filename')
directory = bpy.props.StringProperty(name='Target directory')
scene = bpy.props.StringProperty(options={'HIDDEN'}, default='')
def invoke(self, context, event):
context.window_manager.add_fileselect(self)
return {'RUNNING_MODAL'}
def execute(self, context):
if self.properties.scene == '':
scene = context.scene
else:
scene = bpy.data.scenes[self.properties.scene]
if scene is None:
self.report({'ERROR'}, 'Scene is not valid for export to %s' % self.properties.filename)
return {'CANCELLED'}
# Force scene update; NB, scene.update() doesn't work
scene.frame_set(scene.frame_current)
(self.properties.filename, _) = os.path.splitext(self.properties.filename)
mts_basename = os.path.join(
self.properties.directory,
self.properties.filename)
mts_dae_file = mts_basename + ".dae"
mts_xml_file = mts_basename + ".xml"
mts_adj_file = mts_basename + "_adjustments.xml"
mts_meshes_dir = os.path.join(self.properties.directory, "meshes")
efutil.export_path = mts_xml_file
try:
os.mkdir(mts_meshes_dir)
except OSError:
pass
scene.collada_export(mts_dae_file)
MtsLog('MtsBlend: Writing adjustments file to "%s"' % mts_adj_file)
adj = MtsAdjustments(mts_adj_file)
adj.export(scene)
if scene.mitsuba_engine.binary_path == "":
self.report({'ERROR'}, 'Mitsuba binary path must be specified!')
return {'CANCELLED'}
scene.mitsuba_engine.binary_path = efutil.filesystem_path(scene.mitsuba_engine.binary_path)
efutil.write_config_value('mitsuba', 'defaults', 'binary_path', scene.mitsuba_engine.binary_path)
(mts_path, tail) = os.path.split(bpy.path.abspath(scene.mitsuba_engine.binary_path))
mtsimport_binary = os.path.join(mts_path, "mtsimport")
env = copy.copy(os.environ)
mts_render_libpath = os.path.join(mts_path, "src/librender")
mts_core_libpath = os.path.join(mts_path, "src/libcore")
mts_hw_libpath = os.path.join(mts_path, "src/libhw")
env['LD_LIBRARY_PATH'] = mts_core_libpath + ":" + mts_render_libpath + ":" + mts_hw_libpath
render = scene.render
width = int(render.resolution_x * render.resolution_percentage * 0.01)
height = int(render.resolution_y * render.resolution_percentage * 0.01)
MtsLog("MtsBlend: Launching mtsimport")
try:
process = subprocess.Popen(
[mtsimport_binary, '-r', '%dx%d' % (width, height),
'-l', 'pngfilm', mts_dae_file, mts_xml_file, mts_adj_file],
env = env,
cwd = self.properties.directory
)
if process.wait() != 0:
self.report({'ERROR'}, "mtsimport returned with a nonzero status!")
return {'CANCELLED'}
except OSError:
self.report({'ERROR'}, "Could not execute '%s'" % mtsimport_binary)
return {'CANCELLED'}
return {'FINISHED'}
menu_func = lambda self, context: self.layout.operator("export.mitsuba", text="Export Mitsuba scene...")
bpy.types.INFO_MT_file_export.append(menu_func)

View File

@ -0,0 +1,38 @@
import os
import bpy
from extensions_framework import log
from extensions_framework.util import TimerThread
def MtsLog(*args, popup=False):
'''
Send string to AF log, marked as belonging to Mitsuba module.
Accepts variable args (can be used as pylux.errorHandler)
'''
if len(args) > 0:
log(' '.join(['%s'%a for a in args]), module_name='Mitsuba', popup=popup)
class MtsFilmDisplay(TimerThread):
'''
Periodically update render result with Mituba's framebuffer
'''
STARTUP_DELAY = 1
def kick(self, render_end=False):
xres, yres = self.LocalStorage['resolution']
if render_end:
MtsLog('Final render result %ix%i' % (xres,yres))
else:
MtsLog('Updating render result %ix%i' % (xres,yres))
result = self.LocalStorage['RE'].begin_result(0, 0, int(xres), int(yres))
if os.path.exists(self.LocalStorage['RE'].output_file):
bpy.ops.ef.msg(msg_text='Updating RenderResult')
lay = result.layers[0]
lay.load_from_file(self.LocalStorage['RE'].output_file)
else:
err_msg = 'ERROR: Could not load render result from %s' % self.LocalStorage['RE'].output_file
MtsLog(err_msg)
bpy.ops.ef.msg(msg_type='ERROR', msg_text=err_msg)
self.LocalStorage['RE'].end_result(result)

View File

@ -0,0 +1,85 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
from extensions_framework import declarative_property_group
from extensions_framework import util as efutil
class mitsuba_engine(declarative_property_group):
'''
Storage class for Mitsuba Engine settings.
This class will be instantiated within a Blender scene
object.
'''
controls = [
'export_mode',
'render_mode',
'binary_path',
'refresh_interval'
]
visibility = {
'render_mode': { 'export_mode': 'render' },
'refresh_interval': { 'export_mode': 'render', 'render_mode' : 'cli' }
}
properties = [
{
'type': 'enum',
'attr': 'export_mode',
'name': 'Export mode',
'description': 'Specifies whether or not to launch the renderer after exporting the scene',
'default': 'render',
'items': [
('render', 'Export + Render', 'render'),
('exportonly', 'Only export', 'exportonly')
],
'save_in_preset': True
},
{
'type': 'enum',
'attr': 'render_mode',
'name': 'Rendering mode',
'description': 'Launch the external GUI or use the command-line renderer?',
'default': 'cli',
'items': [
('cli', 'Mitsuba CLI', 'cli'),
('gui', 'Mitsuba GUI', 'gui')
],
'save_in_preset': True
},
{
'type': 'string',
'subtype': 'DIR_PATH',
'attr': 'binary_path',
'name': 'Executable path',
'description': 'Path to the "mitsuba" executable',
'default': efutil.find_config_value('mitsuba', 'defaults', 'binary_path', '')
},
{
'type': 'int',
'attr': 'refresh_interval',
'name': 'Refresh interval',
'description': 'Period for updating rendering on screen (seconds)',
'default': 10,
'min': 1,
'soft_min': 1,
'save_in_preset': True
},
]

View File

@ -0,0 +1,6 @@
This directory contains a very basic plugin for Mitsuba <-> Blender
integration. It is based on the excellent LuxBlend 2.5 code.
MtsBlend piggybacks on Blender's internal COLLADA exporter to get
the scene information into Mitsuba. Whatever gets "lost in translation"
is added back in using Mitsuba's adjustment mechanism.

View File

@ -17,13 +17,6 @@
# ##### END GPL LICENSE BLOCK #####
import bpy
import subprocess
import os
import sys
import math
import copy
import shutil
import time
class MitsubaCheckOp(bpy.types.Operator):
bl_idname = 'mts.check'

View File

View File

@ -0,0 +1,58 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
from properties_render import RenderButtonsPanel
from extensions_framework.ui import property_group_renderer
class render_described_context(RenderButtonsPanel, property_group_renderer):
'''
Base class for render engine settings panels
'''
COMPAT_ENGINES = {'mitsuba'}
class setup_preset(render_described_context, bpy.types.Panel):
'''
Engine settings presets UI Panel
'''
bl_label = 'Mitsuba Engine Presets'
def draw(self, context):
row = self.layout.row(align=True)
row.menu("MITSUBA_MT_presets_engine", text=bpy.types.MITSUBA_MT_presets_engine.bl_label)
row.operator("mitsuba.preset_engine_add", text="", icon="ZOOMIN")
row.operator("mitsuba.preset_engine_add", text="", icon="ZOOMOUT").remove_active = True
super().draw(context)
class engine(render_described_context, bpy.types.Panel):
'''
Engine settings UI Panel
'''
bl_label = 'Mitsuba Engine Configuration'
display_property_groups = [
( ('scene',), 'mitsuba_engine' )
]

View File

@ -1,109 +0,0 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
# Use some of the existing buttons.
import properties_render
properties_render.RENDER_PT_render.COMPAT_ENGINES.add('MITSUBA_RENDER')
properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('MITSUBA_RENDER')
properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('MITSUBA_RENDER')
properties_render.RENDER_PT_output.COMPAT_ENGINES.add('MITSUBA_RENDER')
del properties_render
# Use only a subset of the world panels
import properties_world
properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('MITSUBA_RENDER')
properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('MITSUBA_RENDER')
properties_world.WORLD_PT_world.COMPAT_ENGINES.add('MITSUBA_RENDER')
properties_world.WORLD_PT_mist.COMPAT_ENGINES.add('MITSUBA_RENDER')
del properties_world
# Example of wrapping every class 'as is'
import properties_material
for member in dir(properties_material):
subclass = getattr(properties_material, member)
try:
subclass.COMPAT_ENGINES.add('MITSUBA_RENDER')
except:
pass
del properties_material
import properties_data_mesh
for member in dir(properties_data_mesh):
subclass = getattr(properties_data_mesh, member)
try:
subclass.COMPAT_ENGINES.add('MITSUBA_RENDER')
except:
pass
del properties_data_mesh
import properties_texture
for member in dir(properties_texture):
subclass = getattr(properties_texture, member)
try:
subclass.COMPAT_ENGINES.add('MITSUBA_RENDER')
except:
pass
del properties_texture
import properties_data_camera
for member in dir(properties_data_camera):
subclass = getattr(properties_data_camera, member)
try:
subclass.COMPAT_ENGINES.add('MITSUBA_RENDER')
except:
pass
del properties_data_camera
import properties_data_lamp
for member in dir(properties_data_lamp):
subclass = getattr(properties_data_lamp, member)
try:
subclass.COMPAT_ENGINES.add('MITSUBA_RENDER')
except:
pass
del properties_data_lamp
class RenderButtonsPanel():
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "render"
@classmethod
def poll(cls, context):
rd = context.scene.render
return (rd.use_game_engine == False) and (rd.engine in cls.COMPAT_ENGINES)
class RENDER_PT_mitsuba_radiosity(RenderButtonsPanel, bpy.types.Panel):
bl_label = "Mitsuba setup"
COMPAT_ENGINES = {'MITSUBA_RENDER'}
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render
split = layout.split()
col = split.column();
col.prop(scene, "mts_path", text="Executable")
row = col.row();
row.prop(scene, "mts_gui", text="In external GUI")
row.operator("wm.save_homefile", text="Save", icon ='FILE_TICK')
col.operator("mts.check", text="Check scene")