rotation gizmo, work on the blender plugin

metadata
Wenzel Jakob 2011-03-26 01:39:38 +01:00
parent 4bf6f3728c
commit 1df8255a30
53 changed files with 1128 additions and 442 deletions

View File

@ -18,27 +18,33 @@
import os import os
bl_addon_info = { bl_info = {
"name": "Mitsuba", "name": "Mitsuba",
"author": "Wenzel Jakob", "author": "Wenzel Jakob",
"version": (0, 1), "version": (0, 2, 1),
"blender": (2, 5, 5), "blender": (2, 5, 6),
"api": 31667, "api": 35669,
"category": "Render",
"location": "Render > Engine > Mitsuba", "location": "Render > Engine > Mitsuba",
"description": "Basic Mitsuba integration for Blender", "description": "Basic Mitsuba integration for Blender",
"warning": "", "warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
"Scripts/Render/Mitsuba", "Scripts/Render/Mitsuba",
"tracker_url": "https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba", "tracker_url": "https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba"}
"category": "Render"}
def plugin_path(): def plugin_path():
return os.path.dirname(os.path.realpath(__file__)) return os.path.dirname(os.path.realpath(__file__))
from .core import RENDERENGINE_mitsuba if 'core' in locals():
import imp
imp.reload(core)
else:
import bpy
def register(): from extensions_framework import Addon
RENDERENGINE_mitsuba.install() MitsubaAddon = Addon(bl_info)
register, unregister = MitsubaAddon.init_functions()
def unregister(): # Importing the core package causes extensions_framework managed
RENDERENGINE_mitsuba.uninstall() # RNA class registration via @MitsubaAddon.addon_register_class
from . import core

View File

@ -20,93 +20,61 @@
import os, time, threading, subprocess, sys, copy import os, time, threading, subprocess, sys, copy
# Blender libs # Blender libs
import bpy import bpy, bl_ui
# Framework libs # Framework libs
from extensions_framework.engine import engine_base
from extensions_framework import util as efutil from extensions_framework import util as efutil
# Mitsuba-related classes from .. import MitsubaAddon, plugin_path
from mitsuba import plugin_path
from mitsuba.properties.engine import mitsuba_engine from ..outputs import MtsLog, MtsFilmDisplay
from mitsuba.properties.sampler import mitsuba_sampler from ..export.adjustments import MtsAdjustments
from mitsuba.properties.integrator import mitsuba_integrator from ..export.film import resolution
from mitsuba.properties.lamp import mitsuba_lamp from ..export import get_instance_materials, translate_id
from mitsuba.properties.texture import mitsuba_texture, \
mitsuba_tex_ldrtexture, mitsuba_tex_checkerboard, \ from ..properties import (
mitsuba_tex_gridtexture, mitsuba_tex_mapping engine, sampler, integrator, lamp, texture, material
from mitsuba.properties.material import mitsuba_material, \ );
mitsuba_mat_lambertian, mitsuba_mat_phong, mitsuba_mat_ward, \
mitsuba_mat_microfacet, mitsuba_mat_roughglass, \ from ..ui import (
mitsuba_mat_roughmetal, mitsuba_mat_dielectric, \ render_panels, lamps, materials
mitsuba_mat_mirror, mitsuba_mat_difftrans, \ )
mitsuba_mat_composite, mitsuba_emission
from mitsuba.operators import MITSUBA_OT_preset_engine_add, EXPORT_OT_mitsuba from ..ui.textures import (
from mitsuba.outputs import MtsLog, MtsFilmDisplay main, ldrtexture, checkerboard, gridtexture, mapping
from mitsuba.export.adjustments import MtsAdjustments )
from mitsuba.export import translate_id
from mitsuba.export.film import resolution from ..ui.materials import (
from mitsuba.export import get_instance_materials main, lambertian, phong, ward, microfacet, roughglass,
from mitsuba.ui import render_panels, lamps roughmetal, dielectric, mirror, difftrans, composite,
from mitsuba.ui.textures import TEXTURE_PT_context_texture_mts emission
from mitsuba.ui.textures import main, ldrtexture, checkerboard, \ )
gridtexture, mapping
from mitsuba.ui.materials import MATERIAL_PT_context_material_mts from .. import operators
from mitsuba.ui.materials import main, lambertian, phong, ward, \
microfacet, roughglass, roughmetal, dielectric, \
mirror, difftrans, composite, emission
def compatible(mod): def compatible(mod):
mod = __import__(mod) mod = __import__('bl_ui.' + mod)
for subclass in mod.__dict__.values(): for subclass in mod.__dict__.values():
try: try:
subclass.COMPAT_ENGINES.add('mitsuba') subclass.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
except: except:
pass pass
del mod del mod
import properties_data_lamp bl_ui.properties_data_lamp.DATA_PT_context_lamp.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
properties_data_lamp.DATA_PT_context_lamp.COMPAT_ENGINES.add('mitsuba') bl_ui.properties_render.RENDER_PT_render.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
del properties_data_lamp bl_ui.properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
bl_ui.properties_render.RENDER_PT_output.COMPAT_ENGINES.add(MitsubaAddon.BL_IDNAME)
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_mesh")
compatible("properties_data_camera") compatible("properties_data_camera")
class RENDERENGINE_mitsuba(bpy.types.RenderEngine, engine_base): @MitsubaAddon.addon_register_class
bl_idname = 'mitsuba' class RENDERENGINE_mitsuba(bpy.types.RenderEngine):
bl_idname = MitsubaAddon.BL_IDNAME
bl_label = 'Mitsuba' bl_label = 'Mitsuba'
bl_use_preview = True bl_use_preview = True
property_groups = [
('Scene', mitsuba_engine),
('Scene', mitsuba_integrator),
('Scene', mitsuba_sampler),
('Lamp', mitsuba_lamp),
('Texture', mitsuba_texture),
('mitsuba_texture', mitsuba_tex_ldrtexture),
('mitsuba_texture', mitsuba_tex_checkerboard),
('mitsuba_texture', mitsuba_tex_gridtexture),
('mitsuba_texture', mitsuba_tex_mapping),
('Material', mitsuba_material),
('Material', mitsuba_emission),
('mitsuba_material', mitsuba_mat_lambertian),
('mitsuba_material', mitsuba_mat_phong),
('mitsuba_material', mitsuba_mat_ward),
('mitsuba_material', mitsuba_mat_microfacet),
('mitsuba_material', mitsuba_mat_roughglass),
('mitsuba_material', mitsuba_mat_roughmetal),
('mitsuba_material', mitsuba_mat_dielectric),
('mitsuba_material', mitsuba_mat_difftrans),
('mitsuba_material', mitsuba_mat_mirror),
('mitsuba_material', mitsuba_mat_composite)
]
render_lock = threading.Lock() render_lock = threading.Lock()
def process_wait_timer(self): def process_wait_timer(self):

View File

@ -20,51 +20,46 @@
import os, sys, copy, subprocess, traceback, string import os, sys, copy, subprocess, traceback, string
# Blender Libs # Blender Libs
import bpy import bpy, bl_operators
from presets import AddPresetBase
# Extensions_Framework Libs # Extensions_Framework Libs
from extensions_framework import util as efutil from extensions_framework import util as efutil
from mitsuba.outputs import MtsLog from .. import MitsubaAddon
from mitsuba.export.adjustments import MtsAdjustments from ..outputs import MtsLog
from ..export.adjustments import MtsAdjustments
def try_preset_path_create(preset_subdir): class MITSUBA_MT_base(bpy.types.Menu):
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" preset_operator = "script.execute_preset"
def draw(self, context): def draw(self, context):
try_preset_path_create(self.preset_subdir) return self.draw_preset(context)
return bpy.types.Menu.draw_preset(self, context)
class MITSUBA_OT_preset_base(AddPresetBase): @MitsubaAddon.addon_register_class
def execute(self, context): class MITSUBA_MT_presets_engine(MITSUBA_MT_base):
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" bl_label = "Mitsuba Engine Presets"
preset_subdir = "mitsuba/engine" preset_subdir = "mitsuba/engine"
class MITSUBA_OT_preset_engine_add(MITSUBA_OT_preset_base, bpy.types.Operator): @MitsubaAddon.addon_register_class
class MITSUBA_OT_preset_engine_add(bl_operators.presets.AddPresetBase, bpy.types.Operator):
'''Save the current settings as a preset''' '''Save the current settings as a preset'''
bl_idname = 'mitsuba.preset_engine_add' bl_idname = 'mitsuba.preset_engine_add'
bl_label = 'Add Mitsuba Engine settings preset' bl_label = 'Add Mitsuba Engine settings preset'
preset_menu = 'MITSUBA_MT_presets_engine' 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' preset_subdir = 'mitsuba/engine'
def execute(self, context):
self.preset_values = [
'bpy.context.scene.mitsuba_engine.%s'%v['attr'] for v in bpy.types.mitsuba_engine.get_exportable_properties()
]
return super().execute(context)
class MITSUBA_MT_presets_texture(MITSUBA_MT_base, bpy.types.Menu): @MitsubaAddon.addon_register_class
class MITSUBA_MT_presets_texture(MITSUBA_MT_base):
bl_label = "Mitsuba Texture Presets" bl_label = "Mitsuba Texture Presets"
preset_subdir = "mitsuba/texture" preset_subdir = "mitsuba/texture"
class MITSUBA_OT_preset_texture_add(MITSUBA_OT_preset_base, bpy.types.Operator): @MitsubaAddon.addon_register_class
class MITSUBA_OT_preset_texture_add(bl_operators.presets.AddPresetBase, bpy.types.Operator):
'''Save the current settings as a preset''' '''Save the current settings as a preset'''
bl_idname = 'mitsuba.preset_texture_add' bl_idname = 'mitsuba.preset_texture_add'
bl_label = 'Add Mitsuba Texture settings preset' bl_label = 'Add Mitsuba Texture settings preset'
@ -89,12 +84,13 @@ class MITSUBA_OT_preset_texture_add(MITSUBA_OT_preset_base, bpy.types.Operator):
self.preset_values = pv self.preset_values = pv
return super().execute(context) return super().execute(context)
@MitsubaAddon.addon_register_class
class MITSUBA_MT_presets_material(MITSUBA_MT_base, bpy.types.Menu): class MITSUBA_MT_presets_material(MITSUBA_MT_base):
bl_label = "Mitsuba Material Presets" bl_label = "Mitsuba Material Presets"
preset_subdir = "mitsuba/material" preset_subdir = "mitsuba/material"
class MITSUBA_OT_preset_material_add(MITSUBA_OT_preset_base, bpy.types.Operator): @MitsubaAddon.addon_register_class
class MITSUBA_OT_preset_material_add(bl_operators.presets.AddPresetBase, bpy.types.Operator):
'''Save the current settings as a preset''' '''Save the current settings as a preset'''
bl_idname = 'mitsuba.preset_material_add' bl_idname = 'mitsuba.preset_material_add'
bl_label = 'Add Mitsuba Material settings preset' bl_label = 'Add Mitsuba Material settings preset'
@ -121,6 +117,7 @@ class MITSUBA_OT_preset_material_add(MITSUBA_OT_preset_base, bpy.types.Operator)
self.preset_values = pv self.preset_values = pv
return super().execute(context) return super().execute(context)
@MitsubaAddon.addon_register_class
class EXPORT_OT_mitsuba(bpy.types.Operator): class EXPORT_OT_mitsuba(bpy.types.Operator):
bl_idname = 'export.mitsuba' bl_idname = 'export.mitsuba'
bl_label = 'Export Mitsuba Scene (.xml)' bl_label = 'Export Mitsuba Scene (.xml)'
@ -215,6 +212,7 @@ def menu_func(self, context):
bpy.types.INFO_MT_file_export.append(menu_func) bpy.types.INFO_MT_file_export.append(menu_func)
@MitsubaAddon.addon_register_class
class MITSUBA_OT_material_slot_move(bpy.types.Operator): class MITSUBA_OT_material_slot_move(bpy.types.Operator):
''' Rearrange the material slots ''' ''' Rearrange the material slots '''
bl_idname = 'mitsuba.material_slot_move' bl_idname = 'mitsuba.material_slot_move'
@ -245,6 +243,7 @@ class MITSUBA_OT_material_slot_move(bpy.types.Operator):
obj.active_material_index = new_index obj.active_material_index = new_index
return {'FINISHED'} return {'FINISHED'}
@MitsubaAddon.addon_register_class
class MITSUBA_OT_material_add(bpy.types.Operator): class MITSUBA_OT_material_add(bpy.types.Operator):
''' Append a new material ''' ''' Append a new material '''
bl_idname = 'mitsuba.material_add' bl_idname = 'mitsuba.material_add'

View File

@ -16,15 +16,14 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
from .. import MitsubaAddon
from extensions_framework import declarative_property_group from extensions_framework import declarative_property_group
from extensions_framework import util as efutil from extensions_framework import util as efutil
@MitsubaAddon.addon_register_class
class mitsuba_engine(declarative_property_group): class mitsuba_engine(declarative_property_group):
''' ef_attach_to = ['Scene']
Storage class for Mitsuba Engine settings.
This class will be instantiated within a Blender scene
object.
'''
controls = [ controls = [
'export_mode', 'export_mode',

View File

@ -16,9 +16,11 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
from .. import MitsubaAddon
from extensions_framework import declarative_property_group from extensions_framework import declarative_property_group
from extensions_framework import util as efutil from extensions_framework import util as efutil
@MitsubaAddon.addon_register_class
class mitsuba_integrator(declarative_property_group): class mitsuba_integrator(declarative_property_group):
''' '''
Storage class for Mitsuba Integrator settings. Storage class for Mitsuba Integrator settings.
@ -26,6 +28,8 @@ class mitsuba_integrator(declarative_property_group):
object. object.
''' '''
ef_attach_to = ['Scene']
controls = [ controls = [
'type', 'type',
['motionblur', ['motionblur',
@ -42,7 +46,7 @@ class mitsuba_integrator(declarative_property_group):
'attr': 'type', 'attr': 'type',
'name': 'Type', 'name': 'Type',
'description': 'Specifies the type of integrator to use', 'description': 'Specifies the type of integrator to use',
'default': 'ldintegrator', 'default': 'direct',
'items': [ 'items': [
('direct', 'Direct Illumination', 'direct'), ('direct', 'Direct Illumination', 'direct'),
('path', 'Path tracer', 'path'), ('path', 'Path tracer', 'path'),

View File

@ -16,9 +16,14 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
from .. import MitsubaAddon
from extensions_framework import declarative_property_group from extensions_framework import declarative_property_group
@MitsubaAddon.addon_register_class
class mitsuba_lamp(declarative_property_group): class mitsuba_lamp(declarative_property_group):
ef_attach_to = ['Lamp']
controls = [ controls = [
'samplingWeight', 'samplingWeight',
'envmap_type', 'envmap_type',

View File

@ -1,13 +1,31 @@
import math # ##### 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, math
from copy import deepcopy from copy import deepcopy
import bpy from .. import MitsubaAddon
from extensions_framework import declarative_property_group from extensions_framework import declarative_property_group
from extensions_framework import util as efutil from extensions_framework import util as efutil
from extensions_framework.validate import Logic_Operator from extensions_framework.validate import Logic_Operator
from mitsuba.properties.texture import TextureParameter from ..properties.texture import TextureParameter
from mitsuba.export import ParamSet from ..export import ParamSet
param_reflectance = TextureParameter('reflectance', 'Reflectance', \ param_reflectance = TextureParameter('reflectance', 'Reflectance', \
'Diffuse reflectance value', default=(0.5, 0.5, 0.5)) 'Diffuse reflectance value', default=(0.5, 0.5, 0.5))
@ -23,6 +41,7 @@ def dict_merge(*args):
return vis return vis
@MitsubaAddon.addon_register_class
class mitsuba_material(declarative_property_group): class mitsuba_material(declarative_property_group):
''' '''
Storage class for Mitsuba Material settings. Storage class for Mitsuba Material settings.
@ -30,6 +49,8 @@ class mitsuba_material(declarative_property_group):
object. object.
''' '''
ef_attach_to = ['Material']
controls = [ controls = [
'type', 'type',
] ]
@ -41,7 +62,7 @@ class mitsuba_material(declarative_property_group):
'attr': 'type', 'attr': 'type',
'name': 'Type', 'name': 'Type',
'description': 'Mitsuba material type', 'description': 'Mitsuba material type',
'default': 'matte', 'default': 'lambertian',
'items': [ 'items': [
('lambertian', 'Lambertian', 'Lambertian (i.e. ideally diffuse) material'), ('lambertian', 'Lambertian', 'Lambertian (i.e. ideally diffuse) material'),
('phong', 'Phong', 'Modified Phong BRDF'), ('phong', 'Phong', 'Modified Phong BRDF'),
@ -62,6 +83,7 @@ class mitsuba_material(declarative_property_group):
sub_type = getattr(self, 'mitsuba_mat_%s' % self.type) sub_type = getattr(self, 'mitsuba_mat_%s' % self.type)
return sub_type.get_params() return sub_type.get_params()
@MitsubaAddon.addon_register_class
class mitsuba_emission(declarative_property_group): class mitsuba_emission(declarative_property_group):
''' '''
Storage class for Mitsuba Material emission settings. Storage class for Mitsuba Material emission settings.
@ -69,6 +91,8 @@ class mitsuba_emission(declarative_property_group):
object. object.
''' '''
ef_attach_to = ['Material']
controls = [ controls = [
'color', 'color',
'intensity', 'intensity',
@ -136,7 +160,9 @@ class mitsuba_emission(declarative_property_group):
params.add_float('samplingWeight', self.samplingWeight) params.add_float('samplingWeight', self.samplingWeight)
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_mat_lambertian(declarative_property_group): class mitsuba_mat_lambertian(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = param_reflectance.controls controls = param_reflectance.controls
properties = param_reflectance.properties properties = param_reflectance.properties
@ -148,7 +174,9 @@ class mitsuba_mat_lambertian(declarative_property_group):
params.update(param_reflectance.get_params(self)) params.update(param_reflectance.get_params(self))
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_mat_phong(declarative_property_group): class mitsuba_mat_phong(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = [ controls = [
'diffuseAmount', 'diffuseAmount',
'specularAmount', 'specularAmount',
@ -204,7 +232,9 @@ class mitsuba_mat_phong(declarative_property_group):
params.add_float('exponent', self.exponent) params.add_float('exponent', self.exponent)
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_mat_ward(declarative_property_group): class mitsuba_mat_ward(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = [ controls = [
'diffuseAmount', 'diffuseAmount',
'specularAmount', 'specularAmount',
@ -271,7 +301,9 @@ class mitsuba_mat_ward(declarative_property_group):
params.add_float('alphaY', self.alphaY) params.add_float('alphaY', self.alphaY)
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_mat_microfacet(declarative_property_group): class mitsuba_mat_microfacet(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = [ controls = [
'diffuseAmount', 'diffuseAmount',
'specularAmount', 'specularAmount',
@ -350,7 +382,9 @@ class mitsuba_mat_microfacet(declarative_property_group):
params.add_float('intIOR', self.intIOR) params.add_float('intIOR', self.intIOR)
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_mat_roughglass(declarative_property_group): class mitsuba_mat_roughglass(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = [ controls = [
'specularReflectance', 'specularReflectance',
'specularTransmittance', 'specularTransmittance',
@ -422,7 +456,9 @@ class mitsuba_mat_roughglass(declarative_property_group):
params.add_float('intIOR', self.intIOR) params.add_float('intIOR', self.intIOR)
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_mat_roughmetal(declarative_property_group): class mitsuba_mat_roughmetal(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = [ controls = [
'alphaB', 'alphaB',
'ior', 'k' 'ior', 'k'
@ -473,7 +509,9 @@ class mitsuba_mat_roughmetal(declarative_property_group):
params.add_color('k', self.k) params.add_color('k', self.k)
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_mat_dielectric(declarative_property_group): class mitsuba_mat_dielectric(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = [ controls = [
'specularReflectance', 'specularReflectance',
'specularTransmittance', 'specularTransmittance',
@ -533,7 +571,9 @@ class mitsuba_mat_dielectric(declarative_property_group):
params.add_float('intIOR', self.intIOR) params.add_float('intIOR', self.intIOR)
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_mat_mirror(declarative_property_group): class mitsuba_mat_mirror(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = [ controls = [
'specularReflectance' 'specularReflectance'
] ]
@ -557,7 +597,9 @@ class mitsuba_mat_mirror(declarative_property_group):
params.add_color('specularReflectance', self.specularReflectance) params.add_color('specularReflectance', self.specularReflectance)
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_mat_difftrans(declarative_property_group): class mitsuba_mat_difftrans(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = [ controls = [
'transmittance' 'transmittance'
] ]
@ -631,7 +673,9 @@ def mitsuba_mat_composite_visibility():
result["mat%i_weight" % i] = {'nElements' : Logic_Operator({'gte' : i})} result["mat%i_weight" % i] = {'nElements' : Logic_Operator({'gte' : i})}
return result return result
@MitsubaAddon.addon_register_class
class mitsuba_mat_composite(declarative_property_group): class mitsuba_mat_composite(declarative_property_group):
ef_attach_to = ['mitsuba_material']
controls = [ controls = [
'nElements' 'nElements'
] + sum(map(lambda x: x.get_controls(), param_mat), []) ] + sum(map(lambda x: x.get_controls(), param_mat), [])

View File

@ -16,9 +16,12 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
from .. import MitsubaAddon
from extensions_framework import declarative_property_group from extensions_framework import declarative_property_group
from extensions_framework import util as efutil from extensions_framework import util as efutil
@MitsubaAddon.addon_register_class
class mitsuba_sampler(declarative_property_group): class mitsuba_sampler(declarative_property_group):
''' '''
Storage class for Mitsuba Sampler settings. Storage class for Mitsuba Sampler settings.
@ -26,6 +29,8 @@ class mitsuba_sampler(declarative_property_group):
object. object.
''' '''
ef_attach_to = ['Scene']
controls = [ controls = [
'type', 'type',
'sampleCount' 'sampleCount'

View File

@ -16,6 +16,8 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
from .. import MitsubaAddon
from extensions_framework import declarative_property_group from extensions_framework import declarative_property_group
from extensions_framework import util as efutil from extensions_framework import util as efutil
from extensions_framework.validate import Logic_OR as O from extensions_framework.validate import Logic_OR as O
@ -214,6 +216,7 @@ class TextureParameter(TextureParameterBase):
) )
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_texture(declarative_property_group): class mitsuba_texture(declarative_property_group):
''' '''
Storage class for Mitsuba Texture settings. Storage class for Mitsuba Texture settings.
@ -221,6 +224,8 @@ class mitsuba_texture(declarative_property_group):
object. object.
''' '''
ef_attach_to = ['Texture']
controls = [ controls = [
'type' 'type'
] ]
@ -249,7 +254,10 @@ class mitsuba_texture(declarative_property_group):
else: else:
return ParamSet() return ParamSet()
@MitsubaAddon.addon_register_class
class mitsuba_tex_mapping(declarative_property_group): class mitsuba_tex_mapping(declarative_property_group):
ef_attach_to = ['mitsuba_texture']
controls = [ controls = [
['uscale', 'vscale'], ['uscale', 'vscale'],
['uoffset', 'voffset'] ['uoffset', 'voffset']
@ -310,7 +318,10 @@ class mitsuba_tex_mapping(declarative_property_group):
mapping_params.add_float('voffset', self.voffset) mapping_params.add_float('voffset', self.voffset)
return mapping_params return mapping_params
@MitsubaAddon.addon_register_class
class mitsuba_tex_ldrtexture(declarative_property_group): class mitsuba_tex_ldrtexture(declarative_property_group):
ef_attach_to = ['mitsuba_texture']
controls = [ controls = [
'filename', 'filename',
'wrapMode', 'wrapMode',
@ -399,7 +410,10 @@ class mitsuba_tex_ldrtexture(declarative_property_group):
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_tex_checkerboard(declarative_property_group): class mitsuba_tex_checkerboard(declarative_property_group):
ef_attach_to = ['mitsuba_texture']
controls = [ controls = [
'darkColor', 'darkColor',
'brightColor' 'brightColor'
@ -438,7 +452,10 @@ class mitsuba_tex_checkerboard(declarative_property_group):
return params return params
@MitsubaAddon.addon_register_class
class mitsuba_tex_gridtexture(declarative_property_group): class mitsuba_tex_gridtexture(declarative_property_group):
ef_attach_to = ['mitsuba_texture']
controls = [ controls = [
'darkColor', 'darkColor',
'brightColor', 'brightColor',

View File

@ -16,14 +16,16 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy, bl_ui
from properties_data_lamp import DataButtonsPanel
from .. import MitsubaAddon
from extensions_framework.ui import property_group_renderer from extensions_framework.ui import property_group_renderer
narrowui = 180 narrowui = 180
class lamps(DataButtonsPanel, property_group_renderer, bpy.types.Panel): @MitsubaAddon.addon_register_class
class lamps(bl_ui.properties_data_lamp.DataButtonsPanel, property_group_renderer, bpy.types.Panel):
bl_label = 'Mitsuba Lamps' bl_label = 'Mitsuba Lamps'
COMPAT_ENGINES = {'mitsuba'} COMPAT_ENGINES = {'mitsuba'}

View File

@ -16,11 +16,12 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy, bl_ui
from properties_material import MaterialButtonsPanel
from ... import MitsubaAddon
from ...outputs import MtsLog
from extensions_framework.ui import property_group_renderer from extensions_framework.ui import property_group_renderer
from mitsuba.outputs import MtsLog
from extensions_framework import util as efutil from extensions_framework import util as efutil
material_cache = {} material_cache = {}
@ -36,8 +37,8 @@ def copy(value):
else: else:
raise Exception("Copy: don't know how to handle '%s'" % str(vlaue)) raise Exception("Copy: don't know how to handle '%s'" % str(vlaue))
class mitsuba_material_base(MaterialButtonsPanel, property_group_renderer): class mitsuba_material_base(bl_ui.properties_material.MaterialButtonsPanel, property_group_renderer):
COMPAT_ENGINES = {'mitsuba'} COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
MTS_PROPS = ['type'] MTS_PROPS = ['type']
def validate(self, context): def validate(self, context):
@ -71,8 +72,8 @@ class mitsuba_material_base(MaterialButtonsPanel, property_group_renderer):
def get_contents(self, mat): def get_contents(self, mat):
return mat.mitsuba_material return mat.mitsuba_material
class mitsuba_material_sub(MaterialButtonsPanel, property_group_renderer): class mitsuba_material_sub(bl_ui.properties_material.MaterialButtonsPanel, property_group_renderer):
COMPAT_ENGINES = {'mitsuba'} COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
MTS_COMPAT = set() MTS_COMPAT = set()
MTS_PROPS = [] MTS_PROPS = []
@ -116,9 +117,10 @@ class mitsuba_material_sub(MaterialButtonsPanel, property_group_renderer):
context.material.preview_render_type = context.material.preview_render_type context.material.preview_render_type = context.material.preview_render_type
return super().draw(context) return super().draw(context)
class MATERIAL_PT_preview_mts(MaterialButtonsPanel, bpy.types.Panel): @MitsubaAddon.addon_register_class
class MATERIAL_PT_preview_mts(bl_ui.properties_material.MaterialButtonsPanel, bpy.types.Panel):
bl_label = "Preview" bl_label = "Preview"
COMPAT_ENGINES = {'mitsuba'} COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
def draw(self, context): def draw(self, context):
if not hasattr(context, 'material'): if not hasattr(context, 'material'):
@ -141,11 +143,11 @@ class MATERIAL_PT_preview_mts(MaterialButtonsPanel, bpy.types.Panel):
efutil.write_config_value('mitsuba', 'defaults', 'preview_spp', str(cached_spp)) efutil.write_config_value('mitsuba', 'defaults', 'preview_spp', str(cached_spp))
efutil.write_config_value('mitsuba', 'defaults', 'preview_depth', str(cached_depth)) efutil.write_config_value('mitsuba', 'defaults', 'preview_depth', str(cached_depth))
@MitsubaAddon.addon_register_class
class MATERIAL_PT_context_material_mts(MaterialButtonsPanel, bpy.types.Panel): class MATERIAL_PT_context_material_mts(bl_ui.properties_material.MaterialButtonsPanel, bpy.types.Panel):
bl_label = "" bl_label = ""
bl_options = {'HIDE_HEADER'} bl_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {'mitsuba'} COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):

View File

@ -17,10 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
from properties_material import active_node_mat
class ui_material_composite(mitsuba_material_sub, bpy.types.Panel): class ui_material_composite(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Composite Material' bl_label = 'Mitsuba Composite Material'
@ -33,7 +33,7 @@ class ui_material_composite(mitsuba_material_sub, bpy.types.Panel):
def draw(self, context): def draw(self, context):
super().draw(context) super().draw(context)
mat = active_node_mat(context.material).mitsuba_material.mitsuba_mat_composite mat = bl_ui.properties_material.active_node_mat(context.material).mitsuba_material.mitsuba_mat_composite
weight = 0 weight = 0
missing = False missing = False
selfRef = False selfRef = False

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
class ui_material_dielectric(mitsuba_material_sub, bpy.types.Panel): class ui_material_dielectric(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Dielectric Material' bl_label = 'Mitsuba Dielectric Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
class ui_material_difftrans(mitsuba_material_sub, bpy.types.Panel): class ui_material_difftrans(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Diffuse Transmitter Material' bl_label = 'Mitsuba Diffuse Transmitter Material'

View File

@ -16,11 +16,11 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy, bl_ui
from ... import MitsubaAddon
from mitsuba.ui.materials import mitsuba_material_base from ...ui.materials import mitsuba_material_base
from properties_material import active_node_mat
@MitsubaAddon.addon_register_class
class emission(mitsuba_material_base, bpy.types.Panel): class emission(mitsuba_material_base, bpy.types.Panel):
''' '''
Material Emission Settings Material Emission Settings
@ -39,6 +39,6 @@ class emission(mitsuba_material_base, bpy.types.Panel):
def draw_header(self, context): def draw_header(self, context):
if hasattr(context, "material"): if hasattr(context, "material"):
mat = active_node_mat(context.material) mat = bl_ui.properties_material.active_node_mat(context.material)
self.layout.prop(mat.mitsuba_emission, "use_emission", text="") self.layout.prop(mat.mitsuba_emission, "use_emission", text="")
self.validate(context) self.validate(context)

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
class ui_material_lambertian(mitsuba_material_sub, bpy.types.Panel): class ui_material_lambertian(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Lambertian Material' bl_label = 'Mitsuba Lambertian Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_base
from mitsuba.ui.materials import mitsuba_material_base @MitsubaAddon.addon_register_class
class main(mitsuba_material_base, bpy.types.Panel): class main(mitsuba_material_base, bpy.types.Panel):
''' '''
Material Editor UI Panel Material Editor UI Panel

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
class ui_material_microfacet(mitsuba_material_sub, bpy.types.Panel): class ui_material_microfacet(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Microfacet Material' bl_label = 'Mitsuba Microfacet Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
class ui_material_mirror(mitsuba_material_sub, bpy.types.Panel): class ui_material_mirror(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Mirror Material' bl_label = 'Mitsuba Mirror Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
class ui_material_phong(mitsuba_material_sub, bpy.types.Panel): class ui_material_phong(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Phong Material' bl_label = 'Mitsuba Phong Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
class ui_material_roughglass(mitsuba_material_sub, bpy.types.Panel): class ui_material_roughglass(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Rough Glass Material' bl_label = 'Mitsuba Rough Glass Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
class ui_material_roughmetal(mitsuba_material_sub, bpy.types.Panel): class ui_material_roughmetal(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Rough Metal Material' bl_label = 'Mitsuba Rough Metal Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub @MitsubaAddon.addon_register_class
class ui_material_ward(mitsuba_material_sub, bpy.types.Panel): class ui_material_ward(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Ward Material' bl_label = 'Mitsuba Ward Material'

View File

@ -16,22 +16,24 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import os, bpy import os, bpy, bl_ui
from properties_render import RenderButtonsPanel
from .. import MitsubaAddon
from extensions_framework.ui import property_group_renderer from extensions_framework.ui import property_group_renderer
from extensions_framework import util as efutil from extensions_framework import util as efutil
cached_binary_path = None cached_binary_path = None
class render_described_context(RenderButtonsPanel, property_group_renderer): class render_panel(bl_ui.properties_render.RenderButtonsPanel, property_group_renderer):
''' '''
Base class for render engine settings panels Base class for render engine settings panels
''' '''
COMPAT_ENGINES = {'mitsuba'} COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
class setup_preset(render_described_context, bpy.types.Panel): @MitsubaAddon.addon_register_class
class setup_preset(render_panel, bpy.types.Panel):
''' '''
Engine settings presets UI Panel Engine settings presets UI Panel
''' '''
@ -46,7 +48,8 @@ class setup_preset(render_described_context, bpy.types.Panel):
super().draw(context) super().draw(context)
class engine(render_described_context, bpy.types.Panel): @MitsubaAddon.addon_register_class
class engine(render_panel, bpy.types.Panel):
''' '''
Engine settings UI Panel Engine settings UI Panel
''' '''
@ -71,7 +74,8 @@ class engine(render_described_context, bpy.types.Panel):
efutil.write_config_value('mitsuba', 'defaults', 'binary_path', binary_path) efutil.write_config_value('mitsuba', 'defaults', 'binary_path', binary_path)
super().draw(context) super().draw(context)
class integrator(render_described_context, bpy.types.Panel): @MitsubaAddon.addon_register_class
class integrator(render_panel, bpy.types.Panel):
''' '''
Integrator settings UI Panel Integrator settings UI Panel
''' '''
@ -82,8 +86,8 @@ class integrator(render_described_context, bpy.types.Panel):
( ('scene',), 'mitsuba_integrator' ) ( ('scene',), 'mitsuba_integrator' )
] ]
@MitsubaAddon.addon_register_class
class sampler(render_described_context, bpy.types.Panel): class sampler(render_panel, bpy.types.Panel):
''' '''
Sampler settings UI Panel Sampler settings UI Panel
''' '''

View File

@ -16,17 +16,17 @@
# #
# ##### END GPL LICENSE BLOCK ##### # ##### END GPL LICENSE BLOCK #####
import bpy import bpy, bl_ui
from properties_texture import TextureButtonsPanel
from properties_texture import context_tex_datablock
from extensions_framework.ui import property_group_renderer from extensions_framework.ui import property_group_renderer
class TEXTURE_PT_context_texture_mts(TextureButtonsPanel, bpy.types.Panel): from ... import MitsubaAddon
@MitsubaAddon.addon_register_class
class TEXTURE_PT_context_texture_mts(bl_ui.properties_texture.TextureButtonsPanel, bpy.types.Panel):
bl_label = "" bl_label = ""
bl_options = {'HIDE_HEADER'} bl_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {'mitsuba'} COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
@ -42,7 +42,7 @@ class TEXTURE_PT_context_texture_mts(TextureButtonsPanel, bpy.types.Panel):
node = context.texture_node node = context.texture_node
space = context.space_data space = context.space_data
tex = context.texture tex = context.texture
idblock = context_tex_datablock(context) idblock = bl_ui.properties_texture.context_tex_datablock(context)
tex_collection = space.pin_id is None and type(idblock) != bpy.types.Brush and not node tex_collection = space.pin_id is None and type(idblock) != bpy.types.Brush and not node
if tex_collection: if tex_collection:
@ -70,12 +70,12 @@ class TEXTURE_PT_context_texture_mts(TextureButtonsPanel, bpy.types.Panel):
col = split.column() col = split.column()
class mitsuba_texture_base(TextureButtonsPanel, property_group_renderer): class mitsuba_texture_base(bl_ui.properties_texture.TextureButtonsPanel, property_group_renderer):
''' '''
This is the base class for all Mitsuba texture sub-panels. This is the base class for all Mitsuba texture sub-panels.
''' '''
COMPAT_ENGINES = {'mitsuba'} COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
MTS_COMPAT = set() MTS_COMPAT = set()
@classmethod @classmethod

View File

@ -18,8 +18,10 @@
import bpy import bpy
from mitsuba.ui.textures import mitsuba_texture_base from ... import MitsubaAddon
from ...ui.textures import mitsuba_texture_base
@MitsubaAddon.addon_register_class
class ui_texture_checkerboard(mitsuba_texture_base, bpy.types.Panel): class ui_texture_checkerboard(mitsuba_texture_base, bpy.types.Panel):
bl_label = 'Mitsuba Checkerboard Texture' bl_label = 'Mitsuba Checkerboard Texture'

View File

@ -18,8 +18,10 @@
import bpy import bpy
from mitsuba.ui.textures import mitsuba_texture_base from ... import MitsubaAddon
from ...ui.textures import mitsuba_texture_base
@MitsubaAddon.addon_register_class
class ui_texture_gridtexture(mitsuba_texture_base, bpy.types.Panel): class ui_texture_gridtexture(mitsuba_texture_base, bpy.types.Panel):
bl_label = 'Mitsuba Grid Texture' bl_label = 'Mitsuba Grid Texture'

View File

@ -18,8 +18,10 @@
import bpy import bpy
from mitsuba.ui.textures import mitsuba_texture_base from ... import MitsubaAddon
from ...ui.textures import mitsuba_texture_base
@MitsubaAddon.addon_register_class
class ui_texture_ldrtexture(mitsuba_texture_base, bpy.types.Panel): class ui_texture_ldrtexture(mitsuba_texture_base, bpy.types.Panel):
bl_label = 'Mitsuba Bitmap Texture' bl_label = 'Mitsuba Bitmap Texture'

View File

@ -18,8 +18,10 @@
import bpy import bpy
from mitsuba.ui.textures import mitsuba_texture_base from ... import MitsubaAddon
from ...ui.textures import mitsuba_texture_base
@MitsubaAddon.addon_register_class
class ui_texture_main(mitsuba_texture_base, bpy.types.Panel): class ui_texture_main(mitsuba_texture_base, bpy.types.Panel):
''' '''
Texture Editor UI Panel Texture Editor UI Panel

View File

@ -18,8 +18,10 @@
import bpy import bpy
from mitsuba.ui.textures import mitsuba_texture_base from ... import MitsubaAddon
from ...ui.textures import mitsuba_texture_base
@MitsubaAddon.addon_register_class
class ui_texture_mapping(mitsuba_texture_base, bpy.types.Panel): class ui_texture_mapping(mitsuba_texture_base, bpy.types.Panel):
bl_label = 'Mitsuba UV Mapping' bl_label = 'Mitsuba UV Mapping'

View File

@ -0,0 +1,89 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__GIZMO_H)
#define __GIZMO_H
#include <mitsuba/hw/renderer.h>
MTS_NAMESPACE_BEGIN
/**
* This class is responsible for rendering `gizmos', which are
* intuitive controls for navigating through 3D space.
*/
class MTS_EXPORT_HW Gizmo : public Object {
public:
Gizmo();
/// Initialize the gizmo for the specified bounding sphere
void init(const BSphere &bsphere);
/// Start a new drag operation
void startDrag(const Ray &ray);
//// Perform a drag to the specified ray
void dragTo(const Ray &ray, const Camera *camera);
/// Check whether the gizmo is currently active
inline bool isActive() const { return m_active; }
/// Check whether the gizmo is currently used in a drag operation
inline bool isDragging() const { return m_drag; }
/// Check whether a certain ray intersects the gizmo
inline void rayIntersect(const Ray &ray, Float &t) const {
Float farT;
if (!m_active || !m_bsphere.rayIntersect(ray, t, farT)) {
t = std::numeric_limits<Float>::infinity();
} else {
if (t <= 0)
t = farT;
if (t <= 0)
t = std::numeric_limits<Float>::infinity();
}
}
/// Draw the gizmo
void draw(Renderer *renderer, const Camera *camera);
/// Return the transformation associated with the gizmo
Transform getTransform() const;
/// Reset the gizmo
inline void reset() { m_active = m_drag = false; }
/// Stop dragging
inline void stopDrag() { m_drag = false; }
/// Return the bounding sphere associated with the gizmo
inline const BSphere &getBSphere() const { return m_bsphere; }
MTS_DECLARE_CLASS()
protected:
/// Virtual destructor
virtual ~Gizmo();
private:
BSphere m_bsphere;
Point m_dragStart, m_dragEnd;
bool m_active, m_drag;
};
MTS_NAMESPACE_END
#endif /* __GIZMO_H */

View File

@ -53,6 +53,9 @@ public:
/// Set a float parameter /// Set a float parameter
void setParameter(int id, Float value); void setParameter(int id, Float value);
/// Set a integer parameter
void setParameter(int id, int value);
/// Set a Vector parameter /// Set a Vector parameter
void setParameter(int id, const Vector &value); void setParameter(int id, const Vector &value);

View File

@ -102,6 +102,13 @@ public:
bool centerHoriz = true, bool centerVert = true, bool centerHoriz = true, bool centerVert = true,
const Vector2i &offset = Vector2i(0, 0)); const Vector2i &offset = Vector2i(0, 0));
/// Draw a planar circle with the specified center, normal and radius
void drawCircle(const Point &center, const Normal &normal, Float radius);
/// Draw a 3D arc connecting \c p1 and \c p2
void drawArc(const Point &center,
const Point &p1, const Point &p2, bool shorterPiece);
/// Clean up the renderer after drawing triangle geometry /// Clean up the renderer after drawing triangle geometry
void endDrawingMeshes(); void endDrawingMeshes();

View File

@ -40,8 +40,18 @@ public:
/// Free the texture from GPU memory /// Free the texture from GPU memory
void cleanup(); void cleanup();
/// Bind the texture and enable texturing /**
void bind(int textureUnit = 0) const; * \brief Bind the texture and enable texturing
*
* \param textureUnit
* Specifies the unit to which this texture should be bound
* \param textureIndex
* When this texture has multiple sub-textures (e.g.
* a color and depth map in the case of a
* \ref EColorAndDepthBuffer texture), this parameter
* specifies the one to be bound
*/
void bind(int textureUnit = 0, int textureIndex = 0) const;
/// Download the texture (only for render target textures) /// Download the texture (only for render target textures)
void download(Bitmap *bitmap = NULL); void download(Bitmap *bitmap = NULL);
@ -61,8 +71,35 @@ public:
/// Deactivate the render target /// Deactivate the render target
void releaseTarget(); void releaseTarget();
/// Blit a float render buffer into another render buffer /**
void blit(GPUTexture *texture) const; * \brief Blit a render buffer into another render buffer
*
* \param target
* Specifies the target render buffer (or NULL for the framebuffer)
* \param what
* A bitwise-OR of the components in \ref EFrameBufferType to copy
*/
void blit(GPUTexture *target, int what) const;
/**
* \brief Blit a render buffer into another render buffer
*
* \param target
* Specifies the target render buffer (or NULL for the framebuffer)
* \param what
* A bitwise-OR of the components in \ref EFrameBufferType to copy
* \param sourceOffset
* Offset in the source render buffer
* \param sourceOffset
* Size of the region to be copied from the source render buffer
* \param destOffset
* Offset in the destination render buffer
* \param destOffset
* Size of the region to be copied into the dest destination buffer
*/
void blit(GPUTexture *target, int what, const Point2i &sourceOffset,
const Vector2i &sourceSize, const Point2i &destOffset,
const Vector2i &destSize) const;
/// Clear (assuming that this is a render buffer) /// Clear (assuming that this is a render buffer)
void clear(); void clear();
@ -86,9 +123,7 @@ protected:
GLuint m_format; GLuint m_format;
GLuint m_internalFormat; GLuint m_internalFormat;
GLuint m_dataFormat; GLuint m_dataFormat;
/* For render targets */
GLuint m_fboId, m_depthId; GLuint m_fboId, m_depthId;
GLuint m_extraId;
mutable bool m_needsUpdate; mutable bool m_needsUpdate;
}; };

View File

@ -72,6 +72,12 @@ public:
setParameter(getParameterID(name, failIfMissing), value); setParameter(getParameterID(name, failIfMissing), value);
} }
/// Set a integer parameter by name
inline void setParameter(const std::string &name, int value,
bool failIfMissing = true) {
setParameter(getParameterID(name, failIfMissing), value);
}
/// Set a float parameter by name /// Set a float parameter by name
inline void setParameter(const std::string &name, Float value, inline void setParameter(const std::string &name, Float value,
bool failIfMissing = true) { bool failIfMissing = true) {
@ -181,6 +187,9 @@ public:
/// Set a float parameter /// Set a float parameter
virtual void setParameter(int id, Float value) = 0; virtual void setParameter(int id, Float value) = 0;
/// Set a int parameter
virtual void setParameter(int id, int value) = 0;
/// Set a Vector parameter /// Set a Vector parameter
virtual void setParameter(int id, const Vector &value) = 0; virtual void setParameter(int id, const Vector &value) = 0;

View File

@ -32,7 +32,7 @@ public:
/// Available texture types /// Available texture types
enum ETextureType { enum ETextureType {
/** /**
* 1-D texture, useful for the storage of pre-calculated functions * \brief 1-D texture, useful for the storage of pre-calculated functions
* in conjunction with pixel shaders. Needs 1D texture coordinates * in conjunction with pixel shaders. Needs 1D texture coordinates
*/ */
ETexture1D = 0, ETexture1D = 0,
@ -48,16 +48,22 @@ public:
}; };
/** \brief If the texture type is set to EFrameBuffer, the /** \brief If the texture type is set to EFrameBuffer, the
* configuration must be specified */ * configuration must be one of the following constants */
enum EFrameBufferType { enum EFrameBufferType {
/// This is not a framebuffer /// This is not a framebuffer
ENone = 0, ENone = 0x00,
/// Z-buffered color framebuffer /**
EColorBuffer, * \brief Color framebuffer (\a including an internal depth
* buffer that cannot be accessed as a texture)
*/
EColorBuffer = 0x01,
/// Depth-only framebuffer (e.g. for shadow mapping) /// Depth-only framebuffer (e.g. for shadow mapping)
EDepthBuffer EDepthBuffer = 0x02,
/// Color and texture framebuffer (both exposed as textures)
EColorAndDepthBuffer = 0x03
}; };
/// A texture has one more slots into which bitmaps can be placed /// A texture has one more slots into which bitmaps can be placed
@ -260,8 +266,18 @@ public:
/// Free the texture from GPU memory /// Free the texture from GPU memory
virtual void cleanup() = 0; virtual void cleanup() = 0;
/// Bind the texture and enable texturing /**
virtual void bind(int textureUnit = 0) const = 0; * \brief Bind the texture and enable texturing
*
* \param textureUnit
* Specifies the unit to which this texture should be bound
* \param textureIndex
* When this texture has multiple sub-textures (e.g.
* a color and depth map in the case of a
* \ref EColorAndDepthBuffer texture), this parameter
* specifies the one to be bound
*/
virtual void bind(int textureUnit = 0, int textureIndex = 0) const = 0;
/// Unbind the texture and disable texturing /// Unbind the texture and disable texturing
virtual void unbind() const = 0; virtual void unbind() const = 0;
@ -294,8 +310,35 @@ public:
/// Return the number of samples (for multisample color render targets) /// Return the number of samples (for multisample color render targets)
inline int getSampleCount() const { return m_samples; } inline int getSampleCount() const { return m_samples; }
/// Blit a float render buffer into another render buffer /**
virtual void blit(GPUTexture *texture) const = 0; * \brief Blit a render buffer into another render buffer
*
* \param target
* Specifies the target render buffer
* \param what
* A bitwise-OR of the components in \ref EFrameBufferType to copy
*/
virtual void blit(GPUTexture *target, int what) const = 0;
/**
* \brief Blit a render buffer into another render buffer
*
* \param target
* Specifies the target render buffer (or NULL for the framebuffer)
* \param what
* A bitwise-OR of the components in \ref EFrameBufferType to copy
* \param sourceOffset
* Offset in the source render buffer
* \param sourceOffset
* Size of the region to be copied from the source render buffer
* \param destOffset
* Offset in the destination render buffer
* \param destOffset
* Size of the region to be copied into the dest destination buffer
*/
virtual void blit(GPUTexture *target, int what, const Point2i &sourceOffset,
const Vector2i &sourceSize, const Point2i &destOffset,
const Vector2i &destSize) const = 0;
/// Clear (assuming that this is a render buffer) /// Clear (assuming that this is a render buffer)
virtual void clear() = 0; virtual void clear() = 0;

View File

@ -162,6 +162,14 @@ public:
bool centerHoriz = true, bool centerVert = true, bool centerHoriz = true, bool centerVert = true,
const Vector2i &offset = Vector2i(0, 0)) = 0; const Vector2i &offset = Vector2i(0, 0)) = 0;
/// Draw a planar circle with the specified center, normal and radius
virtual void drawCircle(const Point &center,
const Normal &normal, Float radius) = 0;
/// Draw a 3D arc connecting \c p1 and \c p2
virtual void drawArc(const Point &center,
const Point &p1, const Point &p2, bool shorterPiece) = 0;
/// Blit a screen-sized quad /// Blit a screen-sized quad
virtual void blitQuad(bool flipVertically) = 0; virtual void blitQuad(bool flipVertically) = 0;

View File

@ -255,8 +255,6 @@ public:
} }
MTS_DECLARE_CLASS() MTS_DECLARE_CLASS()
private:
Float m_beta;
}; };
MTS_IMPLEMENT_CLASS_S(SimpleVolumetricPathTracer, false, MonteCarloIntegrator) MTS_IMPLEMENT_CLASS_S(SimpleVolumetricPathTracer, false, MonteCarloIntegrator)

View File

@ -4,7 +4,7 @@ libhw_objects = [
'session.cpp', 'device.cpp', 'gputexture.cpp', 'gpugeometry.cpp', 'session.cpp', 'device.cpp', 'gputexture.cpp', 'gpugeometry.cpp',
'gpuprogram.cpp', 'renderer.cpp', 'glrenderer.cpp', 'glprogram.cpp', 'gpuprogram.cpp', 'renderer.cpp', 'glrenderer.cpp', 'glprogram.cpp',
'glgeometry.cpp', 'gltexture.cpp', 'gpusync.cpp', 'glsync.cpp', 'glgeometry.cpp', 'gltexture.cpp', 'gpusync.cpp', 'glsync.cpp',
'vpl.cpp', 'font.cpp', 'viewer.cpp'] 'vpl.cpp', 'font.cpp', 'viewer.cpp', 'gizmo.cpp']
if sys.platform == 'win32': if sys.platform == 'win32':
libhw_objects += ['wglsession.cpp', libhw_objects += ['wglsession.cpp',

113
src/libhw/gizmo.cpp Normal file
View File

@ -0,0 +1,113 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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, see <http://www.gnu.org/licenses/>.
*/
#include <mitsuba/hw/gizmo.h>
MTS_NAMESPACE_BEGIN
Gizmo::Gizmo() : m_active(false), m_drag(false) { }
Gizmo::~Gizmo() { }
void Gizmo::init(const BSphere &bsphere) {
m_bsphere = bsphere;
m_active = true;
m_drag = false;
}
Transform Gizmo::getTransform() const {
Vector leg1 = normalize(m_dragStart - m_bsphere.center);
Vector leg2 = normalize(m_dragEnd - m_bsphere.center);
Vector rotAxis = normalize(cross(leg1, leg2));
Float angle = unitAngle(leg1, leg2) * 180/M_PI;
return Transform::translate(Vector(m_bsphere.center)) *
Transform::rotate(rotAxis, angle) *
Transform::translate(-Vector(m_bsphere.center));
}
void Gizmo::startDrag(const Ray &ray) {
m_drag = false;
Float nearT, farT;
if (!m_bsphere.rayIntersect(ray, nearT, farT)
|| (nearT < 0 && farT < 0)) {
Log(EWarn, "Gizmo::init(): Internal error (no intersection found)!");
return;
} else if (nearT < 0) {
m_dragStart = ray(farT);
} else {
m_dragStart = ray(nearT);
}
m_active = true;
}
void Gizmo::dragTo(const Ray &ray, const Camera *camera) {
Float nearT, farT;
if (m_bsphere.rayIntersect(ray, nearT, farT)) {
if (nearT < 0)
m_dragEnd = ray(farT);
else
m_dragEnd = ray(nearT);
} else {
Normal n(normalize(m_bsphere.center - camera->getPosition()));
Float t = (dot(n, Vector(m_bsphere.center)) - dot(n, Vector(ray.o)))/dot(n, ray.d);
Point closest = ray(t);
m_dragEnd = m_bsphere.center + normalize(closest -
m_bsphere.center) * m_bsphere.radius;
}
m_drag = true;
}
void Gizmo::draw(Renderer *renderer, const Camera *camera) {
if (m_bsphere.isEmpty())
return;
/* Compute the tangent circle */
Vector camToSphere(m_bsphere.center - camera->getPosition());
const Float length = camToSphere.length(), radius = m_bsphere.radius;
camToSphere /= length;
Float tcRadius = std::sqrt(length*length - radius*radius)*radius/length;
Float tcDist = std::sqrt(radius*radius - tcRadius*tcRadius);
renderer->drawCircle(m_bsphere.center - camToSphere * tcDist,
camToSphere, tcRadius);
if (m_drag) {
Spectrum color1, color2;
color1.fromLinearRGB(0.7f, 0.7f, 1.0f);
color2.fromLinearRGB(0.3f, 0.3f, 0.3f);
Transform trafo = getTransform().inverse();
Point dragEnd = trafo(trafo(m_dragEnd));
renderer->setColor(color1);
renderer->drawArc(m_bsphere.center, m_dragStart, dragEnd, true);
renderer->setColor(color2);
renderer->drawArc(m_bsphere.center, m_dragStart, dragEnd, false);
Vector rotAxis = normalize(cross(m_dragStart-m_bsphere.center,
dragEnd-m_bsphere.center));
Vector circle2Axis = cross(normalize(m_dragStart-m_bsphere.center), rotAxis);
renderer->drawCircle(m_bsphere.center, Normal(circle2Axis), radius);
renderer->setColor(Spectrum(1.0f));
}
}
MTS_IMPLEMENT_CLASS(Gizmo, false, Object)
MTS_NAMESPACE_END

View File

@ -170,6 +170,12 @@ void GLProgram::setParameter(int id, Float value) {
glUniform1f(id, (GLfloat) value); glUniform1f(id, (GLfloat) value);
} }
void GLProgram::setParameter(int id, int value) {
if (id == -1)
return;
glUniform1i(id, value);
}
void GLProgram::setParameter(int id, const Vector &value) { void GLProgram::setParameter(int id, const Vector &value) {
if (id == -1) if (id == -1)
return; return;

View File

@ -741,6 +741,51 @@ void GLRenderer::blitQuad(bool flipVertically) {
glEnd(); glEnd();
} }
void GLRenderer::drawCircle(const Point &center,
const Normal &normal, Float radius) {
int nDiscr = 80;
Vector X, Y;
Float stepSize = 2*M_PI/nDiscr;
coordinateSystem(normal, X, Y);
glBegin(GL_LINE_LOOP);
for (int i=0; i<nDiscr; ++i) {
Float sinTheta = std::sin(i * stepSize) * radius;
Float cosTheta = std::cos(i * stepSize) * radius;
Point p = center + X*cosTheta + Y*sinTheta;
glVertex3f(p.x, p.y, p.z);
}
glEnd();
}
void GLRenderer::drawArc(const Point &center,
const Point &p1, const Point &p2, bool shorterPiece) {
if (p1 == p2 || p1 == center || p2 == center)
return;
Vector X = normalize(p1 - center), Y = p2 - center;
Float radius = Y.length(); Y /= radius;
Float angle = unitAngle(X, Y);
Y = normalize(Y - dot(Y, X) * X);
if (!shorterPiece) {
angle = 2*M_PI - angle;
Y = -Y;
}
int nDiscr = 80;
Float stepSize = angle/(nDiscr-1);
glBegin(GL_LINE_STRIP);
for (int i=0; i<nDiscr; ++i) {
Float sinTheta = std::sin(i * stepSize) * radius;
Float cosTheta = std::cos(i * stepSize) * radius;
Point p = center + X*cosTheta + Y*sinTheta;
glVertex3f(p.x, p.y, p.z);
}
glEnd();
}
void GLRenderer::drawText(const Point2i &_pos, void GLRenderer::drawText(const Point2i &_pos,
const Font *font, const std::string &text) { const Font *font, const std::string &text) {
int viewport[4]; int viewport[4];

View File

@ -31,7 +31,7 @@
MTS_NAMESPACE_BEGIN MTS_NAMESPACE_BEGIN
GLTexture::GLTexture(const std::string &name, Bitmap *bitmap) GLTexture::GLTexture(const std::string &name, Bitmap *bitmap)
: GPUTexture(name, bitmap), m_id(0), m_extraId(0), m_needsUpdate(true) { : GPUTexture(name, bitmap), m_id(0), m_needsUpdate(true) {
} }
void GLTexture::init() { void GLTexture::init() {
@ -48,11 +48,25 @@ void GLTexture::init() {
/* Bind to the texture */ /* Bind to the texture */
glBindTexture(m_glType, m_id); glBindTexture(m_glType, m_id);
/* Set the texture filtering / wrapping modes */ /* Set the texture filtering / wrapping modes
if (!(m_fbType == EColorBuffer && m_samples > 1)) (don't do this for multisample textures)*/
if (!((m_fbType & EColorBuffer) && m_samples > 1))
configureTexture(); /* Multisample textures don't have parameters */ configureTexture(); /* Multisample textures don't have parameters */
if (m_samples > 1) {
int samples;
glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
if (m_samples > samples) {
Log(EWarn, "Attempted to create a multisample framebuffer "
"with an unsupported # of samples (requested=%i, supported=%i)",
m_samples, samples);
m_samples = samples;
}
}
if (m_fbType == ENone) { if (m_fbType == ENone) {
Assert(m_samples == 1);
refresh(); refresh();
} else { } else {
/* Create the FBO and bind it */ /* Create the FBO and bind it */
@ -60,64 +74,73 @@ void GLTexture::init() {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
AssertEx(glIsFramebufferEXT(m_fboId), "Creating an FBO failed"); AssertEx(glIsFramebufferEXT(m_fboId), "Creating an FBO failed");
bool depthAsTexture = m_fbType & EDepthBuffer;
switch (m_fbType) { switch (m_fbType) {
case EColorAndDepthBuffer:
case EColorBuffer: { case EColorBuffer: {
if (m_type == ETexture2D) { if (m_type == ETexture2D) {
/* Create a depth buffer */ if (!depthAsTexture) {
glGenRenderbuffersEXT(1, &m_depthId); glGenRenderbuffersEXT(1, &m_depthId);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthId); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthId);
if (m_samples == 1)
if (m_samples == 1) {
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
GL_DEPTH_COMPONENT, m_size.x, m_size.y); GL_DEPTH_COMPONENT, m_size.x, m_size.y);
else
/* Allocate the texture memory */
glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y,
0, m_format, m_dataFormat, NULL);
} else {
int samples;
glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
if (m_samples > samples) {
Log(EWarn, "Attempted to create a multisample framebuffer "
"with an unsupported # of samples (requested=%i, supported=%i)", m_samples, samples);
m_samples = samples;
}
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
m_samples, GL_DEPTH_COMPONENT, m_size.x, m_size.y); m_samples, GL_DEPTH_COMPONENT, m_size.x, m_size.y);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthId);
} else {
glGenTextures(1, &m_depthId);
glBindTexture(m_glType, m_depthId);
configureTexture();
glTexParameteri(m_glType, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexParameteri(m_glType, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
if (m_samples == 1)
glTexImage2D(m_glType, 0, GL_DEPTH_COMPONENT24, m_size.x, m_size.y,
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
else
glTexImage2DMultisample(m_glType, glTexImage2DMultisample(m_glType,
m_samples, m_internalFormat, m_size.x, m_size.y, GL_FALSE); m_samples, GL_DEPTH_COMPONENT24, m_size.x, m_size.y, GL_FALSE);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT, m_glType, m_depthId, 0);
glBindTexture(m_glType, m_id);
} }
if (m_samples == 1)
glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y,
0, m_format, m_dataFormat, NULL);
else
glTexImage2DMultisample(m_glType,
m_samples, m_internalFormat, m_size.x, m_size.y, GL_FALSE);
if (isMipMapped()) if (isMipMapped())
glGenerateMipmapEXT(m_glType); glGenerateMipmapEXT(m_glType);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthId);
/* Attach the texture as a color target */
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, m_glType, m_id, 0); GL_COLOR_ATTACHMENT0_EXT, m_glType, m_id, 0);
} else if (m_type == ETextureCubeMap) { } else if (m_type == ETextureCubeMap) {
Assert(m_size.x == m_size.y && isPowerOfTwo(m_size.x)); Assert(m_size.x == m_size.y && isPowerOfTwo(m_size.x));
Assert(m_fbType == EColorBuffer);
Assert(m_samples == 1);
for (int i=0; i<6; i++) for (int i=0; i<6; i++)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat, m_size.x, m_size.y, glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat,
0, m_format, m_dataFormat, NULL); m_size.x, m_size.y, 0, m_format, m_dataFormat, NULL);
if (isMipMapped()) if (isMipMapped())
glGenerateMipmapEXT(m_glType); glGenerateMipmapEXT(m_glType);
/* Generate an identifier */ /* Generate an identifier */
glGenTextures(1, &m_extraId); glGenTextures(1, &m_depthId);
glBindTexture(m_glType, m_extraId); glBindTexture(m_glType, m_depthId);
glTexParameteri(m_glType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(m_glType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(m_glType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(m_glType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
for (int i=0; i<6; i++) for (int i=0; i<6; i++)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT24, m_size.x, m_size.y, glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT24,
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); m_size.x, m_size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
if (glewIsSupported("GL_EXT_geometry_shader4")) if (glewIsSupported("GL_EXT_geometry_shader4"))
activateSide(-1); activateSide(-1);
@ -147,8 +170,8 @@ void GLTexture::init() {
} else if (m_type == ETextureCubeMap) { } else if (m_type == ETextureCubeMap) {
Assert(m_size.x == m_size.y && isPowerOfTwo(m_size.x)); Assert(m_size.x == m_size.y && isPowerOfTwo(m_size.x));
for (int i=0; i<6; i++) for (int i=0; i<6; i++)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat, m_size.x, m_size.y, glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat,
0, m_format, m_dataFormat, NULL); m_size.x, m_size.y, 0, m_format, m_dataFormat, NULL);
if (glewIsSupported("GL_EXT_geometry_shader4")) if (glewIsSupported("GL_EXT_geometry_shader4"))
activateSide(-1); activateSide(-1);
@ -229,12 +252,6 @@ void GLTexture::refresh() {
} }
} }
/* Does not support floating point textures on all platforms
if (isMipMapped())
gluBuild2DMipmaps(m_glType, m_internalFormat, m_size.x, m_size.y,
m_format, m_dataFormat, bitmap->getData());
else
*/
glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y, glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y,
0, m_format, m_dataFormat, bitmap->getData()); 0, m_format, m_dataFormat, bitmap->getData());
@ -480,19 +497,23 @@ void GLTexture::activateSide(int side) {
if (side == -1) { if (side == -1) {
if (m_fbType == EColorBuffer) { if (m_fbType == EColorBuffer) {
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_id, 0); glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_id, 0);
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_extraId, 0); glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_depthId, 0);
} else { } else if (m_fbType == EDepthBuffer) {
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_id, 0); glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_id, 0);
} else {
Log(EError, "Unsupported framebuffer type!");
} }
} else { } else {
if (m_fbType == EColorBuffer) { if (m_fbType == EColorBuffer) {
//glFramebufferTextureFaceEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_id, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
//glFramebufferTextureFaceEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_extraId, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side); GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_extraId, 0); GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_depthId, 0);
} else if (m_fbType == EDepthBuffer) {
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
} else { } else {
//glFramebufferTextureFaceEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_id, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side); Log(EError, "Unsupported framebuffer type!");
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
} }
} }
} }
@ -509,15 +530,20 @@ void GLTexture::releaseTarget() {
m_needsUpdate = true; m_needsUpdate = true;
} }
void GLTexture::bind(int textureUnit) const { void GLTexture::bind(int textureUnit, int textureIndex) const {
/* Bind to the texture */ /* Bind to the texture */
if (GLEW_VERSION_1_3) { if (GLEW_VERSION_1_3) {
m_textureUnits.get().insert(textureUnit); m_textureUnits.get().insert(textureUnit);
glActiveTexture(GL_TEXTURE0 + textureUnit); glActiveTexture(GL_TEXTURE0 + textureUnit);
} else { } else {
AssertEx(textureUnit == 0, "Multitexture is not supported"); if (textureUnit != 0)
Log(EError, "Multitexturing is not supported");
} }
glEnable(m_glType); glEnable(m_glType);
if (textureIndex == 1 && m_fbType == EColorAndDepthBuffer)
glBindTexture(m_glType, m_depthId);
else
glBindTexture(m_glType, m_id); glBindTexture(m_glType, m_id);
if (isMipMapped() && m_needsUpdate) { if (isMipMapped() && m_needsUpdate) {
@ -545,41 +571,85 @@ void GLTexture::cleanup() {
return; return;
if (m_fbType != ENone) { if (m_fbType != ENone) {
Log(ETrace, "Freeing framebuffer \"%s\"", m_name.c_str()); Log(ETrace, "Freeing framebuffer \"%s\"", m_name.c_str());
switch (m_fbType) { if (m_fbType == EColorAndDepthBuffer || (m_fbType == EColorBuffer && m_type == ETextureCubeMap)) {
case EColorBuffer: glDeleteTextures(1, &m_depthId);
} else if (m_fbType == EColorBuffer) {
glDeleteRenderbuffersEXT(1, &m_depthId); glDeleteRenderbuffersEXT(1, &m_depthId);
break;
case EDepthBuffer:
break;
default:
Log(EError, "Invalid framebuffer type!");
} }
glDeleteFramebuffersEXT(1, &m_fboId); glDeleteFramebuffersEXT(1, &m_fboId);
} else { } else {
Log(ETrace, "Freeing texture \"%s\"", m_name.c_str()); Log(ETrace, "Freeing texture \"%s\"", m_name.c_str());
} }
glDeleteTextures(1, &m_id); glDeleteTextures(1, &m_id);
m_id = 0; m_id = 0;
if (m_extraId != 0) {
glDeleteTextures(1, &m_extraId);
m_extraId = 0;
}
} }
void GLTexture::blit(GPUTexture *texture) const { void GLTexture::blit(GPUTexture *target, int what) const {
GLTexture *dest = static_cast<GLTexture *>(texture); GLTexture *dest = static_cast<GLTexture *>(target);
Assert(m_fbType != ENone && (dest == NULL || dest->m_fbType != ENone));
Assert(m_fbType == EColorBuffer && dest->m_fbType == EColorBuffer); if (!GLEW_EXT_framebuffer_blit)
Log(EError, "Your OpenGL driver does not support fast "
"framebuffer blitting!");
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_fboId); glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_fboId);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dest->m_fboId); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,
(dest == NULL) ? GL_NONE : dest->m_fboId);
int flags = 0;
if (what & EDepthBuffer)
flags |= GL_DEPTH_BUFFER_BIT;
if (what & EColorBuffer)
flags |= GL_COLOR_BUFFER_BIT;
if (!dest) {
glBlitFramebufferEXT(0, 0, m_size.x, m_size.y, 0, 0, glBlitFramebufferEXT(0, 0, m_size.x, m_size.y, 0, 0,
dest->m_size.x, dest->m_size.y, GL_COLOR_BUFFER_BIT, GL_LINEAR); m_size.x, m_size.y, flags, GL_NEAREST);
} else {
glBlitFramebufferEXT(0, 0, m_size.x, m_size.y, 0, 0,
dest->m_size.x, dest->m_size.y, flags,
(m_size == dest->m_size) ? GL_NEAREST : GL_LINEAR);
}
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_NONE);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_NONE);
}
void GLTexture::blit(GPUTexture *target, int what, const Point2i &sourceOffset,
const Vector2i &sourceSize, const Point2i &destOffset,
const Vector2i &destSize) const {
GLTexture *dest = static_cast<GLTexture *>(target);
Assert(m_fbType != ENone && (dest == NULL || dest->m_fbType != ENone));
if (!GLEW_EXT_framebuffer_blit)
Log(EError, "Your OpenGL driver does not support fast "
"framebuffer blitting!");
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_fboId);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,
(dest == NULL) ? GL_NONE : dest->m_fboId);
int flags = 0;
if (what & EDepthBuffer)
flags |= GL_DEPTH_BUFFER_BIT;
if (what & EColorBuffer)
flags |= GL_COLOR_BUFFER_BIT;
glBlitFramebufferEXT(sourceOffset.x, sourceOffset.y,
sourceOffset.x + sourceSize.x, sourceOffset.x + sourceSize.y,
destOffset.x, destOffset.y, destOffset.x + destSize.x,
destOffset.y + destSize.y, flags,
(sourceSize == destSize) ? GL_NEAREST : GL_LINEAR);
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_NONE);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_NONE);
} }
void GLTexture::clear() { void GLTexture::clear() {
Assert(m_fbType != ENone); Assert(m_fbType != ENone);
glClear(GL_DEPTH_BUFFER_BIT | (m_fbType == EColorBuffer ? GL_COLOR_BUFFER_BIT : 0)); glClear(GL_DEPTH_BUFFER_BIT
| ((m_fbType & EColorBuffer) ? GL_COLOR_BUFFER_BIT : 0));
} }
GLTexture::~GLTexture() { GLTexture::~GLTexture() {

View File

@ -87,6 +87,7 @@ void GPUTexture::setFrameBufferType(EFrameBufferType type) {
switch (m_fbType) { switch (m_fbType) {
case EColorBuffer: case EColorBuffer:
case EColorAndDepthBuffer:
break; break;
case EDepthBuffer: case EDepthBuffer:
m_format = EDepth; m_format = EDepth;
@ -164,6 +165,7 @@ static const char *toString(GPUTexture::EFrameBufferType fbType) {
case GPUTexture::ENone: return "none"; case GPUTexture::ENone: return "none";
case GPUTexture::EDepthBuffer: return "depthBuffer"; case GPUTexture::EDepthBuffer: return "depthBuffer";
case GPUTexture::EColorBuffer: return "colorBuffer"; case GPUTexture::EColorBuffer: return "colorBuffer";
case GPUTexture::EColorAndDepthBuffer: return "colorAndDepthBuffer";
default: SLog(EError, "Invalid framebuffer type"); return NULL; default: SLog(EError, "Invalid framebuffer type"); return NULL;
} }
} }

View File

@ -343,10 +343,9 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
<< "varying out vec3 vertexColor;" << endl << "varying out vec3 vertexColor;" << endl
<< endl << endl
<< "void main() {" << endl << "void main() {" << endl
<< " vec3 p0 = gl_PositionIn[0].xyz / gl_PositionIn[0].w;" << endl << " vec3 edge1 = camVec_vertex[0]-camVec_vertex[1];" << endl
<< " vec3 p1 = gl_PositionIn[1].xyz / gl_PositionIn[1].w;" << endl << " vec3 edge2 = camVec_vertex[0]-camVec_vertex[2];" << endl
<< " vec3 p2 = gl_PositionIn[2].xyz / gl_PositionIn[2].w;" << endl << " normal = normalize(cross(edge1, edge2));" << endl
<< " normal = normalize(cross(p1 - p0, p2 - p0));" << endl
<< " gl_Position = vec4(0.0);" << endl << " gl_Position = vec4(0.0);" << endl
<< " lightVec = camVec = vec3(0.0);" << endl << " lightVec = camVec = vec3(0.0);" << endl
<< " for (int i=0; i<gl_VerticesIn; ++i) {" << endl << " for (int i=0; i<gl_VerticesIn; ++i) {" << endl

View File

@ -33,10 +33,17 @@ enum EConnectionType {
}; };
enum ENavigationMode { enum ENavigationMode {
EFlythroughFixedYaw = 0, EArcBall = 0,
EFlythroughFixedYaw,
EFlythrough EFlythrough
}; };
enum ESelectionMode {
ENothing = 0,
EShape,
EScene
};
namespace mitsuba { namespace mitsuba {
class RemoteWorker; class RemoteWorker;
}; };
@ -184,13 +191,16 @@ struct SceneContext {
bool diffuseReceivers; bool diffuseReceivers;
bool showKDTree; bool showKDTree;
int shownKDTreeLevel; int shownKDTreeLevel;
ESelectionMode selectionMode;
const Shape *selectedShape;
/* Preview state */ /* Preview state */
std::deque<VPL> vpls; std::deque<VPL> vpls;
PreviewQueueEntry previewBuffer; PreviewQueueEntry previewBuffer;
SceneContext() : scene(NULL), sceneResID(-1), renderJob(NULL) { SceneContext() : scene(NULL), sceneResID(-1),
} renderJob(NULL), selectionMode(ENothing),
selectedShape(NULL) { }
/// Detect the path length /// Detect the path length
int detectPathLength() const; int detectPathLength() const;

View File

@ -38,12 +38,14 @@ GLWidget::GLWidget(QWidget *parent) :
m_movementTimer = new QTimer(parent); m_movementTimer = new QTimer(parent);
m_movementTimer->setInterval(20); m_movementTimer->setInterval(20);
m_movementTimer->setSingleShot(false); m_movementTimer->setSingleShot(false);
m_wheelTimer = new Timer();
m_redrawTimer = new QTimer(parent); m_redrawTimer = new QTimer(parent);
m_redrawTimer->setInterval(200); m_redrawTimer->setInterval(200);
connect(m_movementTimer, SIGNAL(timeout()), this, SLOT(timerImpulse())); connect(m_movementTimer, SIGNAL(timeout()), this, SLOT(timerImpulse()));
connect(m_redrawTimer, SIGNAL(timeout()), this, SLOT(updateGL())); connect(m_redrawTimer, SIGNAL(timeout()), this, SLOT(updateGL()));
m_renderer = Renderer::create(NULL); m_renderer = Renderer::create(NULL);
m_device = new QtDevice(this); m_device = new QtDevice(this);
m_gizmo = new Gizmo();
m_preview = new PreviewThread(m_device, m_renderer); m_preview = new PreviewThread(m_device, m_renderer);
connect(m_preview, SIGNAL(caughtException(const QString &)), connect(m_preview, SIGNAL(caughtException(const QString &)),
this, SLOT(onException(const QString &)), Qt::QueuedConnection); this, SLOT(onException(const QString &)), Qt::QueuedConnection);
@ -114,6 +116,9 @@ void GLWidget::initializeGL() {
if (!m_renderer->getCapabilities()->isSupported( if (!m_renderer->getCapabilities()->isSupported(
RendererCapabilities::EVertexBufferObjects)) RendererCapabilities::EVertexBufferObjects))
missingExtensions.push_back("Vertex buffer objects"); missingExtensions.push_back("Vertex buffer objects");
if (!m_renderer->getCapabilities()->isSupported(
RendererCapabilities::EBufferBlit))
missingExtensions.push_back("Fast blitting");
if (missingExtensions.size() > 0 || m_softwareFallback) { if (missingExtensions.size() > 0 || m_softwareFallback) {
#if !defined(MTS_GUI_SOFTWARE_FALLBACK) #if !defined(MTS_GUI_SOFTWARE_FALLBACK)
@ -149,6 +154,7 @@ void GLWidget::initializeGL() {
); );
m_gammaTonemap->setSource(GPUProgram::EFragmentProgram, m_gammaTonemap->setSource(GPUProgram::EFragmentProgram,
"#version 120\n"
"uniform sampler2D source;\n" "uniform sampler2D source;\n"
"uniform float invWhitePoint, invGamma;\n" "uniform float invWhitePoint, invGamma;\n"
"uniform bool sRGB;\n" "uniform bool sRGB;\n"
@ -162,7 +168,7 @@ void GLWidget::initializeGL() {
"void main() {\n" "void main() {\n"
" vec4 color = texture2D(source, gl_TexCoord[0].xy) * invWhitePoint;\n" " vec4 color = texture2D(source, gl_TexCoord[0].xy) * invWhitePoint;\n"
" if (sRGB)\n" " if (sRGB)\n"
" gl_FragColor = vec4(toSRGB(color.r), toSRGB(color.g), toSRGB(color.b), 1);" " gl_FragColor = vec4(toSRGB(color.r), toSRGB(color.g), toSRGB(color.b), 1);\n"
" else\n" " else\n"
" gl_FragColor = vec4(pow(color.rgb, vec3(invGamma)), 1);\n" " gl_FragColor = vec4(pow(color.rgb, vec3(invGamma)), 1);\n"
"}\n" "}\n"
@ -176,6 +182,7 @@ void GLWidget::initializeGL() {
); );
m_reinhardTonemap->setSource(GPUProgram::EFragmentProgram, m_reinhardTonemap->setSource(GPUProgram::EFragmentProgram,
"#version 120\n"
"uniform sampler2D source;\n" "uniform sampler2D source;\n"
"uniform float key, invWpSqr, invGamma, multiplier;\n" "uniform float key, invWpSqr, invGamma, multiplier;\n"
"uniform bool sRGB;\n" "uniform bool sRGB;\n"
@ -288,6 +295,9 @@ void GLWidget::initializeGL() {
m_logoTexture->init(); m_logoTexture->init();
m_font->init(m_renderer); m_font->init(m_renderer);
m_redrawTimer->start(); m_redrawTimer->start();
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glLineWidth(0.6f);
} }
void GLWidget::setScene(SceneContext *context) { void GLWidget::setScene(SceneContext *context) {
@ -301,6 +311,7 @@ void GLWidget::setScene(SceneContext *context) {
m_framebufferChanged = true; m_framebufferChanged = true;
m_mouseButtonDown = false; m_mouseButtonDown = false;
m_leftKeyDown = m_rightKeyDown = m_upKeyDown = m_downKeyDown = false; m_leftKeyDown = m_rightKeyDown = m_upKeyDown = m_downKeyDown = false;
m_gizmo->reset();
updateGeometry(); updateGeometry();
updateScrollBars(); updateScrollBars();
updateGL(); updateGL();
@ -509,7 +520,8 @@ void GLWidget::resetPreview() {
if (!m_context || !m_context->scene || !m_preview->isRunning()) if (!m_context || !m_context->scene || !m_preview->isRunning())
return; return;
bool motion = m_leftKeyDown || m_rightKeyDown || bool motion = m_leftKeyDown || m_rightKeyDown ||
m_upKeyDown || m_downKeyDown || m_mouseButtonDown; m_upKeyDown || m_downKeyDown || m_mouseButtonDown ||
m_wheelTimer->getMilliseconds() < 200;
m_preview->setSceneContext(m_context, false, motion); m_preview->setSceneContext(m_context, false, motion);
updateGL(); updateGL();
} }
@ -523,21 +535,49 @@ void GLWidget::keyPressEvent(QKeyEvent *event) {
if (event->isAutoRepeat() || !m_context) if (event->isAutoRepeat() || !m_context)
return; return;
PinholeCamera *camera = static_cast<PinholeCamera *>(m_context->scene->getCamera());
switch (event->key()) { switch (event->key()) {
case Qt::Key_PageUp: m_context->movementScale *= 2; break; case Qt::Key_PageUp: m_context->movementScale *= 2; break;
case Qt::Key_PageDown: m_context->movementScale /= 2; break; case Qt::Key_PageDown: m_context->movementScale /= 2; break;
case Qt::Key_A:
case Qt::Key_Left: case Qt::Key_Left:
m_leftKeyDown = true; break; m_leftKeyDown = true; break;
case Qt::Key_D:
case Qt::Key_Right: case Qt::Key_Right:
m_rightKeyDown = true; break; m_rightKeyDown = true; break;
case Qt::Key_W:
case Qt::Key_Up: case Qt::Key_Up:
m_upKeyDown = true; break; m_upKeyDown = true; break;
case Qt::Key_S:
case Qt::Key_Down: case Qt::Key_Down:
m_downKeyDown = true; break; m_downKeyDown = true; break;
case Qt::Key_A: {
if (m_context->selectionMode == ENothing) {
m_context->selectionMode = EScene;
m_gizmo->init(m_context->scene->getBSphere());
} else {
m_context->selectionMode = ENothing;
m_gizmo->reset();
}
m_context->selectedShape = NULL;
updateGL();
}
// break intentionally missing
case Qt::Key_F: {
if (!m_gizmo->isActive())
return;
Vector up;
if (m_navigationMode == EFlythroughFixedYaw)
up = m_context->up;
else
up = camera->getInverseViewTransform()(Vector(0,1,0));
Vector d = Vector(camera->getImagePlaneNormal());
Float fov = std::min(camera->getXFov(), camera->getYFov())*0.8/2;
const BSphere &bs = m_gizmo->getBSphere();
Float distance = bs.radius/std::tan(fov * M_PI/180);
camera->setInverseViewTransform(
Transform::lookAt(bs.center - distance*d, bs.center, up));
resetPreview();
};
break;
} }
if (!m_movementTimer->isActive() && (m_leftKeyDown || m_rightKeyDown || m_upKeyDown || m_downKeyDown)) { if (!m_movementTimer->isActive() && (m_leftKeyDown || m_rightKeyDown || m_upKeyDown || m_downKeyDown)) {
m_clock->reset(); m_clock->reset();
@ -549,16 +589,12 @@ void GLWidget::keyReleaseEvent(QKeyEvent *event) {
if (event->isAutoRepeat() || !m_context || !m_preview->isRunning()) if (event->isAutoRepeat() || !m_context || !m_preview->isRunning())
return; return;
switch (event->key()) { switch (event->key()) {
case Qt::Key_A:
case Qt::Key_Left: case Qt::Key_Left:
m_leftKeyDown = false; break; m_leftKeyDown = false; break;
case Qt::Key_D:
case Qt::Key_Right: case Qt::Key_Right:
m_rightKeyDown = false; break; m_rightKeyDown = false; break;
case Qt::Key_W:
case Qt::Key_Up: case Qt::Key_Up:
m_upKeyDown = false; break; m_upKeyDown = false; break;
case Qt::Key_S:
case Qt::Key_Down: case Qt::Key_Down:
m_downKeyDown = false; break; m_downKeyDown = false; break;
case Qt::Key_BracketLeft: case Qt::Key_BracketLeft:
@ -601,7 +637,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
return; return;
} }
if (!m_didSetCursor) { if (!m_didSetCursor && !(m_navigationMode == EArcBall && event->buttons() & Qt::LeftButton)) {
QApplication::setOverrideCursor(Qt::BlankCursor); QApplication::setOverrideCursor(Qt::BlankCursor);
m_didSetCursor = true; m_didSetCursor = true;
} }
@ -610,7 +646,20 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
Point p = camera->getInverseViewTransform()(Point(0,0,0)); Point p = camera->getInverseViewTransform()(Point(0,0,0));
Vector direction = camera->getInverseViewTransform()(Vector(0,0,1)); Vector direction = camera->getInverseViewTransform()(Vector(0,0,1));
Vector up; Vector up;
bool didMove = false;
if (m_navigationMode == EArcBall) {
if (event->buttons() & Qt::LeftButton) {
Ray ray;
Point2i offset = upperLeft();
Point2 sample = Point2(m_mousePos.x() - offset.x, m_mousePos.y() - offset.y);
camera->setViewTransform(m_storedViewTransform);
camera->generateRay(sample, Point2(0, 0), 0, ray);
m_gizmo->dragTo(ray, camera);
camera->setViewTransform(m_storedViewTransform * m_gizmo->getTransform());
didMove = true;
}
} else {
if (m_navigationMode == EFlythrough) if (m_navigationMode == EFlythrough)
up = camera->getInverseViewTransform()(Vector(0,1,0)); up = camera->getInverseViewTransform()(Vector(0,1,0));
else if (m_navigationMode == EFlythroughFixedYaw) else if (m_navigationMode == EFlythroughFixedYaw)
@ -618,8 +667,6 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
else else
SLog(EError, "Unknown navigation mode encountered!"); SLog(EError, "Unknown navigation mode encountered!");
bool didMove = false;
if (event->buttons() & Qt::LeftButton) { if (event->buttons() & Qt::LeftButton) {
Float yaw = -.03f * rel.x() * m_mouseSensitivity; Float yaw = -.03f * rel.x() * m_mouseSensitivity;
Float pitch = -.03f * rel.y() * m_mouseSensitivity; Float pitch = -.03f * rel.y() * m_mouseSensitivity;
@ -658,6 +705,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
} }
camera->setFov(std::min(std::max((Float) 1.0f, camera->getFov() + fovChange), (Float) 100.0f)); camera->setFov(std::min(std::max((Float) 1.0f, camera->getFov() + fovChange), (Float) 100.0f));
}
camera->configure(); camera->configure();
didMove = true; didMove = true;
@ -671,6 +719,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
didMove = true; didMove = true;
} }
if (m_navigationMode != EArcBall) {
QPoint global = mapToGlobal(m_mousePos); QPoint global = mapToGlobal(m_mousePos);
QDesktopWidget *desktop = QApplication::desktop(); QDesktopWidget *desktop = QApplication::desktop();
@ -681,6 +730,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
m_ignoreMouseEvent = target - global; m_ignoreMouseEvent = target - global;
QCursor::setPos(target); QCursor::setPos(target);
} }
}
if (didMove) if (didMove)
timerImpulse(); timerImpulse();
@ -689,10 +739,10 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
void GLWidget::wheelEvent(QWheelEvent *event) { void GLWidget::wheelEvent(QWheelEvent *event) {
QScrollBar *bar = event->orientation() == Qt::Vertical QScrollBar *bar = event->orientation() == Qt::Vertical
? m_vScroll : m_hScroll; ? m_vScroll : m_hScroll;
if (!m_preview->isRunning())
if (!bar->isVisible() || !m_preview->isRunning())
return; return;
if (bar->isVisible()) {
int oldStep = bar->singleStep(); int oldStep = bar->singleStep();
bar->setSingleStep(event->delta()/4); bar->setSingleStep(event->delta()/4);
#if defined(__OSX__) #if defined(__OSX__)
@ -705,6 +755,29 @@ void GLWidget::wheelEvent(QWheelEvent *event) {
QAbstractSlider::SliderSingleStepSub QAbstractSlider::SliderSingleStepSub
: QAbstractSlider::SliderSingleStepAdd); : QAbstractSlider::SliderSingleStepAdd);
bar->setSingleStep(oldStep); bar->setSingleStep(oldStep);
} else {
ProjectiveCamera *camera
= static_cast<ProjectiveCamera *>(m_context->scene->getCamera());
Vector up;
if (m_navigationMode == EFlythroughFixedYaw)
up = m_context->up;
else
up = camera->getInverseViewTransform()(Vector(0,1,0));
Vector d = Vector(camera->getImagePlaneNormal());
Point o = camera->getPosition();
Intersection its;
if (m_context->scene->rayIntersect(Ray(o, d, 0), its)) {
Float length = (its.p - o).length();
length *= std::pow(1 - 1e-3f, event->delta());
camera->setInverseViewTransform(
Transform::lookAt(its.p - length*d, its.p, up));
m_wheelTimer->reset();
resetPreview();
}
}
event->accept(); event->accept();
} }
@ -714,6 +787,37 @@ void GLWidget::mousePressEvent(QMouseEvent *event) {
m_mousePos = event->pos(); m_mousePos = event->pos();
m_initialMousePos = mapToGlobal(m_mousePos); m_initialMousePos = mapToGlobal(m_mousePos);
m_mouseButtonDown = true; m_mouseButtonDown = true;
ProjectiveCamera *camera = static_cast<ProjectiveCamera *>(m_context->scene->getCamera());
if (m_navigationMode == EArcBall && event->buttons() & Qt::LeftButton) {
Point2i offset = upperLeft();
Point2 sample = Point2(m_mousePos.x() - offset.x, m_mousePos.y() - offset.y);
Intersection its;
Ray ray;
Float t;
camera->generateRay(sample, Point2(0, 0), 0, ray);
m_gizmo->rayIntersect(ray, t);
if (m_context->scene->rayIntersect(ray, its)) {
if (its.t < t) {
SLog(EInfo, "Selected shape \"%s\"", its.shape->getName().c_str());
m_context->selectedShape = its.shape;
m_gizmo->init(its.shape->getAABB().getBSphere());
m_context->selectionMode = EShape;
}
} else {
if (t == std::numeric_limits<Float>::infinity()) {
m_gizmo->reset();
m_context->selectionMode = ENothing;
m_context->selectedShape = NULL;
return;
}
}
m_gizmo->startDrag(ray);
m_storedViewTransform = camera->getViewTransform();
}
} }
void GLWidget::mouseReleaseEvent(QMouseEvent *event) { void GLWidget::mouseReleaseEvent(QMouseEvent *event) {
@ -721,17 +825,20 @@ void GLWidget::mouseReleaseEvent(QMouseEvent *event) {
return; return;
if (event->buttons() == 0) { if (event->buttons() == 0) {
m_mouseButtonDown = false; m_mouseButtonDown = false;
if (m_didSetCursor) { if (m_didSetCursor) {
resetPreview(); resetPreview();
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
QCursor::setPos(m_initialMousePos); QCursor::setPos(m_initialMousePos);
m_didSetCursor = false; m_didSetCursor = false;
} else if (m_gizmo->isDragging()) {
m_gizmo->stopDrag();
resetPreview();
} }
} }
} }
void GLWidget::paintGL() { void GLWidget::paintGL() {
m_renderer->setDepthMask(false);
m_renderer->setDepthTest(false); m_renderer->setDepthTest(false);
if (m_context == NULL) { if (m_context == NULL) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
@ -740,7 +847,7 @@ void GLWidget::paintGL() {
m_renderer->blitTexture(m_logoTexture); m_renderer->blitTexture(m_logoTexture);
m_renderer->setBlendMode(Renderer::EBlendNone); m_renderer->setBlendMode(Renderer::EBlendNone);
} else if (m_context != NULL) { } else if (m_context != NULL) {
Point3i size; Vector2i size;
glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
PreviewQueueEntry entry; PreviewQueueEntry entry;
@ -753,14 +860,15 @@ void GLWidget::paintGL() {
return; return;
} }
bool motion = m_leftKeyDown || m_rightKeyDown || bool motion = m_leftKeyDown || m_rightKeyDown ||
m_upKeyDown || m_downKeyDown || m_mouseButtonDown; m_upKeyDown || m_downKeyDown || m_mouseButtonDown ||
m_wheelTimer->getMilliseconds() < 200;
entry = m_preview->acquireBuffer(motion ? -1 : 50); entry = m_preview->acquireBuffer(motion ? -1 : 50);
if (entry.buffer == NULL) { if (entry.buffer == NULL) {
/* Unsuccessful at acquiring a buffer in the /* Unsuccessful at acquiring a buffer in the
alloted time - just leave and keep the current display */ alloted time - just leave and keep the current display */
return; return;
} }
size = entry.buffer->getSize(); size = Vector2i(entry.buffer->getSize().x, entry.buffer->getSize().y);
buffer = entry.buffer; buffer = entry.buffer;
} else if (m_context->mode == ERender) { } else if (m_context->mode == ERender) {
if (m_framebuffer == NULL || if (m_framebuffer == NULL ||
@ -806,7 +914,7 @@ void GLWidget::paintGL() {
m_framebufferChanged = false; m_framebufferChanged = false;
} }
size = m_framebuffer->getSize(); size = Vector2i(m_framebuffer->getSize().x, m_framebuffer->getSize().y);
buffer = m_framebuffer; buffer = m_framebuffer;
} }
@ -822,9 +930,8 @@ void GLWidget::paintGL() {
if (m_context->mode == EPreview) if (m_context->mode == EPreview)
invWhitePoint /= entry.vplSampleOffset; invWhitePoint /= entry.vplSampleOffset;
buffer->bind();
m_gammaTonemap->bind(); m_gammaTonemap->bind();
m_gammaTonemap->setParameter("source", buffer); m_gammaTonemap->setParameter("source", 0);
m_gammaTonemap->setParameter("invWhitePoint", invWhitePoint); m_gammaTonemap->setParameter("invWhitePoint", invWhitePoint);
m_gammaTonemap->setParameter("invGamma", 1/m_context->gamma); m_gammaTonemap->setParameter("invGamma", 1/m_context->gamma);
m_gammaTonemap->setParameter("sRGB", m_context->srgb); m_gammaTonemap->setParameter("sRGB", m_context->srgb);
@ -832,7 +939,6 @@ void GLWidget::paintGL() {
!m_hScroll->isVisible(), !m_vScroll->isVisible(), !m_hScroll->isVisible(), !m_vScroll->isVisible(),
-m_context->scrollOffset); -m_context->scrollOffset);
m_gammaTonemap->unbind(); m_gammaTonemap->unbind();
buffer->unbind();
} else if (m_context->toneMappingMethod == EReinhard) { } else if (m_context->toneMappingMethod == EReinhard) {
if (m_luminanceBuffer[0] == NULL || m_luminanceBuffer[0]->getSize() != Point3i(size.x, size.y, 1)) { if (m_luminanceBuffer[0] == NULL || m_luminanceBuffer[0]->getSize() != Point3i(size.x, size.y, 1)) {
for (int i=0; i<2; ++i) { for (int i=0; i<2; ++i) {
@ -892,9 +998,8 @@ void GLWidget::paintGL() {
logLuminance = 1; logLuminance = 1;
} }
buffer->bind();
m_reinhardTonemap->bind(); m_reinhardTonemap->bind();
m_reinhardTonemap->setParameter("source", buffer); m_reinhardTonemap->setParameter("source", 0);
m_reinhardTonemap->setParameter("key", m_context->reinhardKey/logLuminance); m_reinhardTonemap->setParameter("key", m_context->reinhardKey/logLuminance);
m_reinhardTonemap->setParameter("multiplier", multiplier); m_reinhardTonemap->setParameter("multiplier", multiplier);
m_reinhardTonemap->setParameter("invWpSqr", std::pow((Float) 2, m_context->reinhardBurn)); m_reinhardTonemap->setParameter("invWpSqr", std::pow((Float) 2, m_context->reinhardBurn));
@ -904,7 +1009,6 @@ void GLWidget::paintGL() {
!m_hScroll->isVisible(), !m_vScroll->isVisible(), !m_hScroll->isVisible(), !m_vScroll->isVisible(),
-m_context->scrollOffset); -m_context->scrollOffset);
m_reinhardTonemap->unbind(); m_reinhardTonemap->unbind();
buffer->unbind();
} }
if (m_context->mode == EPreview) { if (m_context->mode == EPreview) {
@ -917,19 +1021,14 @@ void GLWidget::paintGL() {
} }
} }
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLint viewport[4]; GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport); glGetIntegerv(GL_VIEWPORT, viewport);
Vector2 scrSize(viewport[2], viewport[3]); if (viewport[2] > size.x || viewport[3] > size.y) {
if (scrSize.x > size.x || scrSize.y > size.y) {
/* Draw a border to highlight the region occupied by the image */ /* Draw a border to highlight the region occupied by the image */
Vector2i upperLeft((scrSize.x - size.x)/2, glMatrixMode(GL_MODELVIEW);
(scrSize.y - size.y)/2); glLoadIdentity();
Vector2i upperLeft((viewport[2] - size.x)/2, (viewport[3] - size.y)/2);
Vector2i lowerRight = upperLeft + Vector2i(size.x, size.y); Vector2i lowerRight = upperLeft + Vector2i(size.x, size.y);
glColor4f(0.4f, 0.4f, 0.4f, 1.0f); glColor4f(0.4f, 0.4f, 0.4f, 1.0f);
glBegin(GL_LINE_LOOP); glBegin(GL_LINE_LOOP);
glVertex2f(upperLeft.x, upperLeft.y); glVertex2f(upperLeft.x, upperLeft.y);
@ -939,10 +1038,81 @@ void GLWidget::paintGL() {
glEnd(); glEnd();
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
} }
if (m_context->mode == EPreview) {
const ProjectiveCamera *camera = static_cast<const ProjectiveCamera *>
(m_context->scene->getCamera());
m_renderer->setCamera(camera);
Point2i offset = upperLeft(true);
buffer->blit(NULL, GPUTexture::EDepthBuffer, Point2i(0, 0),
size, offset, size);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glViewport(offset.x, offset.y, size.x, size.y);
m_renderer->setDepthTest(true);
m_renderer->setDepthMask(false);
m_renderer->setBlendMode(Renderer::EBlendAdditive);
glDepthFunc(GL_LESS);
if (m_context->showKDTree) {
oglRenderKDTree(m_context->scene->getKDTree());
const std::vector<Shape *> shapes = m_context->scene->getShapes();
for (size_t j=0; j<shapes.size(); ++j)
if (shapes[j]->getKDTree())
oglRenderKDTree(shapes[j]->getKDTree());
}
if (m_navigationMode == EArcBall && m_gizmo->isActive())
m_gizmo->draw(m_renderer, camera);
m_renderer->setBlendMode(Renderer::EBlendNone);
m_renderer->setDepthTest(false);
m_renderer->setDepthMask(true);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
}
} }
swapBuffers(); swapBuffers();
} }
void GLWidget::oglRenderKDTree(const KDTreeBase<AABB> *kdtree) {
std::stack<boost::tuple<const KDTreeBase<AABB>::KDNode *, AABB, uint32_t> > stack;
stack.push(boost::make_tuple(kdtree->getRoot(), kdtree->getTightAABB(), 0));
Float brightness = 0.1f;
while (!stack.empty()) {
const KDTreeBase<AABB>::KDNode *node = boost::get<0>(stack.top());
AABB aabb = boost::get<1>(stack.top());
int level = boost::get<2>(stack.top());
stack.pop();
m_renderer->setColor(Spectrum(brightness));
m_renderer->drawAABB(aabb);
if (!node->isLeaf()) {
int axis = node->getAxis();
float split = node->getSplit();
if (level + 1 <= m_context->shownKDTreeLevel) {
Float tmp = aabb.max[axis];
aabb.max[axis] = split;
stack.push(boost::make_tuple(node->getLeft(), aabb, level+1));
aabb.max[axis] = tmp;
aabb.min[axis] = split;
stack.push(boost::make_tuple(node->getRight(), aabb, level+1));
} else {
aabb.min[axis] = split;
aabb.max[axis] = split;
Spectrum color;
color.fromLinearRGB(0, 0, 4*brightness);
m_renderer->setColor(color);
m_renderer->drawAABB(aabb);
}
}
}
}
void GLWidget::resizeEvent(QResizeEvent *event) { void GLWidget::resizeEvent(QResizeEvent *event) {
if (m_context && m_ignoreResizeEvents) { if (m_context && m_ignoreResizeEvents) {
event->accept(); event->accept();
@ -1052,6 +1222,18 @@ void GLWidget::onUpdateView() {
m_framebufferChanged = true; m_framebufferChanged = true;
} }
Point2i GLWidget::upperLeft(bool flipY) const {
if (!m_context)
return Point2i(0, 0);
Vector2i filmSize = m_context->scene->getCamera()->getFilm()->getSize();
Vector2i deviceSize = m_device->getSize();
return Point2i(
deviceSize.x < filmSize.x ? (-m_context->scrollOffset.x) : (deviceSize.x - filmSize.x)/2,
deviceSize.y < filmSize.y ? (flipY ? (deviceSize.y-filmSize.y
+ m_context->scrollOffset.y) : -m_context->scrollOffset.y) : (deviceSize.y - filmSize.y)/2);
}
void GLWidget::resizeGL(int width, int height) { void GLWidget::resizeGL(int width, int height) {
glViewport(0, 0, (GLint) width, (GLint) height); glViewport(0, 0, (GLint) width, (GLint) height);
m_device->setSize(Vector2i(width, height)); m_device->setSize(Vector2i(width, height));

View File

@ -28,6 +28,7 @@
#include <mitsuba/hw/gpuprogram.h> #include <mitsuba/hw/gpuprogram.h>
#include <mitsuba/hw/gpusync.h> #include <mitsuba/hw/gpusync.h>
#include <mitsuba/hw/vpl.h> #include <mitsuba/hw/vpl.h>
#include <mitsuba/hw/gizmo.h>
#if defined(WIN32) #if defined(WIN32)
#include <mitsuba/hw/wgldevice.h> #include <mitsuba/hw/wgldevice.h>
#endif #endif
@ -99,6 +100,8 @@ protected:
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event);
void dragEnterEvent(QDragEnterEvent *event); void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event); void dropEvent(QDropEvent *event);
void oglRenderKDTree(const KDTreeBase<AABB> *kdtree);
Point2i upperLeft(bool flipY = false) const;
/* Masquerade QGLWidget as a GL device for libhw */ /* Masquerade QGLWidget as a GL device for libhw */
#if defined(WIN32) #if defined(WIN32)
@ -130,6 +133,7 @@ private:
ref<GPUProgram> m_downsamplingProgram, m_luminanceProgram; ref<GPUProgram> m_downsamplingProgram, m_luminanceProgram;
ref<QtDevice> m_device; ref<QtDevice> m_device;
ref<Font> m_font; ref<Font> m_font;
ref<Gizmo> m_gizmo;
SceneContext *m_context; SceneContext *m_context;
bool m_framebufferChanged, m_mouseButtonDown; bool m_framebufferChanged, m_mouseButtonDown;
bool m_leftKeyDown, m_rightKeyDown; bool m_leftKeyDown, m_rightKeyDown;
@ -145,7 +149,9 @@ private:
bool m_ignoreScrollEvents, m_ignoreResizeEvents; bool m_ignoreScrollEvents, m_ignoreResizeEvents;
int m_mouseSensitivity, m_softwareFallback; int m_mouseSensitivity, m_softwareFallback;
ref<Bitmap> m_fallbackBitmap; ref<Bitmap> m_fallbackBitmap;
ref<Timer> m_wheelTimer;
QString m_errorString; QString m_errorString;
Transform m_storedViewTransform;
}; };
#endif /* __GLWIDGET_H */ #endif /* __GLWIDGET_H */

View File

@ -141,7 +141,7 @@ MainWindow::MainWindow(QWidget *parent) :
ui->glView->setInvertMouse(settings.value("invertMouse", false).toBool()); ui->glView->setInvertMouse(settings.value("invertMouse", false).toBool());
ui->glView->setMouseSensitivity(settings.value("mouseSensitivity", 3).toInt()); ui->glView->setMouseSensitivity(settings.value("mouseSensitivity", 3).toInt());
ui->glView->setNavigationMode((ENavigationMode) settings.value("navigationMode", ui->glView->setNavigationMode((ENavigationMode) settings.value("navigationMode",
EFlythrough).toInt()); EArcBall).toInt());
m_searchPaths = settings.value("searchPaths", QStringList()).toStringList(); m_searchPaths = settings.value("searchPaths", QStringList()).toStringList();
m_blockSize = settings.value("blockSize", 32).toInt(); m_blockSize = settings.value("blockSize", 32).toInt();
m_listenPort = settings.value("listenPort", MTS_DEFAULT_PORT).toInt(); m_listenPort = settings.value("listenPort", MTS_DEFAULT_PORT).toInt();
@ -1649,6 +1649,13 @@ QString ServerConnection::toString() const {
SceneContext::SceneContext(SceneContext *ctx) { SceneContext::SceneContext(SceneContext *ctx) {
if (ctx->scene) { if (ctx->scene) {
/* Temporarily set up a new file resolver */
ref<Thread> thread = Thread::getThread();
ref<FileResolver> oldResolver = thread->getFileResolver();
ref<FileResolver> newResolver = oldResolver->clone();
newResolver->addPath(fs::complete(ctx->scene->getSourceFile()).parent_path());
thread->setFileResolver(newResolver);
scene = new Scene(ctx->scene); scene = new Scene(ctx->scene);
ref<PluginManager> pluginMgr = PluginManager::getInstance(); ref<PluginManager> pluginMgr = PluginManager::getInstance();
ref<PinholeCamera> oldCamera = static_cast<PinholeCamera *>(ctx->scene->getCamera()); ref<PinholeCamera> oldCamera = static_cast<PinholeCamera *>(ctx->scene->getCamera());
@ -1696,6 +1703,7 @@ SceneContext::SceneContext(SceneContext *ctx) {
scene->configure(); scene->configure();
sceneResID = ctx->sceneResID; sceneResID = ctx->sceneResID;
Scheduler::getInstance()->retainResource(sceneResID); Scheduler::getInstance()->retainResource(sceneResID);
thread->setFileResolver(oldResolver);
} else { } else {
sceneResID = -1; sceneResID = -1;
renderJob = NULL; renderJob = NULL;
@ -1726,6 +1734,8 @@ SceneContext::SceneContext(SceneContext *ctx) {
diffuseSources = ctx->diffuseSources; diffuseSources = ctx->diffuseSources;
showKDTree = ctx->showKDTree; showKDTree = ctx->showKDTree;
shownKDTreeLevel = ctx->shownKDTreeLevel; shownKDTreeLevel = ctx->shownKDTreeLevel;
selectedShape = ctx->selectedShape;
selectionMode = ctx->selectionMode;
} }
SceneContext::~SceneContext() { SceneContext::~SceneContext() {

View File

@ -469,7 +469,7 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
m_shaderManager->setVPL(vpl); m_shaderManager->setVPL(vpl);
Point2 jitter(.5f, .5f); Point2 jitter(.5f, .5f);
if (!m_motion && !m_context->showKDTree) if (!m_motion && !m_context->showKDTree && m_accumBuffer != NULL)
jitter -= Vector2(m_random->nextFloat(), m_random->nextFloat()); jitter -= Vector2(m_random->nextFloat(), m_random->nextFloat());
m_mutex->lock(); m_mutex->lock();
@ -494,13 +494,6 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
m_shaderManager->unbind(); m_shaderManager->unbind();
} }
m_renderer->endDrawingMeshes(); m_renderer->endDrawingMeshes();
if (m_context->showKDTree) {
oglRenderKDTree(m_context->scene->getKDTree());
const std::vector<Shape *> shapes = m_context->scene->getShapes();
for (size_t j=0; j<shapes.size(); ++j)
if (shapes[j]->getKDTree())
oglRenderKDTree(shapes[j]->getKDTree());
}
m_shaderManager->drawBackground(clipToWorld, camPos); m_shaderManager->drawBackground(clipToWorld, camPos);
m_framebuffer->releaseTarget(); m_framebuffer->releaseTarget();
@ -511,6 +504,7 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
if (m_accumBuffer == NULL) { if (m_accumBuffer == NULL) {
target.buffer->clear(); target.buffer->clear();
m_renderer->blitTexture(m_framebuffer, true); m_renderer->blitTexture(m_framebuffer, true);
m_framebuffer->blit(target.buffer, GPUTexture::EDepthBuffer);
} else { } else {
m_accumBuffer->bind(1); m_accumBuffer->bind(1);
m_accumProgram->bind(); m_accumProgram->bind();
@ -519,9 +513,11 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
m_renderer->blitQuad(true); m_renderer->blitQuad(true);
m_accumProgram->unbind(); m_accumProgram->unbind();
m_accumBuffer->unbind(); m_accumBuffer->unbind();
m_accumBuffer->blit(target.buffer, GPUTexture::EDepthBuffer);
} }
m_framebuffer->unbind();
m_renderer->setDepthMask(true); m_renderer->setDepthMask(true);
m_framebuffer->unbind();
m_renderer->setDepthTest(true); m_renderer->setDepthTest(true);
target.buffer->releaseTarget(); target.buffer->releaseTarget();
m_accumBuffer = target.buffer; m_accumBuffer = target.buffer;
@ -542,42 +538,6 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
} }
} }
void PreviewThread::oglRenderKDTree(const KDTreeBase<AABB> *kdtree) {
std::stack<boost::tuple<const KDTreeBase<AABB>::KDNode *, AABB, uint32_t> > stack;
stack.push(boost::make_tuple(kdtree->getRoot(), kdtree->getTightAABB(), 0));
Float brightness = 10.0f;
while (!stack.empty()) {
const KDTreeBase<AABB>::KDNode *node = boost::get<0>(stack.top());
AABB aabb = boost::get<1>(stack.top());
int level = boost::get<2>(stack.top());
stack.pop();
m_renderer->setColor(Spectrum(brightness));
m_renderer->drawAABB(aabb);
if (!node->isLeaf()) {
int axis = node->getAxis();
float split = node->getSplit();
if (level + 1 <= m_context->shownKDTreeLevel) {
Float tmp = aabb.max[axis];
aabb.max[axis] = split;
stack.push(boost::make_tuple(node->getLeft(), aabb, level+1));
aabb.max[axis] = tmp;
aabb.min[axis] = split;
stack.push(boost::make_tuple(node->getRight(), aabb, level+1));
} else {
aabb.min[axis] = split;
aabb.max[axis] = split;
Spectrum color;
color.fromLinearRGB(0, 0, 2*brightness);
m_renderer->setColor(color);
m_renderer->drawAABB(aabb);
}
}
}
}
void PreviewThread::rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl) { void PreviewThread::rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
Float nearClip = std::numeric_limits<Float>::infinity(), Float nearClip = std::numeric_limits<Float>::infinity(),
farClip = -std::numeric_limits<Float>::infinity(); farClip = -std::numeric_limits<Float>::infinity();

View File

@ -74,8 +74,6 @@ protected:
virtual ~PreviewThread(); virtual ~PreviewThread();
/// Render a single VPL using OpenGL /// Render a single VPL using OpenGL
void oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl); void oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
/// Render a wireframe visualization of a kd-tree
void oglRenderKDTree(const KDTreeBase<AABB> *kdtree);
/// Render a single VPL using real-time coherent ray tracing /// Render a single VPL using real-time coherent ray tracing
void rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl); void rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
private: private:

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>378</width> <width>378</width>
<height>531</height> <height>533</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -455,12 +455,14 @@ movements while navigating in the realt-time preview.</string>
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body&gt; &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This option specifies the camera behavior when navigating within the realtime preview.&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This option specifies the camera behavior when navigating within the realtime preview.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Fly-through (Fix yaw)&lt;/span&gt;: Always yaw around a fixed &amp;quot;up&amp;quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Arcball&lt;/span&gt;: Rotate around the scene or the currently selected object.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Fly-through&lt;/span&gt;: Always yaw around the current camera &amp;quot;up&amp;quot; axis.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;First person (Fix yaw)&lt;/span&gt;: A first-person navigation mode that resembles walking through a scene (e.g. in a 3D game). This variant always yaws around a fixed &amp;quot;up&amp;quot; axis that is determined when the scene is loaded -- this is intuitive but assumes that the camera has already been set up correctly.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;First person&lt;/span&gt;: As above, but always yaw around the current camera &amp;quot;up&amp;quot; axis.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Navigation :</string> <string>Navigation :</string>
@ -476,21 +478,28 @@ p, li { white-space: pre-wrap; }
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body&gt; &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This option specifies the camera behavior when navigating within the realtime preview.&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This option specifies the camera behavior when navigating within the realtime preview.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Fly-through (Fix yaw)&lt;/span&gt;: Always yaw around a fixed &amp;quot;up&amp;quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Arcball&lt;/span&gt;: Rotate around the scene or the currently selected object.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Fly-through&lt;/span&gt;: Always yaw around the current camera &amp;quot;up&amp;quot; axis.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;First person (Fix yaw)&lt;/span&gt;: A first-person navigation mode that resembles walking through a scene (e.g. in a 3D game). This variant always yaws around a fixed &amp;quot;up&amp;quot; axis that is determined when the scene is loaded -- this is intuitive but assumes that the camera has already been set up correctly.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;First person&lt;/span&gt;: As above, but always yaw around the current camera &amp;quot;up&amp;quot; axis.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<item> <item>
<property name="text"> <property name="text">
<string>Fly-through (Fix yaw)</string> <string>Arcball</string>
</property> </property>
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>Fly-through</string> <string>First person (Fix yaw)</string>
</property>
</item>
<item>
<property name="text">
<string>First Person</string>
</property> </property>
</item> </item>
</widget> </widget>

View File

@ -19,6 +19,7 @@
#include "rendersettingsdlg.h" #include "rendersettingsdlg.h"
#include "ui_rendersettingsdlg.h" #include "ui_rendersettingsdlg.h"
#include <mitsuba/core/plugin.h> #include <mitsuba/core/plugin.h>
#include <mitsuba/core/fresolver.h>
/* ====================== Some helper routines ====================== */ /* ====================== Some helper routines ====================== */
@ -305,6 +306,13 @@ void RenderSettingsDialog::apply(SceneContext *ctx) {
Properties filmProps = oldCamera->getFilm()->getProperties(); Properties filmProps = oldCamera->getFilm()->getProperties();
ref<PluginManager> pluginMgr = PluginManager::getInstance(); ref<PluginManager> pluginMgr = PluginManager::getInstance();
/* Temporarily set up a new file resolver */
ref<Thread> thread = Thread::getThread();
ref<FileResolver> oldResolver = thread->getFileResolver();
ref<FileResolver> newResolver = oldResolver->clone();
newResolver->addPath(fs::complete(scene->getSourceFile()).parent_path());
thread->setFileResolver(newResolver);
/* Configure the reconstruction filter */ /* Configure the reconstruction filter */
Properties rFilterProps(getPluginName(ui->rFilterBox)); Properties rFilterProps(getPluginName(ui->rFilterBox));
if (m_rFilterNode != NULL) if (m_rFilterNode != NULL)
@ -384,6 +392,7 @@ void RenderSettingsDialog::apply(SceneContext *ctx) {
scene->configure(); scene->configure();
ctx->scene = scene; ctx->scene = scene;
thread->setFileResolver(oldResolver);
} }
RenderSettingsDialog::~RenderSettingsDialog() { RenderSettingsDialog::~RenderSettingsDialog() {