medium-related bugfixes

metadata
Wenzel Jakob 2011-03-28 22:05:55 +02:00
parent 6fe9cb7b6b
commit 5560e70033
12 changed files with 203 additions and 124 deletions

View File

@ -52,7 +52,7 @@ from ..ui.materials import (
from .. import operators
def compatible(mod):
mod = __import__('bl_ui.' + mod)
mod = getattr(bl_ui, mod)
for subclass in mod.__dict__.values():
try:
subclass.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
@ -67,12 +67,13 @@ bl_ui.properties_render.RENDER_PT_output.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNA
compatible("properties_data_mesh")
compatible("properties_data_camera")
compatible("properties_particle")
@MitsubaAddon.addon_register_class
class RENDERENGINE_mitsuba(bpy.types.RenderEngine):
bl_idname = MitsubaAddon.BL_IDNAME
bl_label = 'Mitsuba'
bl_use_preview = True
bl_use_preview = False
render_lock = threading.Lock()

View File

@ -16,7 +16,7 @@
#
# ##### END GPL LICENSE BLOCK #####
import bpy, os, copy, subprocess
import bpy, os, copy, subprocess, math, mathutils
from extensions_framework import util as efutil
from ..outputs import MtsLog
@ -246,44 +246,75 @@ class MtsExporter:
self.exported_textures = []
self.materials = materials if materials != None else bpy.data.materials
self.textures = textures if textures != None else bpy.data.textures
self.indent = 0
self.stack = []
def parameter(self, paramType, paramName, attributes = {}):
self.out.write('\t' * self.indent + '<%s name="%s"' % (paramType, paramName))
for (k, v) in attributes.items():
self.out.write(' %s=\"%s\"' % (k, v))
self.out.write('/>\n')
def element(self, name, attributes = {}):
self.out.write('\t' * self.indent + '<%s' % name)
for (k, v) in attributes.items():
self.out.write(' %s=\"%s\"' % (k, v))
self.out.write('/>\n')
def openElement(self, name, attributes = {}):
self.out.write('\t' * self.indent + '<%s' % name)
for (k, v) in attributes.items():
self.out.write(' %s=\"%s\"' % (k, v))
self.out.write('>\n')
self.indent = self.indent+1
self.stack.append(name)
def closeElement(self):
self.indent = self.indent-1
name = self.stack.pop()
self.out.write('\t' * self.indent + '</%s>\n' % name)
def exportWorldTrafo(self, trafo):
self.out.write('\t\t<transform name="toWorld">\n')
self.out.write('\t\t\t<matrix value="')
self.openElement('transform', {'name' : 'toWorld'})
value = ""
for j in range(0,4):
for i in range(0,4):
self.out.write("%f " % trafo[i][j])
self.out.write('"/>\n\t\t</transform>\n')
value += "%f " % trafo[i][j]
self.element('matrix', {'value' : value})
self.closeElement()
def exportLamp(self, lamp, idx):
ltype = lamp.data.mitsuba_lamp.type
ltype = lamp.data.type
name = translate_id(lamp.data.name)
mult = lamp.data.mitsuba_lamp.intensity
if ltype == 'POINT':
self.out.write('\t<luminaire id="%s-light" type="point">\n' % name)
mult = lamp.data.mitsuba_lamp.intensity
self.openElement('luminaire', { 'type' : 'point', 'id' : '%s-light' % name })
self.exportWorldTrafo(lamp.matrix_world)
self.out.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))
self.out.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
self.out.write('\t</luminaire>\n')
self.parameter('rgb', 'intensity', {'value' :
"%f %f %f" % (lamp.data.color.r*mult, lamp.data.color.g*mult,
lamp.data.color.b*mult)})
self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight})
self.closeElement()
elif ltype == 'AREA':
self.out.write('\t<remove id="%s-light"/>\n' % name)
self.out.write('\t<shape type="obj">\n')
size_x = lamp.data.size
size_y = lamp.data.size
self.element('remove', { 'id' : '%s-light' % name})
self.openElement('shape', { 'type' : 'obj'} )
(size_x, size_y) = (lamp.data.size, lamp.data.size)
if lamp.data.shape == 'RECTANGLE':
size_y = lamp.data.size_y
mult = mult / (2 * size_x * size_y)
filename = "area_luminaire_%d.obj" % idx
self.out.write('\t\t<string name="filename" value="meshes/%s"/>\n' % filename)
self.parameter('string', 'filename', { 'value' : 'meshes/%s' % filename})
self.exportWorldTrafo(lamp.matrix_world)
self.out.write('\n\t\t<luminaire id="%s-arealight" type="area">\n' % name)
mult = lamp.data.mitsuba_lamp.intensity / (2 * size_x * size_y)
self.out.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))
self.out.write('\t\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
self.out.write('\t\t</luminaire>\n')
self.out.write('\t</shape>\n')
self.openElement('luminaire', { 'id' : '%s-arealight' % name, 'type' : 'area'})
self.parameter('rgb', 'intensity', { 'value' : "%f %f %f"
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)})
self.closeElement()
self.openElement('bsdf', { 'type' : 'lambertian'})
self.parameter('spectrum', 'reflectance', {'value' : '0'})
self.closeElement()
self.closeElement()
path = os.path.join(self.meshes_dir, filename)
objFile = open(path, 'w')
objFile.write('v %f %f 0\n' % (-size_x/2, -size_y/2))
@ -293,47 +324,45 @@ class MtsExporter:
objFile.write('f 4 3 2 1\n')
objFile.close()
elif ltype == 'SUN':
self.out.write('\t<luminaire id="%s-light" type="directional">\n' % name)
mult = lamp.data.mitsuba_lamp.intensity
self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'directional'})
scale = mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1]))
self.exportWorldTrafo(lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])))
self.out.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))
self.out.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
self.out.write('\t</luminaire>\n')
self.parameter('rgb', 'intensity', { 'value' : "%f %f %f"
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)})
self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight})
self.closeElement()
elif ltype == 'SPOT':
self.out.write('\t<luminaire id="%s-light" type="spot">\n' % name)
mult = lamp.data.mitsuba_lamp.intensity
self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'spot'})
self.exportWorldTrafo(lamp.matrix_world * mathutils.Matrix.Scale(-1, 4, mathutils.Vector([0, 0, 1])))
self.out.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))
self.out.write('\t\t<float name="cutoffAngle" value="%f"/>\n' % (lamp.data.spot_size * 180 / (math.pi * 2)))
self.out.write('\t\t<float name="beamWidth" value="%f"/>\n' % (lamp.data.spot_blend * lamp.data.spot_size * 180 / (math.pi * 2)))
self.out.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
self.out.write('\t</luminaire>\n')
elif ltype == 'ENV':
self.parameter('rgb', 'intensity', { 'value' : "%f %f %f"
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)})
self.parameter('float', 'cutoffAngle', {'value' : '%f' % (lamp.data.spot_size * 180 / (math.pi * 2))})
self.parameter('float', 'beamWidth', {'value' : '%f' % (lamp.data.spot_blend * lamp.data.spot_size * 180 / (math.pi * 2))})
self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight})
self.closeElement()
elif ltype == 'HEMI':
if lamp.data.mitsuba_lamp.envmap_type == 'constant':
self.out.write('\t<luminaire id="%s-light" type="constant">\n' % name)
mult = lamp.data.mitsuba_lamp.intensity
self.out.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))
self.out.write('\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.data.mitsuba_lamp.samplingWeight)
self.out.write('\t</luminaire>\n')
self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'constant'})
self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight})
self.parameter('rgb', 'intensity', { 'value' : "%f %f %f"
% (lamp.data.color.r*mult, lamp.data.color.g*mult, lamp.data.color.b*mult)})
self.closeElement()
elif lamp.data.mitsuba_lamp.envmap_type == 'envmap':
self.out.write('\t<luminaire id="%s-light" type="envmap">\n' % name)
self.out.write('\t\t<string name="filename" value="%s"/>\n' % efutil.filesystem_path(lamp.data.mitsuba_lamp.envmap_file))
self.openElement('luminaire', { 'id' : '%s-light' % name, 'type' : 'envmap'})
self.parameter('string', 'filename', {'value' : efutil.filesystem_path(lamp.data.mitsuba_lamp.envmap_file)})
self.exportWorldTrafo(lamp.matrix_world)
self.out.write('\t\t<float name="intensityScale" value="%f"/>\n' % lamp.data.mitsuba_lamp.intensity)
self.out.write('\t</luminaire>\n')
self.parameter('float', 'intensityScale', {'value' : '%f' % lamp.data.mitsuba_lamp.intensity})
self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.data.mitsuba_lamp.samplingWeight})
self.closeElement()
def exportIntegrator(self, integrator):
self.out.write('\t<integrator id="integrator" type="%s">\n' % integrator.type)
self.out.write('\t</integrator>\n')
self.openElement('integrator', { 'id' : 'integrator', 'type' : integrator.type})
self.closeElement()
def exportSampler(self, sampler):
self.out.write('\t<sampler id="sampler" type="%s">\n' % sampler.type)
self.out.write('\t\t<integer name="sampleCount" value="%i"/>\n' % sampler.sampleCount)
self.out.write('\t</sampler>\n')
self.openElement('sampler', { 'id' : 'sampler', 'type' : sampler.type})
self.parameter('integer', 'sampleCount', { 'value' : '%i' % sampler.sampleCount})
self.closeElement()
def findTexture(self, name):
if name in self.textures:
@ -382,23 +411,24 @@ class MtsExporter:
self.out.write('\t</bsdf>\n')
def exportEmission(self, obj):
mult = lamp.intensity
lamp = obj.data.materials[0].mitsuba_emission
name = translate_id(obj.data.name)
self.out.write('\t<append id="%s-mesh_0">\n' % name)
self.out.write('\t\t<luminaire id="%s-emission" type="area">\n' % name)
mult = lamp.intensity
self.out.write('\t\t\t<rgb name="intensity" value="%f %f %f"/>\n'
% (lamp.color.r*mult, lamp.color.g*mult, lamp.color.b*mult))
self.out.write('\t\t\t<float name="samplingWeight" value="%f"/>\n' % lamp.samplingWeight)
self.out.write('\t\t</luminaire>\n')
self.out.write('\t</append>\n')
self.openElement('append', { 'id' : '%s-mesh_0' % name})
self.openElement('luminaire', { 'id' : '%s-emission' % name, 'type' : 'area'})
self.parameter('float', 'samplingWeight', {'value' : '%f' % lamp.samplingWeight})
self.parameter('rgb', 'intensity', { 'value' : "%f %f %f"
% (lamp.color.r*mult, lamp.color.g*mult, lamp.color.b*mult)})
self.closeElement()
self.closeElement()
def writeHeader(self):
self.out = open(self.adj_filename, 'w')
self.out.write('<scene>\n');
self.out.write('<?xml version="1.0" encoding="utf-8"?>\n');
self.openElement('scene')
def writeFooter(self):
self.out.write('</scene>\n');
self.closeElement()
self.out.close()
def exportPreviewMesh(self, material):

View File

@ -17,7 +17,7 @@
# ##### END GPL LICENSE BLOCK #####
# System Libs
import os, sys, subprocess, traceback, string
import os, sys, subprocess, traceback, string, math
# Blender Libs
import bpy, bl_operators
@ -207,3 +207,54 @@ class MITSUBA_OT_material_add(bpy.types.Operator):
obj.data.materials.append(mat)
obj.active_material_index = len(obj.data.materials)-1
return {'FINISHED'}
def material_converter(report, scene, blender_mat):
try:
mitsuba_mat = blender_mat.mitsuba_material
mitsuba_mat.type = 'microfacet'
mitsuba_mat.mitsuba_mat_microfacet.diffuseReflectance_color = [blender_mat.diffuse_intensity*i for i in blender_mat.diffuse_color]
mitsuba_mat.mitsuba_mat_microfacet.specularAmount = 1.0
mitsuba_mat.mitsuba_mat_microfacet.diffuseAmount = 1.0
logHardness = math.log(blender_mat.specular_hardness)
specular_scale = 2.0 * max(0.0128415*logHardness**2 - 0.171266*logHardness + 0.575631, 0.0)
mitsuba_mat.mitsuba_mat_microfacet.specularReflectance_color = [specular_scale * blender_mat.specular_intensity*i for i in blender_mat.specular_color]
mitsuba_mat.mitsuba_mat_microfacet.alphaB = min(max(0.757198 - 0.120395*logHardness, 0.0), 1.0)
report({'INFO'}, 'Converted blender material "%s"' % blender_mat.name)
return {'FINISHED'}
except Exception as err:
report({'ERROR'}, 'Cannot convert material: %s' % err)
return {'CANCELLED'}
@MitsubaAddon.addon_register_class
class MITSUBA_OT_convert_all_materials(bpy.types.Operator):
bl_idname = 'mitsuba.convert_all_materials'
bl_label = 'Convert all Blender materials'
def report_log(self, level, msg):
MtsLog('Material conversion %s: %s' % (level, msg))
def execute(self, context):
for blender_mat in bpy.data.materials:
# Don't convert materials from linked-in files
if blender_mat.library == None:
material_converter(self.report_log, context.scene, blender_mat)
return {'FINISHED'}
@MitsubaAddon.addon_register_class
class MITSUBA_OT_convert_material(bpy.types.Operator):
bl_idname = 'mitsuba.convert_material'
bl_label = 'Convert selected Blender material'
material_name = bpy.props.StringProperty(default='')
def execute(self, context):
if self.properties.material_name == '':
blender_mat = context.material
else:
blender_mat = bpy.data.materials[self.properties.material_name]
material_converter(self.report, context.scene, blender_mat)
return {'FINISHED'}

View File

@ -28,8 +28,7 @@ class MtsFilmDisplay(TimerThread):
result = self.LocalStorage['RE'].begin_result(0, 0, int(xres), int(yres))
if os.path.exists(self.LocalStorage['output_file']):
lay = result.layers[0]
lay.load_from_file(self.LocalStorage['output_file'])
result.layers[0].load_from_file(self.LocalStorage['output_file'])
else:
err_msg = 'ERROR: Could not load render result from %s' % self.LocalStorage['output_file']
MtsLog(err_msg)

View File

@ -36,21 +36,6 @@ class mitsuba_lamp(declarative_property_group):
}
properties = [
{
'type': 'enum',
'attr': 'type',
'name': 'Light source type',
'description': 'Specifies the behavior of the light source',
'default': 'POINT',
'items': [
('POINT', 'Point', 'Omnidirectional spot light source'),
('SUN', 'Dir', 'Constant direction parallel light source'),
('SPOT', 'Spot', 'Directional cone light source'),
('ENV', 'Env', 'Environment map light source'),
('AREA', 'Area', 'Diffuse area light source')
],
'save_in_preset': True
},
{
'type': 'float',
'attr': 'samplingWeight',

View File

@ -23,7 +23,7 @@ from .. import MitsubaAddon
from extensions_framework import declarative_property_group
from extensions_framework import util as efutil
from extensions_framework.validate import Logic_Operator
from extensions_framework.validate import Logic_Operator, Logic_OR as O
from ..properties.texture import TextureParameter
from ..export import ParamSet
@ -53,14 +53,19 @@ class mitsuba_material(declarative_property_group):
controls = [
'type',
]
'twosided'
]
visibility = {
'twosided' : { 'type' : O(['lambertian', 'phong', 'ward', 'mirror', 'roughmetal', 'microfacet', 'composite'])}
}
properties = [
# Material Type Select
{
'type': 'enum',
'attr': 'type',
'name': 'Type',
'name': 'Material Type',
'description': 'Mitsuba material type',
'default': 'lambertian',
'items': [
@ -76,6 +81,14 @@ class mitsuba_material(declarative_property_group):
('composite', 'Composite material', 'Allows creating mixtures of different materials')
],
'save_in_preset': True
},
{
'type': 'bool',
'attr': 'twosided',
'name': 'Use two-sided shading',
'description': 'Use two-sided shading for this material? This only makes sense for non-transparent/translucent materials.',
'default': False,
'save_in_preset': True
}
]

View File

@ -125,7 +125,7 @@ class TextureParameter(TextureParameterBase):
vis.update(self.get_extra_visibility())
return vis
# colour for each material type. If the property name is
# color for each material type. If the property name is
# not set, then the color won't be changed.
master_color_map = {
'lambertian': 'reflectance',

View File

@ -27,8 +27,8 @@ narrowui = 180
@MitsubaAddon.addon_register_class
class lamps(bl_ui.properties_data_lamp.DataButtonsPanel, property_group_renderer, bpy.types.Panel):
bl_label = 'Mitsuba Lamps'
COMPAT_ENGINES = {'mitsuba'}
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
display_property_groups = [
( ('lamp',), 'mitsuba_lamp' )
]
@ -41,14 +41,9 @@ class lamps(bl_ui.properties_data_lamp.DataButtonsPanel, property_group_renderer
wide_ui = context.region.width > narrowui
if wide_ui:
layout.prop(lamp.mitsuba_lamp, "type", expand=True)
layout.prop(lamp, "type", expand=True)
else:
layout.prop(lamp.mitsuba_lamp, "type", text="")
if lamp.mitsuba_lamp.type == 'ENV':
lamp.type = 'HEMI'
else:
lamp.type = lamp.mitsuba_lamp.type
layout.prop(lamp, "type", text="")
split = layout.split()

View File

@ -37,5 +37,10 @@ class main(mitsuba_material_base, bpy.types.Panel):
row.menu("MITSUBA_MT_presets_material", text=bpy.types.MITSUBA_MT_presets_material.bl_label)
row.operator("mitsuba.preset_material_add", text="", icon="ZOOMIN")
row.operator("mitsuba.preset_material_add", text="", icon="ZOOMOUT").remove_active = True
row = self.layout.row(align=True)
row.operator("mitsuba.convert_all_materials", icon='WORLD_DATA')
row = self.layout.row(align=True)
row.operator("mitsuba.convert_material", icon='MATERIAL_DATA')
super().draw(context)

View File

@ -80,6 +80,14 @@ public:
return Spectrum(0.0f);
}
/* Possibly include emitted radiance if requested */
if (its.isLuminaire() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
Li += its.Le(-ray.d);
/* Include radiance from a subsurface integrator if requested */
if (its.hasSubsurface() && (rRec.type & RadianceQueryRecord::ESubsurfaceRadiance))
Li += its.LoSub(scene, -ray.d);
const BSDF *bsdf = its.getBSDF(ray);
if (EXPECT_NOT_TAKEN(!bsdf)) {
@ -89,14 +97,6 @@ public:
return Li;
}
/* Possibly include emitted radiance if requested */
if (its.isLuminaire() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
Li += its.Le(-ray.d);
/* Include radiance from a subsurface integrator if requested */
if (its.hasSubsurface() && (rRec.type & RadianceQueryRecord::ESubsurfaceRadiance))
Li += its.LoSub(scene, -ray.d);
/* Leave here if direct illumination was not requested */
if (!(rRec.type & RadianceQueryRecord::EDirectSurfaceRadiance))
return Li;

View File

@ -179,16 +179,6 @@ public:
break;
}
const BSDF *bsdf = its.getBSDF(ray);
if (!bsdf) {
/* Pass right through the surface (there is no BSDF) */
if (its.isMediumTransition())
rRec.medium = its.getTargetMedium(ray.d);
ray.setOrigin(its.p);
scene->rayIntersect(ray, its);
continue;
}
/* Possibly include emitted radiance if requested */
if (its.isLuminaire() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
Li += pathThroughput * its.Le(-ray.d);
@ -200,6 +190,16 @@ public:
if (rRec.depth == m_maxDepth && m_maxDepth > 0)
break;
const BSDF *bsdf = its.getBSDF(ray);
if (!bsdf) {
/* Pass right through the surface (there is no BSDF) */
if (its.isMediumTransition())
rRec.medium = its.getTargetMedium(ray.d);
ray.setOrigin(its.p);
scene->rayIntersect(ray, its);
continue;
}
/* ==================================================================== */
/* Luminaire sampling */
/* ==================================================================== */

View File

@ -134,6 +134,14 @@ public:
computeIntersection = true;
/* Possibly include emitted radiance if requested */
if (its.isLuminaire() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
Li += pathThroughput * its.Le(-ray.d);
/* Include radiance from a subsurface integrator if requested */
if (its.hasSubsurface() && (rRec.type & RadianceQueryRecord::ESubsurfaceRadiance))
Li += pathThroughput * its.LoSub(rRec.scene, -ray.d);
const BSDF *bsdf = its.getBSDF(ray);
if (!bsdf) {
@ -144,14 +152,6 @@ public:
continue;
}
/* Possibly include emitted radiance if requested */
if (its.isLuminaire() && (rRec.type & RadianceQueryRecord::EEmittedRadiance))
Li += pathThroughput * its.Le(-ray.d);
/* Include radiance from a subsurface integrator if requested */
if (its.hasSubsurface() && (rRec.type & RadianceQueryRecord::ESubsurfaceRadiance))
Li += pathThroughput * its.LoSub(rRec.scene, -ray.d);
/* ==================================================================== */
/* Luminaire sampling */
/* ==================================================================== */