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
bl_addon_info = {
bl_info = {
"name": "Mitsuba",
"author": "Wenzel Jakob",
"version": (0, 1),
"blender": (2, 5, 5),
"api": 31667,
"version": (0, 2, 1),
"blender": (2, 5, 6),
"api": 35669,
"category": "Render",
"location": "Render > Engine > Mitsuba",
"description": "Basic Mitsuba integration for Blender",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
"Scripts/Render/Mitsuba",
"tracker_url": "https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba",
"category": "Render"}
"tracker_url": "https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba"}
def plugin_path():
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
from extensions_framework import Addon
MitsubaAddon = Addon(bl_info)
register, unregister = MitsubaAddon.init_functions()
def register():
RENDERENGINE_mitsuba.install()
def unregister():
RENDERENGINE_mitsuba.uninstall()
# Importing the core package causes extensions_framework managed
# RNA class registration via @MitsubaAddon.addon_register_class
from . import core

View File

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

View File

@ -20,51 +20,46 @@
import os, sys, copy, subprocess, traceback, string
# Blender Libs
import bpy
from presets import AddPresetBase
import bpy, bl_operators
# Extensions_Framework Libs
from extensions_framework import util as efutil
from mitsuba.outputs import MtsLog
from mitsuba.export.adjustments import MtsAdjustments
from .. import MitsubaAddon
from ..outputs import MtsLog
from ..export.adjustments import MtsAdjustments
def try_preset_path_create(preset_subdir):
target_path = os.path.join(bpy.utils.preset_paths('')[0], preset_subdir)
if not os.path.exists(target_path):
os.makedirs(target_path)
class MITSUBA_MT_base(object):
class MITSUBA_MT_base(bpy.types.Menu):
preset_operator = "script.execute_preset"
def draw(self, context):
try_preset_path_create(self.preset_subdir)
return bpy.types.Menu.draw_preset(self, context)
return self.draw_preset(context)
class MITSUBA_OT_preset_base(AddPresetBase):
def execute(self, context):
try_preset_path_create(self.preset_subdir)
return super().execute(context)
class MITSUBA_MT_presets_engine(MITSUBA_MT_base, bpy.types.Menu):
@MitsubaAddon.addon_register_class
class MITSUBA_MT_presets_engine(MITSUBA_MT_base):
bl_label = "Mitsuba Engine Presets"
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'''
bl_idname = 'mitsuba.preset_engine_add'
bl_label = 'Add Mitsuba Engine settings preset'
preset_menu = 'MITSUBA_MT_presets_engine'
preset_values = [
'bpy.context.scene.mitsuba_engine.%s'%v['attr'] for v in bpy.types.mitsuba_engine.get_exportable_properties()
]
preset_subdir = 'mitsuba/engine'
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"
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'''
bl_idname = 'mitsuba.preset_texture_add'
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
return super().execute(context)
class MITSUBA_MT_presets_material(MITSUBA_MT_base, bpy.types.Menu):
@MitsubaAddon.addon_register_class
class MITSUBA_MT_presets_material(MITSUBA_MT_base):
bl_label = "Mitsuba Material Presets"
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'''
bl_idname = 'mitsuba.preset_material_add'
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
return super().execute(context)
@MitsubaAddon.addon_register_class
class EXPORT_OT_mitsuba(bpy.types.Operator):
bl_idname = 'export.mitsuba'
bl_label = 'Export Mitsuba Scene (.xml)'
@ -215,6 +212,7 @@ def menu_func(self, context):
bpy.types.INFO_MT_file_export.append(menu_func)
@MitsubaAddon.addon_register_class
class MITSUBA_OT_material_slot_move(bpy.types.Operator):
''' Rearrange the material slots '''
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
return {'FINISHED'}
@MitsubaAddon.addon_register_class
class MITSUBA_OT_material_add(bpy.types.Operator):
''' Append a new material '''
bl_idname = 'mitsuba.material_add'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,14 +16,16 @@
#
# ##### END GPL LICENSE BLOCK #####
import bpy
from properties_data_lamp import DataButtonsPanel
import bpy, bl_ui
from .. import MitsubaAddon
from extensions_framework.ui import property_group_renderer
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'
COMPAT_ENGINES = {'mitsuba'}

View File

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

View File

@ -17,10 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
import bpy
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_sub
from mitsuba.ui.materials import mitsuba_material_sub
from properties_material import active_node_mat
@MitsubaAddon.addon_register_class
class ui_material_composite(mitsuba_material_sub, bpy.types.Panel):
bl_label = 'Mitsuba Composite Material'
@ -33,7 +33,7 @@ class ui_material_composite(mitsuba_material_sub, bpy.types.Panel):
def draw(self, 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
missing = False
selfRef = False

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
bl_label = 'Mitsuba Dielectric Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
bl_label = 'Mitsuba Diffuse Transmitter Material'

View File

@ -16,11 +16,11 @@
#
# ##### END GPL LICENSE BLOCK #####
import bpy
from mitsuba.ui.materials import mitsuba_material_base
from properties_material import active_node_mat
import bpy, bl_ui
from ... import MitsubaAddon
from ...ui.materials import mitsuba_material_base
@MitsubaAddon.addon_register_class
class emission(mitsuba_material_base, bpy.types.Panel):
'''
Material Emission Settings
@ -39,6 +39,6 @@ class emission(mitsuba_material_base, bpy.types.Panel):
def draw_header(self, context):
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.validate(context)

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
bl_label = 'Mitsuba Lambertian Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
'''
Material Editor UI Panel

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
bl_label = 'Mitsuba Microfacet Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
bl_label = 'Mitsuba Mirror Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
bl_label = 'Mitsuba Phong Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
bl_label = 'Mitsuba Rough Glass Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
bl_label = 'Mitsuba Rough Metal Material'

View File

@ -17,9 +17,10 @@
# ##### END GPL LICENSE BLOCK #####
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):
bl_label = 'Mitsuba Ward Material'

View File

@ -16,22 +16,24 @@
#
# ##### END GPL LICENSE BLOCK #####
import os, bpy
from properties_render import RenderButtonsPanel
import os, bpy, bl_ui
from .. import MitsubaAddon
from extensions_framework.ui import property_group_renderer
from extensions_framework import util as efutil
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
'''
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
'''
@ -46,7 +48,8 @@ class setup_preset(render_described_context, bpy.types.Panel):
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
'''
@ -71,7 +74,8 @@ class engine(render_described_context, bpy.types.Panel):
efutil.write_config_value('mitsuba', 'defaults', 'binary_path', binary_path)
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
'''
@ -82,8 +86,8 @@ class integrator(render_described_context, bpy.types.Panel):
( ('scene',), 'mitsuba_integrator' )
]
class sampler(render_described_context, bpy.types.Panel):
@MitsubaAddon.addon_register_class
class sampler(render_panel, bpy.types.Panel):
'''
Sampler settings UI Panel
'''

View File

@ -16,17 +16,17 @@
#
# ##### END GPL LICENSE BLOCK #####
import bpy
from properties_texture import TextureButtonsPanel
from properties_texture import context_tex_datablock
import bpy, bl_ui
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_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {'mitsuba'}
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
@classmethod
def poll(cls, context):
@ -42,7 +42,7 @@ class TEXTURE_PT_context_texture_mts(TextureButtonsPanel, bpy.types.Panel):
node = context.texture_node
space = context.space_data
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
if tex_collection:
@ -70,12 +70,12 @@ class TEXTURE_PT_context_texture_mts(TextureButtonsPanel, bpy.types.Panel):
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.
'''
COMPAT_ENGINES = {'mitsuba'}
COMPAT_ENGINES = { MitsubaAddon.BL_IDNAME }
MTS_COMPAT = set()
@classmethod

View File

@ -18,8 +18,10 @@
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):
bl_label = 'Mitsuba Checkerboard Texture'

View File

@ -18,8 +18,10 @@
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):
bl_label = 'Mitsuba Grid Texture'

View File

@ -18,8 +18,10 @@
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):
bl_label = 'Mitsuba Bitmap Texture'

View File

@ -18,8 +18,10 @@
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):
'''
Texture Editor UI Panel

View File

@ -18,8 +18,10 @@
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):
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
void setParameter(int id, Float value);
/// Set a integer parameter
void setParameter(int id, int value);
/// Set a Vector parameter
void setParameter(int id, const Vector &value);
@ -97,7 +100,7 @@ public:
/** Set a GPUTexture parameter. Must be executed after
binding the texture to a texture unit */
void setParameter(int id, const GPUTexture *value);
void setParameter(int id, const GPUTexture *value);
MTS_DECLARE_CLASS()
protected:

View File

@ -102,6 +102,13 @@ public:
bool centerHoriz = true, bool centerVert = true,
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
void endDrawingMeshes();

View File

@ -39,9 +39,19 @@ public:
/// Free the texture from GPU memory
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)
void download(Bitmap *bitmap = NULL);
@ -61,8 +71,35 @@ public:
/// Deactivate the render target
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)
void clear();
@ -86,9 +123,7 @@ protected:
GLuint m_format;
GLuint m_internalFormat;
GLuint m_dataFormat;
/* For render targets */
GLuint m_fboId, m_depthId;
GLuint m_extraId;
mutable bool m_needsUpdate;
};

View File

@ -72,6 +72,12 @@ public:
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
inline void setParameter(const std::string &name, Float value,
bool failIfMissing = true) {
@ -181,6 +187,9 @@ public:
/// Set a float parameter
virtual void setParameter(int id, Float value) = 0;
/// Set a int parameter
virtual void setParameter(int id, int value) = 0;
/// Set a Vector parameter
virtual void setParameter(int id, const Vector &value) = 0;

View File

@ -32,7 +32,7 @@ public:
/// Available texture types
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
*/
ETexture1D = 0,
@ -48,16 +48,22 @@ public:
};
/** \brief If the texture type is set to EFrameBuffer, the
* configuration must be specified */
* configuration must be one of the following constants */
enum EFrameBufferType {
/// 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)
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
@ -260,8 +266,18 @@ public:
/// Free the texture from GPU memory
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
virtual void unbind() const = 0;
@ -294,8 +310,35 @@ public:
/// Return the number of samples (for multisample color render targets)
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)
virtual void clear() = 0;

View File

@ -76,9 +76,9 @@ class MTS_EXPORT_HW Renderer : public Object {
public:
/* Possible blending modes */
enum EBlendMode {
EBlendNone, // Blending turned off
EBlendAlpha, // Normal alpha blending
EBlendAdditive // Additive blending
EBlendNone, // Blending turned off
EBlendAlpha, // Normal alpha blending
EBlendAdditive // Additive blending
};
/* Possible culling modes */
@ -162,6 +162,14 @@ public:
bool centerHoriz = true, bool centerVert = true,
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
virtual void blitQuad(bool flipVertically) = 0;

View File

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

View File

@ -4,7 +4,7 @@ libhw_objects = [
'session.cpp', 'device.cpp', 'gputexture.cpp', 'gpugeometry.cpp',
'gpuprogram.cpp', 'renderer.cpp', 'glrenderer.cpp', 'glprogram.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':
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);
}
void GLProgram::setParameter(int id, int value) {
if (id == -1)
return;
glUniform1i(id, value);
}
void GLProgram::setParameter(int id, const Vector &value) {
if (id == -1)
return;

View File

@ -741,6 +741,51 @@ void GLRenderer::blitQuad(bool flipVertically) {
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,
const Font *font, const std::string &text) {
int viewport[4];

View File

@ -31,7 +31,7 @@
MTS_NAMESPACE_BEGIN
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() {
@ -48,11 +48,25 @@ void GLTexture::init() {
/* Bind to the texture */
glBindTexture(m_glType, m_id);
/* Set the texture filtering / wrapping modes */
if (!(m_fbType == EColorBuffer && m_samples > 1))
/* Set the texture filtering / wrapping modes
(don't do this for multisample textures)*/
if (!((m_fbType & EColorBuffer) && m_samples > 1))
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) {
Assert(m_samples == 1);
refresh();
} else {
/* Create the FBO and bind it */
@ -60,64 +74,73 @@ void GLTexture::init() {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboId);
AssertEx(glIsFramebufferEXT(m_fboId), "Creating an FBO failed");
bool depthAsTexture = m_fbType & EDepthBuffer;
switch (m_fbType) {
case EColorAndDepthBuffer:
case EColorBuffer: {
if (m_type == ETexture2D) {
/* Create a depth buffer */
glGenRenderbuffersEXT(1, &m_depthId);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthId);
if (m_samples == 1) {
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
GL_DEPTH_COMPONENT, m_size.x, m_size.y);
/* Allocate the texture memory */
glTexImage2D(m_glType, 0, m_internalFormat, m_size.x, m_size.y,
0, m_format, m_dataFormat, NULL);
if (!depthAsTexture) {
glGenRenderbuffersEXT(1, &m_depthId);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthId);
if (m_samples == 1)
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
GL_DEPTH_COMPONENT, m_size.x, m_size.y);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT,
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 {
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,
m_samples, GL_DEPTH_COMPONENT, m_size.x, m_size.y);
glTexImage2DMultisample(m_glType,
m_samples, m_internalFormat, m_size.x, m_size.y, GL_FALSE);
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,
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())
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,
GL_COLOR_ATTACHMENT0_EXT, m_glType, m_id, 0);
} else if (m_type == ETextureCubeMap) {
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++)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat, m_size.x, m_size.y,
0, m_format, m_dataFormat, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat,
m_size.x, m_size.y, 0, m_format, m_dataFormat, NULL);
if (isMipMapped())
glGenerateMipmapEXT(m_glType);
/* Generate an identifier */
glGenTextures(1, &m_extraId);
glBindTexture(m_glType, m_extraId);
glGenTextures(1, &m_depthId);
glBindTexture(m_glType, m_depthId);
glTexParameteri(m_glType, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(m_glType, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
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,
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT24,
m_size.x, m_size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
if (glewIsSupported("GL_EXT_geometry_shader4"))
activateSide(-1);
@ -147,8 +170,8 @@ void GLTexture::init() {
} else if (m_type == ETextureCubeMap) {
Assert(m_size.x == m_size.y && isPowerOfTwo(m_size.x));
for (int i=0; i<6; i++)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat, m_size.x, m_size.y,
0, m_format, m_dataFormat, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, m_internalFormat,
m_size.x, m_size.y, 0, m_format, m_dataFormat, NULL);
if (glewIsSupported("GL_EXT_geometry_shader4"))
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,
0, m_format, m_dataFormat, bitmap->getData());
@ -480,19 +497,23 @@ void GLTexture::activateSide(int side) {
if (side == -1) {
if (m_fbType == EColorBuffer) {
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_id, 0);
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_extraId, 0);
} else {
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_depthId, 0);
} else if (m_fbType == EDepthBuffer) {
glFramebufferTextureEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_id, 0);
} else {
Log(EError, "Unsupported framebuffer type!");
}
} else {
if (m_fbType == EColorBuffer) {
//glFramebufferTextureFaceEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, m_id, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side);
//glFramebufferTextureFaceEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_extraId, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side);
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, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_extraId, 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,
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 {
//glFramebufferTextureFaceEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, m_id, 0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + side, m_id, 0);
Log(EError, "Unsupported framebuffer type!");
}
}
}
@ -509,16 +530,21 @@ void GLTexture::releaseTarget() {
m_needsUpdate = true;
}
void GLTexture::bind(int textureUnit) const {
void GLTexture::bind(int textureUnit, int textureIndex) const {
/* Bind to the texture */
if (GLEW_VERSION_1_3) {
m_textureUnits.get().insert(textureUnit);
glActiveTexture(GL_TEXTURE0 + textureUnit);
} else {
AssertEx(textureUnit == 0, "Multitexture is not supported");
if (textureUnit != 0)
Log(EError, "Multitexturing is not supported");
}
glEnable(m_glType);
glBindTexture(m_glType, m_id);
if (textureIndex == 1 && m_fbType == EColorAndDepthBuffer)
glBindTexture(m_glType, m_depthId);
else
glBindTexture(m_glType, m_id);
if (isMipMapped() && m_needsUpdate) {
glGenerateMipmapEXT(m_glType);
@ -530,7 +556,7 @@ void GLTexture::unbind() const {
if (GLEW_VERSION_1_3) {
std::set<int> &textureUnits = m_textureUnits.get();
for (std::set<int>::iterator it = textureUnits.begin();
it != textureUnits.end(); ++it) {
it != textureUnits.end(); ++it) {
glActiveTexture(GL_TEXTURE0 + *it);
glDisable(m_glType);
}
@ -545,41 +571,85 @@ void GLTexture::cleanup() {
return;
if (m_fbType != ENone) {
Log(ETrace, "Freeing framebuffer \"%s\"", m_name.c_str());
switch (m_fbType) {
case EColorBuffer:
glDeleteRenderbuffersEXT(1, &m_depthId);
break;
case EDepthBuffer:
break;
default:
Log(EError, "Invalid framebuffer type!");
if (m_fbType == EColorAndDepthBuffer || (m_fbType == EColorBuffer && m_type == ETextureCubeMap)) {
glDeleteTextures(1, &m_depthId);
} else if (m_fbType == EColorBuffer) {
glDeleteRenderbuffersEXT(1, &m_depthId);
}
glDeleteFramebuffersEXT(1, &m_fboId);
} else {
Log(ETrace, "Freeing texture \"%s\"", m_name.c_str());
}
glDeleteTextures(1, &m_id);
m_id = 0;
if (m_extraId != 0) {
glDeleteTextures(1, &m_extraId);
m_extraId = 0;
}
}
void GLTexture::blit(GPUTexture *texture) const {
GLTexture *dest = static_cast<GLTexture *>(texture);
void GLTexture::blit(GPUTexture *target, int what) const {
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_DRAW_FRAMEBUFFER_EXT, dest->m_fboId);
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);
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,
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() {
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() {

View File

@ -87,6 +87,7 @@ void GPUTexture::setFrameBufferType(EFrameBufferType type) {
switch (m_fbType) {
case EColorBuffer:
case EColorAndDepthBuffer:
break;
case EDepthBuffer:
m_format = EDepth;
@ -164,6 +165,7 @@ static const char *toString(GPUTexture::EFrameBufferType fbType) {
case GPUTexture::ENone: return "none";
case GPUTexture::EDepthBuffer: return "depthBuffer";
case GPUTexture::EColorBuffer: return "colorBuffer";
case GPUTexture::EColorAndDepthBuffer: return "colorAndDepthBuffer";
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
<< endl
<< "void main() {" << endl
<< " vec3 p0 = gl_PositionIn[0].xyz / gl_PositionIn[0].w;" << endl
<< " vec3 p1 = gl_PositionIn[1].xyz / gl_PositionIn[1].w;" << endl
<< " vec3 p2 = gl_PositionIn[2].xyz / gl_PositionIn[2].w;" << endl
<< " normal = normalize(cross(p1 - p0, p2 - p0));" << endl
<< " vec3 edge1 = camVec_vertex[0]-camVec_vertex[1];" << endl
<< " vec3 edge2 = camVec_vertex[0]-camVec_vertex[2];" << endl
<< " normal = normalize(cross(edge1, edge2));" << endl
<< " gl_Position = vec4(0.0);" << endl
<< " lightVec = camVec = vec3(0.0);" << endl
<< " for (int i=0; i<gl_VerticesIn; ++i) {" << endl

View File

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

View File

@ -38,12 +38,14 @@ GLWidget::GLWidget(QWidget *parent) :
m_movementTimer = new QTimer(parent);
m_movementTimer->setInterval(20);
m_movementTimer->setSingleShot(false);
m_wheelTimer = new Timer();
m_redrawTimer = new QTimer(parent);
m_redrawTimer->setInterval(200);
connect(m_movementTimer, SIGNAL(timeout()), this, SLOT(timerImpulse()));
connect(m_redrawTimer, SIGNAL(timeout()), this, SLOT(updateGL()));
m_renderer = Renderer::create(NULL);
m_device = new QtDevice(this);
m_gizmo = new Gizmo();
m_preview = new PreviewThread(m_device, m_renderer);
connect(m_preview, SIGNAL(caughtException(const QString &)),
this, SLOT(onException(const QString &)), Qt::QueuedConnection);
@ -114,6 +116,9 @@ void GLWidget::initializeGL() {
if (!m_renderer->getCapabilities()->isSupported(
RendererCapabilities::EVertexBufferObjects))
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 !defined(MTS_GUI_SOFTWARE_FALLBACK)
@ -149,6 +154,7 @@ void GLWidget::initializeGL() {
);
m_gammaTonemap->setSource(GPUProgram::EFragmentProgram,
"#version 120\n"
"uniform sampler2D source;\n"
"uniform float invWhitePoint, invGamma;\n"
"uniform bool sRGB;\n"
@ -162,7 +168,7 @@ void GLWidget::initializeGL() {
"void main() {\n"
" vec4 color = texture2D(source, gl_TexCoord[0].xy) * invWhitePoint;\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"
" gl_FragColor = vec4(pow(color.rgb, vec3(invGamma)), 1);\n"
"}\n"
@ -176,6 +182,7 @@ void GLWidget::initializeGL() {
);
m_reinhardTonemap->setSource(GPUProgram::EFragmentProgram,
"#version 120\n"
"uniform sampler2D source;\n"
"uniform float key, invWpSqr, invGamma, multiplier;\n"
"uniform bool sRGB;\n"
@ -288,6 +295,9 @@ void GLWidget::initializeGL() {
m_logoTexture->init();
m_font->init(m_renderer);
m_redrawTimer->start();
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glLineWidth(0.6f);
}
void GLWidget::setScene(SceneContext *context) {
@ -301,6 +311,7 @@ void GLWidget::setScene(SceneContext *context) {
m_framebufferChanged = true;
m_mouseButtonDown = false;
m_leftKeyDown = m_rightKeyDown = m_upKeyDown = m_downKeyDown = false;
m_gizmo->reset();
updateGeometry();
updateScrollBars();
updateGL();
@ -509,7 +520,8 @@ void GLWidget::resetPreview() {
if (!m_context || !m_context->scene || !m_preview->isRunning())
return;
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);
updateGL();
}
@ -522,22 +534,50 @@ void GLWidget::keyPressEvent(QKeyEvent *event) {
if (event->isAutoRepeat() || !m_context)
return;
PinholeCamera *camera = static_cast<PinholeCamera *>(m_context->scene->getCamera());
switch (event->key()) {
case Qt::Key_PageUp: m_context->movementScale *= 2; break;
case Qt::Key_PageDown: m_context->movementScale /= 2; break;
case Qt::Key_A:
case Qt::Key_Left:
m_leftKeyDown = true; break;
case Qt::Key_D:
case Qt::Key_Right:
m_rightKeyDown = true; break;
case Qt::Key_W:
case Qt::Key_Up:
m_upKeyDown = true; break;
case Qt::Key_S:
case Qt::Key_Down:
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)) {
m_clock->reset();
@ -549,16 +589,12 @@ void GLWidget::keyReleaseEvent(QKeyEvent *event) {
if (event->isAutoRepeat() || !m_context || !m_preview->isRunning())
return;
switch (event->key()) {
case Qt::Key_A:
case Qt::Key_Left:
m_leftKeyDown = false; break;
case Qt::Key_D:
case Qt::Key_Right:
m_rightKeyDown = false; break;
case Qt::Key_W:
case Qt::Key_Up:
m_upKeyDown = false; break;
case Qt::Key_S:
case Qt::Key_Down:
m_downKeyDown = false; break;
case Qt::Key_BracketLeft:
@ -589,7 +625,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
return;
QPoint previousPos = m_mousePos,
rel = event->pos() - m_mousePos;
rel = event->pos() - m_mousePos;
m_mousePos = event->pos();
if (!m_context || !m_context->scene || !m_mouseButtonDown || rel == QPoint(0,0))
@ -601,7 +637,7 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
return;
}
if (!m_didSetCursor) {
if (!m_didSetCursor && !(m_navigationMode == EArcBall && event->buttons() & Qt::LeftButton)) {
QApplication::setOverrideCursor(Qt::BlankCursor);
m_didSetCursor = true;
}
@ -610,54 +646,66 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
Point p = camera->getInverseViewTransform()(Point(0,0,0));
Vector direction = camera->getInverseViewTransform()(Vector(0,0,1));
Vector up;
if (m_navigationMode == EFlythrough)
up = camera->getInverseViewTransform()(Vector(0,1,0));
else if (m_navigationMode == EFlythroughFixedYaw)
up = m_context->up;
else
SLog(EError, "Unknown navigation mode encountered!");
bool didMove = false;
if (event->buttons() & Qt::LeftButton) {
Float yaw = -.03f * rel.x() * m_mouseSensitivity;
Float pitch = -.03f * rel.y() * m_mouseSensitivity;
if (m_invertMouse)
pitch *= -1;
Transform trafo = Transform::rotate(Vector(0,1,0), yaw)
* Transform::rotate(Vector(1,0,0), pitch)
* camera->getViewTransform();
direction = trafo.inverse()(Vector(0,0,1));
if (camera->getViewTransform().det3x3() < 0) {
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, up));
} else {
camera->setInverseViewTransform(
Transform::lookAt(p, p+direction, up) *
Transform::scale(Vector(-1,1,1))
);
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;
}
didMove = true;
}
} else {
if (m_navigationMode == EFlythrough)
up = camera->getInverseViewTransform()(Vector(0,1,0));
else if (m_navigationMode == EFlythroughFixedYaw)
up = m_context->up;
else
SLog(EError, "Unknown navigation mode encountered!");
if (event->buttons() & Qt::RightButton) {
Float roll = rel.x() * m_mouseSensitivity * .02f;
Float fovChange = rel.y() * m_mouseSensitivity * .03f;
if (event->buttons() & Qt::LeftButton) {
Float yaw = -.03f * rel.x() * m_mouseSensitivity;
Float pitch = -.03f * rel.y() * m_mouseSensitivity;
if (m_invertMouse)
pitch *= -1;
if (camera->getViewTransform().det3x3() < 0) {
m_context->up = Transform::rotate(direction, roll)(up);
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, m_context->up));
} else {
m_context->up = Transform::rotate(direction, -roll)(up);
camera->setInverseViewTransform(
Transform::lookAt(p, p+direction, m_context->up) *
Transform::scale(Vector(-1,1,1))
);
Transform trafo = Transform::rotate(Vector(0,1,0), yaw)
* Transform::rotate(Vector(1,0,0), pitch)
* camera->getViewTransform();
direction = trafo.inverse()(Vector(0,0,1));
if (camera->getViewTransform().det3x3() < 0) {
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, up));
} else {
camera->setInverseViewTransform(
Transform::lookAt(p, p+direction, up) *
Transform::scale(Vector(-1,1,1))
);
}
didMove = true;
}
camera->setFov(std::min(std::max((Float) 1.0f, camera->getFov() + fovChange), (Float) 100.0f));
if (event->buttons() & Qt::RightButton) {
Float roll = rel.x() * m_mouseSensitivity * .02f;
Float fovChange = rel.y() * m_mouseSensitivity * .03f;
if (camera->getViewTransform().det3x3() < 0) {
m_context->up = Transform::rotate(direction, roll)(up);
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, m_context->up));
} else {
m_context->up = Transform::rotate(direction, -roll)(up);
camera->setInverseViewTransform(
Transform::lookAt(p, p+direction, m_context->up) *
Transform::scale(Vector(-1,1,1))
);
}
camera->setFov(std::min(std::max((Float) 1.0f, camera->getFov() + fovChange), (Float) 100.0f));
}
camera->configure();
didMove = true;
@ -671,15 +719,17 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
didMove = true;
}
QPoint global = mapToGlobal(m_mousePos);
QDesktopWidget *desktop = QApplication::desktop();
if (m_navigationMode != EArcBall) {
QPoint global = mapToGlobal(m_mousePos);
QDesktopWidget *desktop = QApplication::desktop();
if (global.x() < 50 || global.y() < 50 ||
global.x() > desktop->width()-50 ||
global.y() > desktop->height()-50) {
QPoint target(desktop->width()/2, desktop->height()/2);
m_ignoreMouseEvent = target - global;
QCursor::setPos(target);
if (global.x() < 50 || global.y() < 50 ||
global.x() > desktop->width()-50 ||
global.y() > desktop->height()-50) {
QPoint target(desktop->width()/2, desktop->height()/2);
m_ignoreMouseEvent = target - global;
QCursor::setPos(target);
}
}
if (didMove)
@ -689,22 +739,45 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
void GLWidget::wheelEvent(QWheelEvent *event) {
QScrollBar *bar = event->orientation() == Qt::Vertical
? m_vScroll : m_hScroll;
if (!bar->isVisible() || !m_preview->isRunning())
if (!m_preview->isRunning())
return;
int oldStep = bar->singleStep();
bar->setSingleStep(event->delta()/4);
if (bar->isVisible()) {
int oldStep = bar->singleStep();
bar->setSingleStep(event->delta()/4);
#if defined(__OSX__)
/* Support two-finger swipes */
if (std::abs(event->delta()) < 8*15)
bar->setSingleStep(event->delta());
/* Support two-finger swipes */
if (std::abs(event->delta()) < 8*15)
bar->setSingleStep(event->delta());
#endif
bar->triggerAction(event->delta() > 0 ?
QAbstractSlider::SliderSingleStepSub
: QAbstractSlider::SliderSingleStepAdd);
bar->setSingleStep(oldStep);
bar->triggerAction(event->delta() > 0 ?
QAbstractSlider::SliderSingleStepSub
: QAbstractSlider::SliderSingleStepAdd);
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();
}
@ -714,6 +787,37 @@ void GLWidget::mousePressEvent(QMouseEvent *event) {
m_mousePos = event->pos();
m_initialMousePos = mapToGlobal(m_mousePos);
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) {
@ -721,17 +825,20 @@ void GLWidget::mouseReleaseEvent(QMouseEvent *event) {
return;
if (event->buttons() == 0) {
m_mouseButtonDown = false;
if (m_didSetCursor) {
resetPreview();
QApplication::restoreOverrideCursor();
QCursor::setPos(m_initialMousePos);
m_didSetCursor = false;
} else if (m_gizmo->isDragging()) {
m_gizmo->stopDrag();
resetPreview();
}
}
}
void GLWidget::paintGL() {
m_renderer->setDepthMask(false);
m_renderer->setDepthTest(false);
if (m_context == NULL) {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
@ -740,7 +847,7 @@ void GLWidget::paintGL() {
m_renderer->blitTexture(m_logoTexture);
m_renderer->setBlendMode(Renderer::EBlendNone);
} else if (m_context != NULL) {
Point3i size;
Vector2i size;
glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
PreviewQueueEntry entry;
@ -753,14 +860,15 @@ void GLWidget::paintGL() {
return;
}
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);
if (entry.buffer == NULL) {
/* Unsuccessful at acquiring a buffer in the
alloted time - just leave and keep the current display */
return;
}
size = entry.buffer->getSize();
size = Vector2i(entry.buffer->getSize().x, entry.buffer->getSize().y);
buffer = entry.buffer;
} else if (m_context->mode == ERender) {
if (m_framebuffer == NULL ||
@ -806,7 +914,7 @@ void GLWidget::paintGL() {
m_framebufferChanged = false;
}
size = m_framebuffer->getSize();
size = Vector2i(m_framebuffer->getSize().x, m_framebuffer->getSize().y);
buffer = m_framebuffer;
}
@ -822,9 +930,8 @@ void GLWidget::paintGL() {
if (m_context->mode == EPreview)
invWhitePoint /= entry.vplSampleOffset;
buffer->bind();
m_gammaTonemap->bind();
m_gammaTonemap->setParameter("source", buffer);
m_gammaTonemap->setParameter("source", 0);
m_gammaTonemap->setParameter("invWhitePoint", invWhitePoint);
m_gammaTonemap->setParameter("invGamma", 1/m_context->gamma);
m_gammaTonemap->setParameter("sRGB", m_context->srgb);
@ -832,7 +939,6 @@ void GLWidget::paintGL() {
!m_hScroll->isVisible(), !m_vScroll->isVisible(),
-m_context->scrollOffset);
m_gammaTonemap->unbind();
buffer->unbind();
} else if (m_context->toneMappingMethod == EReinhard) {
if (m_luminanceBuffer[0] == NULL || m_luminanceBuffer[0]->getSize() != Point3i(size.x, size.y, 1)) {
for (int i=0; i<2; ++i) {
@ -892,9 +998,8 @@ void GLWidget::paintGL() {
logLuminance = 1;
}
buffer->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("multiplier", multiplier);
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_context->scrollOffset);
m_reinhardTonemap->unbind();
buffer->unbind();
}
if (m_context->mode == EPreview) {
@ -917,19 +1021,14 @@ void GLWidget::paintGL() {
}
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
Vector2 scrSize(viewport[2], viewport[3]);
if (scrSize.x > size.x || scrSize.y > size.y) {
if (viewport[2] > size.x || viewport[3] > size.y) {
/* Draw a border to highlight the region occupied by the image */
Vector2i upperLeft((scrSize.x - size.x)/2,
(scrSize.y - size.y)/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Vector2i upperLeft((viewport[2] - size.x)/2, (viewport[3] - size.y)/2);
Vector2i lowerRight = upperLeft + Vector2i(size.x, size.y);
glColor4f(0.4f, 0.4f, 0.4f, 1.0f);
glBegin(GL_LINE_LOOP);
glVertex2f(upperLeft.x, upperLeft.y);
@ -939,10 +1038,81 @@ void GLWidget::paintGL() {
glEnd();
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();
}
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) {
if (m_context && m_ignoreResizeEvents) {
event->accept();
@ -1052,6 +1222,18 @@ void GLWidget::onUpdateView() {
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) {
glViewport(0, 0, (GLint) width, (GLint) height);
m_device->setSize(Vector2i(width, height));

View File

@ -28,6 +28,7 @@
#include <mitsuba/hw/gpuprogram.h>
#include <mitsuba/hw/gpusync.h>
#include <mitsuba/hw/vpl.h>
#include <mitsuba/hw/gizmo.h>
#if defined(WIN32)
#include <mitsuba/hw/wgldevice.h>
#endif
@ -99,6 +100,8 @@ protected:
void wheelEvent(QWheelEvent *event);
void dragEnterEvent(QDragEnterEvent *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 */
#if defined(WIN32)
@ -130,6 +133,7 @@ private:
ref<GPUProgram> m_downsamplingProgram, m_luminanceProgram;
ref<QtDevice> m_device;
ref<Font> m_font;
ref<Gizmo> m_gizmo;
SceneContext *m_context;
bool m_framebufferChanged, m_mouseButtonDown;
bool m_leftKeyDown, m_rightKeyDown;
@ -145,7 +149,9 @@ private:
bool m_ignoreScrollEvents, m_ignoreResizeEvents;
int m_mouseSensitivity, m_softwareFallback;
ref<Bitmap> m_fallbackBitmap;
ref<Timer> m_wheelTimer;
QString m_errorString;
Transform m_storedViewTransform;
};
#endif /* __GLWIDGET_H */

View File

@ -141,7 +141,7 @@ MainWindow::MainWindow(QWidget *parent) :
ui->glView->setInvertMouse(settings.value("invertMouse", false).toBool());
ui->glView->setMouseSensitivity(settings.value("mouseSensitivity", 3).toInt());
ui->glView->setNavigationMode((ENavigationMode) settings.value("navigationMode",
EFlythrough).toInt());
EArcBall).toInt());
m_searchPaths = settings.value("searchPaths", QStringList()).toStringList();
m_blockSize = settings.value("blockSize", 32).toInt();
m_listenPort = settings.value("listenPort", MTS_DEFAULT_PORT).toInt();
@ -1649,6 +1649,13 @@ QString ServerConnection::toString() const {
SceneContext::SceneContext(SceneContext *ctx) {
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);
ref<PluginManager> pluginMgr = PluginManager::getInstance();
ref<PinholeCamera> oldCamera = static_cast<PinholeCamera *>(ctx->scene->getCamera());
@ -1696,6 +1703,7 @@ SceneContext::SceneContext(SceneContext *ctx) {
scene->configure();
sceneResID = ctx->sceneResID;
Scheduler::getInstance()->retainResource(sceneResID);
thread->setFileResolver(oldResolver);
} else {
sceneResID = -1;
renderJob = NULL;
@ -1726,6 +1734,8 @@ SceneContext::SceneContext(SceneContext *ctx) {
diffuseSources = ctx->diffuseSources;
showKDTree = ctx->showKDTree;
shownKDTreeLevel = ctx->shownKDTreeLevel;
selectedShape = ctx->selectedShape;
selectionMode = ctx->selectionMode;
}
SceneContext::~SceneContext() {

View File

@ -469,7 +469,7 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
m_shaderManager->setVPL(vpl);
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());
m_mutex->lock();
@ -494,13 +494,6 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
m_shaderManager->unbind();
}
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_framebuffer->releaseTarget();
@ -511,6 +504,7 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
if (m_accumBuffer == NULL) {
target.buffer->clear();
m_renderer->blitTexture(m_framebuffer, true);
m_framebuffer->blit(target.buffer, GPUTexture::EDepthBuffer);
} else {
m_accumBuffer->bind(1);
m_accumProgram->bind();
@ -519,9 +513,11 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
m_renderer->blitQuad(true);
m_accumProgram->unbind();
m_accumBuffer->unbind();
m_accumBuffer->blit(target.buffer, GPUTexture::EDepthBuffer);
}
m_framebuffer->unbind();
m_renderer->setDepthMask(true);
m_framebuffer->unbind();
m_renderer->setDepthTest(true);
target.buffer->releaseTarget();
m_accumBuffer = target.buffer;
@ -541,42 +537,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) {
Float nearClip = std::numeric_limits<Float>::infinity(),

View File

@ -74,8 +74,6 @@ protected:
virtual ~PreviewThread();
/// Render a single VPL using OpenGL
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
void rtrtRenderVPL(PreviewQueueEntry &target, const VPL &vpl);
private:

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>378</width>
<height>531</height>
<height>533</height>
</rect>
</property>
<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;
&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; }
&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;-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; 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 name="text">
<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;
&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; }
&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;-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; 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>
<item>
<property name="text">
<string>Fly-through (Fix yaw)</string>
<string>Arcball</string>
</property>
</item>
<item>
<property name="text">
<string>Fly-through</string>
<string>First person (Fix yaw)</string>
</property>
</item>
<item>
<property name="text">
<string>First Person</string>
</property>
</item>
</widget>

View File

@ -19,6 +19,7 @@
#include "rendersettingsdlg.h"
#include "ui_rendersettingsdlg.h"
#include <mitsuba/core/plugin.h>
#include <mitsuba/core/fresolver.h>
/* ====================== Some helper routines ====================== */
@ -305,6 +306,13 @@ void RenderSettingsDialog::apply(SceneContext *ctx) {
Properties filmProps = oldCamera->getFilm()->getProperties();
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 */
Properties rFilterProps(getPluginName(ui->rFilterBox));
if (m_rFilterNode != NULL)
@ -384,6 +392,7 @@ void RenderSettingsDialog::apply(SceneContext *ctx) {
scene->configure();
ctx->scene = scene;
thread->setFileResolver(oldResolver);
}
RenderSettingsDialog::~RenderSettingsDialog() {