material preview support
parent
40114792c9
commit
ada5d996a3
|
@ -49,6 +49,7 @@ protected:
|
||||||
Float m_gamma, m_exposure;
|
Float m_gamma, m_exposure;
|
||||||
std::string m_toneMappingMethod;
|
std::string m_toneMappingMethod;
|
||||||
Float m_reinhardKey, m_reinhardBurn;
|
Float m_reinhardKey, m_reinhardBurn;
|
||||||
|
int m_compressionRate;
|
||||||
public:
|
public:
|
||||||
PNGFilm(const Properties &props) : Film(props) {
|
PNGFilm(const Properties &props) : Film(props) {
|
||||||
m_pixels = new Pixel[m_cropSize.x * m_cropSize.y];
|
m_pixels = new Pixel[m_cropSize.x * m_cropSize.y];
|
||||||
|
@ -68,6 +69,8 @@ public:
|
||||||
m_reinhardBurn = props.getFloat("reinhardBurn", 0.0f);
|
m_reinhardBurn = props.getFloat("reinhardBurn", 0.0f);
|
||||||
/* Reinhard "key" parameter */
|
/* Reinhard "key" parameter */
|
||||||
m_reinhardKey = props.getFloat("reinhardKey", 0.18f);
|
m_reinhardKey = props.getFloat("reinhardKey", 0.18f);
|
||||||
|
/* Compression rate (1=low, 9=high) */
|
||||||
|
m_compressionRate = props.getInteger("compressionRate", 1);
|
||||||
|
|
||||||
if (m_toneMappingMethod != "gamma" && m_toneMappingMethod != "reinhard")
|
if (m_toneMappingMethod != "gamma" && m_toneMappingMethod != "reinhard")
|
||||||
Log(EError, "Unknown tone mapping method specified (must be 'gamma' or 'reinhard')");
|
Log(EError, "Unknown tone mapping method specified (must be 'gamma' or 'reinhard')");
|
||||||
|
@ -95,6 +98,7 @@ public:
|
||||||
m_reinhardKey = stream->readFloat();
|
m_reinhardKey = stream->readFloat();
|
||||||
m_reinhardBurn = stream->readFloat();
|
m_reinhardBurn = stream->readFloat();
|
||||||
m_exposure = stream->readFloat();
|
m_exposure = stream->readFloat();
|
||||||
|
m_compressionRate = stream->readInt();
|
||||||
m_gamma = 1.0f / m_gamma;
|
m_gamma = 1.0f / m_gamma;
|
||||||
m_pixels = new Pixel[m_cropSize.x * m_cropSize.y];
|
m_pixels = new Pixel[m_cropSize.x * m_cropSize.y];
|
||||||
}
|
}
|
||||||
|
@ -109,6 +113,7 @@ public:
|
||||||
stream->writeFloat(m_reinhardKey);
|
stream->writeFloat(m_reinhardKey);
|
||||||
stream->writeFloat(m_reinhardBurn);
|
stream->writeFloat(m_reinhardBurn);
|
||||||
stream->writeFloat(m_exposure);
|
stream->writeFloat(m_exposure);
|
||||||
|
stream->writeInt(m_compressionRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~PNGFilm() {
|
virtual ~PNGFilm() {
|
||||||
|
@ -403,7 +408,7 @@ public:
|
||||||
Log(EInfo, "Writing image to \"%s\" ..", filename.leaf().c_str());
|
Log(EInfo, "Writing image to \"%s\" ..", filename.leaf().c_str());
|
||||||
ref<FileStream> stream = new FileStream(filename, FileStream::ETruncWrite);
|
ref<FileStream> stream = new FileStream(filename, FileStream::ETruncWrite);
|
||||||
bitmap->setGamma(m_gamma);
|
bitmap->setGamma(m_gamma);
|
||||||
bitmap->save(Bitmap::EPNG, stream, 1);
|
bitmap->save(Bitmap::EPNG, stream, m_compressionRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool destinationExists(const fs::path &baseName) const {
|
bool destinationExists(const fs::path &baseName) const {
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#
|
#
|
||||||
# ##### END GPL LICENSE BLOCK #####
|
# ##### END GPL LICENSE BLOCK #####
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
bl_addon_info = {
|
bl_addon_info = {
|
||||||
"name": "Mitsuba",
|
"name": "Mitsuba",
|
||||||
"author": "Wenzel Jakob",
|
"author": "Wenzel Jakob",
|
||||||
|
@ -30,6 +32,8 @@ bl_addon_info = {
|
||||||
"tracker_url": "https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba",
|
"tracker_url": "https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba",
|
||||||
"category": "Render"}
|
"category": "Render"}
|
||||||
|
|
||||||
|
def plugin_path():
|
||||||
|
return os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
from .core import RENDERENGINE_mitsuba
|
from .core import RENDERENGINE_mitsuba
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ from extensions_framework.engine import engine_base
|
||||||
from extensions_framework import util as efutil
|
from extensions_framework import util as efutil
|
||||||
|
|
||||||
# Mitsuba-related classes
|
# Mitsuba-related classes
|
||||||
|
from mitsuba import plugin_path
|
||||||
from mitsuba.properties.engine import mitsuba_engine
|
from mitsuba.properties.engine import mitsuba_engine
|
||||||
from mitsuba.properties.lamp import mitsuba_lamp
|
from mitsuba.properties.lamp import mitsuba_lamp
|
||||||
from mitsuba.properties.texture import mitsuba_texture, \
|
from mitsuba.properties.texture import mitsuba_texture, \
|
||||||
|
@ -41,6 +42,7 @@ from mitsuba.properties.material import mitsuba_material, \
|
||||||
from mitsuba.operators import MITSUBA_OT_preset_engine_add, EXPORT_OT_mitsuba
|
from mitsuba.operators import MITSUBA_OT_preset_engine_add, EXPORT_OT_mitsuba
|
||||||
from mitsuba.outputs import MtsLog, MtsFilmDisplay
|
from mitsuba.outputs import MtsLog, MtsFilmDisplay
|
||||||
from mitsuba.export.adjustments import MtsAdjustments
|
from mitsuba.export.adjustments import MtsAdjustments
|
||||||
|
from mitsuba.export import translate_id
|
||||||
from mitsuba.export.film import resolution
|
from mitsuba.export.film import resolution
|
||||||
from mitsuba.export import get_instance_materials
|
from mitsuba.export import get_instance_materials
|
||||||
from mitsuba.ui import render_panels
|
from mitsuba.ui import render_panels
|
||||||
|
@ -133,13 +135,61 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base):
|
||||||
return
|
return
|
||||||
|
|
||||||
tempdir = efutil.temp_directory()
|
tempdir = efutil.temp_directory()
|
||||||
matpreview_file = os.path.join(tempdir, "matpreview_materials.xml")
|
matfile = os.path.join(tempdir, "matpreview_materials.xml")
|
||||||
|
output_file = os.path.join(tempdir, "matpreview.png")
|
||||||
|
scene_file = os.path.join(os.path.join(plugin_path(),
|
||||||
|
"matpreview"), "matpreview.xml")
|
||||||
pm = likely_materials[0]
|
pm = likely_materials[0]
|
||||||
adj = MtsAdjustments(matpreview_file, tempdir,
|
adj = MtsAdjustments(matfile, tempdir,
|
||||||
bpy.data.materials, bpy.data.textures)
|
bpy.data.materials, bpy.data.textures)
|
||||||
adj.writeHeader()
|
adj.writeHeader()
|
||||||
adj.exportMaterial(pm)
|
adj.exportMaterial(pm)
|
||||||
adj.writeFooter()
|
adj.writeFooter()
|
||||||
|
(mts_path, tail) = os.path.split(bpy.path.abspath(scene.mitsuba_engine.binary_path))
|
||||||
|
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
|
||||||
|
(width, height) = resolution(scene)
|
||||||
|
refresh_interval = 1
|
||||||
|
mitsuba_process = subprocess.Popen(
|
||||||
|
[mitsuba_binary, '-r%i' % refresh_interval,
|
||||||
|
'-o', output_file, '-Dmatfile=%s' % matfile,
|
||||||
|
'-Dmatname=%s' % translate_id(pm.name),
|
||||||
|
'-Dwidth=%i' % width,
|
||||||
|
'-Dheight=%i' % height,
|
||||||
|
'-q',
|
||||||
|
'-o', output_file, scene_file],
|
||||||
|
env = env,
|
||||||
|
cwd = tempdir
|
||||||
|
)
|
||||||
|
framebuffer_thread = MtsFilmDisplay({
|
||||||
|
'resolution': resolution(scene),
|
||||||
|
'RE': self,
|
||||||
|
'output_file': output_file
|
||||||
|
})
|
||||||
|
framebuffer_thread.set_kick_period(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 mitsuba is still running, then send SIGINT
|
||||||
|
if mitsuba_process.poll() == None:
|
||||||
|
# Use SIGTERM because that's the only one supported on Windows
|
||||||
|
mitsuba_process.send_signal(subprocess.signal.SIGTERM)
|
||||||
|
|
||||||
|
# Stop updating the render result and load the final image
|
||||||
|
framebuffer_thread.stop()
|
||||||
|
framebuffer_thread.join()
|
||||||
|
|
||||||
|
if mitsuba_process.poll() != None and mitsuba_process.returncode != 0:
|
||||||
|
MtsLog("MtsBlend: Rendering failed -- check the console")
|
||||||
|
else:
|
||||||
|
framebuffer_thread.kick(render_end=True)
|
||||||
|
|
||||||
|
|
||||||
def render(self, scene):
|
def render(self, scene):
|
||||||
|
@ -196,17 +246,18 @@ class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base):
|
||||||
cwd = self.output_dir
|
cwd = self.output_dir
|
||||||
)
|
)
|
||||||
elif scene.mitsuba_engine.render_mode == 'cli':
|
elif scene.mitsuba_engine.render_mode == 'cli':
|
||||||
self.output_file = efutil.export_path[:-4] + ".png"
|
output_file = efutil.export_path[:-4] + ".png"
|
||||||
|
|
||||||
mitsuba_process = subprocess.Popen(
|
mitsuba_process = subprocess.Popen(
|
||||||
[mitsuba_binary, '-r', '%d' % scene.mitsuba_engine.refresh_interval,
|
[mitsuba_binary, '-r', '%d' % scene.mitsuba_engine.refresh_interval,
|
||||||
'-o', self.output_file, efutil.export_path],
|
'-o', output_file, efutil.export_path],
|
||||||
env = env,
|
env = env,
|
||||||
cwd = self.output_dir
|
cwd = self.output_dir
|
||||||
)
|
)
|
||||||
framebuffer_thread = MtsFilmDisplay({
|
framebuffer_thread = MtsFilmDisplay({
|
||||||
'resolution': resolution(scene),
|
'resolution': resolution(scene),
|
||||||
'RE': self,
|
'RE': self,
|
||||||
|
'output_file': output_file
|
||||||
})
|
})
|
||||||
framebuffer_thread.set_kick_period(scene.mitsuba_engine.refresh_interval)
|
framebuffer_thread.set_kick_period(scene.mitsuba_engine.refresh_interval)
|
||||||
framebuffer_thread.start()
|
framebuffer_thread.start()
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,80 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no" ?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Automatically converted from COLLADA
|
||||||
|
|
||||||
|
-->
|
||||||
|
<scene>
|
||||||
|
<integrator id="integrator" type="direct"/>
|
||||||
|
<include filename="$matfile"/>
|
||||||
|
|
||||||
|
<camera id="Camera-camera" type="perspective">
|
||||||
|
<float name="fov" value="28.8415"/>
|
||||||
|
<boolean name="mapSmallerSide" value="true"/>
|
||||||
|
|
||||||
|
<transform name="toWorld">
|
||||||
|
<matrix value="0.68588 -0.31737 -0.654862 3.69558 0.727634 0.312469 0.610666 -3.46243 -0.0108168 0.895343 -0.445245 3.25463 0 0 0 1"/>
|
||||||
|
</transform>
|
||||||
|
|
||||||
|
<sampler type="ldsampler">
|
||||||
|
<integer name="sampleCount" value="16"/>
|
||||||
|
</sampler>
|
||||||
|
|
||||||
|
<film id="film" type="pngfilm">
|
||||||
|
<integer name="width" value="$width"/>
|
||||||
|
<integer name="height" value="$height"/>
|
||||||
|
<boolean name="alpha" value="false"/>
|
||||||
|
<boolean name="banner" value="false"/>
|
||||||
|
<rfilter type="gaussian"/>
|
||||||
|
</film>
|
||||||
|
</camera>
|
||||||
|
|
||||||
|
<luminaire id="Area_002-light" type="envmap">
|
||||||
|
<string name="filename" value="envmap.exr"/>
|
||||||
|
<transform name="toWorld">
|
||||||
|
<matrix value="-0.224951 -0.000001 -0.974370 0.000000 -0.974370 0.000000 0.224951 0.000000 0.000000 1.000000 -0.000001 8.870000 0.000000 0.000000 0.000000 1.000000 "/>
|
||||||
|
</transform>
|
||||||
|
<float name="intensityScale" value="1.540006"/>
|
||||||
|
</luminaire>
|
||||||
|
|
||||||
|
<bsdf id="Material_001" type="lambertian">
|
||||||
|
<rgb name="reflectance" value="0.5 0.5 0.5"/>
|
||||||
|
</bsdf>
|
||||||
|
|
||||||
|
<texture id="Checkerboard_Texture" type="checkerboard">
|
||||||
|
<rgb name="darkColor" value="0.20000000298 0.20000000298 0.20000000298"/>
|
||||||
|
<rgb name="brightColor" value="0.40000000596 0.40000000596 0.40000000596"/>
|
||||||
|
<float name="uscale" value="30.0"/>
|
||||||
|
<float name="vscale" value="30.0"/>
|
||||||
|
<float name="uoffset" value="0.0"/>
|
||||||
|
<float name="voffset" value="0.0"/>
|
||||||
|
</texture><bsdf id="Plane_Material" type="lambertian">
|
||||||
|
<ref id="Checkerboard_Texture" name="reflectance"/>
|
||||||
|
</bsdf><shape id="Interior-mesh_0" type="serialized">
|
||||||
|
<string name="filename" value="matpreview.Scene.00010.serialized"/>
|
||||||
|
<integer name="shapeIndex" value="0"/>
|
||||||
|
<transform name="toWorld">
|
||||||
|
<matrix value="1 0 0 0 0 1 0 0 0 0 1 0.0252155 0 0 0 1"/>
|
||||||
|
</transform>
|
||||||
|
<ref id="Material_001" name="bsdf"/>
|
||||||
|
</shape>
|
||||||
|
|
||||||
|
<shape id="Exterior-mesh_0" type="serialized">
|
||||||
|
<string name="filename" value="matpreview.Scene.00010.serialized"/>
|
||||||
|
<integer name="shapeIndex" value="1"/>
|
||||||
|
<transform name="toWorld">
|
||||||
|
<matrix value="0.614046 0.614047 0 -1.78814e-07 -0.614047 0.614046 0 2.08616e-07 0 0 0.868393 1.02569 0 0 0 1"/>
|
||||||
|
</transform>
|
||||||
|
<ref id="$matname" name="bsdf"/>
|
||||||
|
</shape>
|
||||||
|
|
||||||
|
<shape id="Plane-mesh_0" type="serialized">
|
||||||
|
<string name="filename" value="matpreview.Scene.00010.serialized"/>
|
||||||
|
<integer name="shapeIndex" value="2"/>
|
||||||
|
<transform name="toWorld">
|
||||||
|
<matrix value="20 0 0 -10 0 20 0 10 0 0 20 0 0 0 0 1"/>
|
||||||
|
</transform>
|
||||||
|
<ref id="Plane_Material" name="bsdf"/>
|
||||||
|
</shape>
|
||||||
|
|
||||||
|
</scene>
|
|
@ -27,12 +27,12 @@ class MtsFilmDisplay(TimerThread):
|
||||||
MtsLog('Updating render result %ix%i' % (xres,yres))
|
MtsLog('Updating render result %ix%i' % (xres,yres))
|
||||||
|
|
||||||
result = self.LocalStorage['RE'].begin_result(0, 0, int(xres), int(yres))
|
result = self.LocalStorage['RE'].begin_result(0, 0, int(xres), int(yres))
|
||||||
if os.path.exists(self.LocalStorage['RE'].output_file):
|
if os.path.exists(self.LocalStorage['output_file']):
|
||||||
bpy.ops.ef.msg(msg_text='Updating RenderResult')
|
bpy.ops.ef.msg(msg_text='Updating RenderResult')
|
||||||
lay = result.layers[0]
|
lay = result.layers[0]
|
||||||
lay.load_from_file(self.LocalStorage['RE'].output_file)
|
lay.load_from_file(self.LocalStorage['output_file'])
|
||||||
else:
|
else:
|
||||||
err_msg = 'ERROR: Could not load render result from %s' % self.LocalStorage['RE'].output_file
|
err_msg = 'ERROR: Could not load render result from %s' % self.LocalStorage['output_file']
|
||||||
MtsLog(err_msg)
|
MtsLog(err_msg)
|
||||||
bpy.ops.ef.msg(msg_type='ERROR', msg_text=err_msg)
|
bpy.ops.ef.msg(msg_type='ERROR', msg_text=err_msg)
|
||||||
self.LocalStorage['RE'].end_result(result)
|
self.LocalStorage['RE'].end_result(result)
|
||||||
|
|
Loading…
Reference in New Issue