From 69eaa609812a3627a590507b56acac1cee293349 Mon Sep 17 00:00:00 2001 From: Gray Olson Date: Thu, 30 May 2019 01:45:02 -0700 Subject: [PATCH 1/6] display final render in opengl viewport widget --- src/appleseed.studio/CMakeLists.txt | 20 +- .../mainwindow/mainwindow.cpp | 73 +-- src/appleseed.studio/mainwindow/mainwindow.h | 4 +- ...{lightpathswidget.cpp => glscenelayer.cpp} | 352 ++---------- .../mainwindow/rendering/glscenelayer.h | 144 +++++ .../mainwindow/rendering/lightpathslayer.cpp | 534 ++++++++++++++++++ .../{lightpathswidget.h => lightpathslayer.h} | 49 +- .../rendering/lightpathspickinghandler.cpp | 2 +- .../rendering/lightpathspickinghandler.h | 6 +- ...stab.cpp => lightpathsviewportmanager.cpp} | 52 +- ...pathstab.h => lightpathsviewportmanager.h} | 12 +- .../mainwindow/rendering/qttilecallback.cpp | 29 +- .../mainwindow/rendering/qttilecallback.h | 6 +- .../mainwindow/rendering/renderingmanager.cpp | 8 +- .../{renderwidget.cpp => renderlayer.cpp} | 68 +-- .../{renderwidget.h => renderlayer.h} | 22 +- .../mainwindow/rendering/rendertab.cpp | 77 ++- .../mainwindow/rendering/rendertab.h | 13 +- .../mainwindow/rendering/viewportwidget.cpp | 210 +++++++ .../mainwindow/rendering/viewportwidget.h | 141 +++++ 20 files changed, 1243 insertions(+), 579 deletions(-) rename src/appleseed.studio/mainwindow/rendering/{lightpathswidget.cpp => glscenelayer.cpp} (64%) create mode 100644 src/appleseed.studio/mainwindow/rendering/glscenelayer.h create mode 100644 src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp rename src/appleseed.studio/mainwindow/rendering/{lightpathswidget.h => lightpathslayer.h} (73%) rename src/appleseed.studio/mainwindow/rendering/{lightpathstab.cpp => lightpathsviewportmanager.cpp} (87%) rename src/appleseed.studio/mainwindow/rendering/{lightpathstab.h => lightpathsviewportmanager.h} (92%) rename src/appleseed.studio/mainwindow/rendering/{renderwidget.cpp => renderlayer.cpp} (89%) rename src/appleseed.studio/mainwindow/rendering/{renderwidget.h => renderlayer.h} (92%) create mode 100644 src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp create mode 100644 src/appleseed.studio/mainwindow/rendering/viewportwidget.h diff --git a/src/appleseed.studio/CMakeLists.txt b/src/appleseed.studio/CMakeLists.txt index 0db48fc3e3..7f7e251860 100644 --- a/src/appleseed.studio/CMakeLists.txt +++ b/src/appleseed.studio/CMakeLists.txt @@ -248,12 +248,14 @@ source_group ("mainwindow\\pythonconsole" FILES set (mainwindow_rendering_sources mainwindow/rendering/cameracontroller.cpp mainwindow/rendering/cameracontroller.h - mainwindow/rendering/lightpathspickinghandler.cpp - mainwindow/rendering/lightpathspickinghandler.h - mainwindow/rendering/lightpathstab.cpp - mainwindow/rendering/lightpathstab.h - mainwindow/rendering/lightpathswidget.cpp - mainwindow/rendering/lightpathswidget.h + # mainwindow/rendering/glscenelayer.h + # mainwindow/rendering/glscenelayer.cpp + # mainwindow/rendering/lightpathspickinghandler.cpp + # mainwindow/rendering/lightpathspickinghandler.h + # mainwindow/rendering/lightpathsviewportmanager.cpp + # mainwindow/rendering/lightpathsviewportmanager.h + # mainwindow/rendering/lightpathslayer.cpp + # mainwindow/rendering/lightpathslayer.h mainwindow/rendering/materialdrophandler.cpp mainwindow/rendering/materialdrophandler.h mainwindow/rendering/pixelcolortracker.cpp @@ -273,10 +275,12 @@ set (mainwindow_rendering_sources mainwindow/rendering/renderregionhandler.h mainwindow/rendering/rendertab.cpp mainwindow/rendering/rendertab.h - mainwindow/rendering/renderwidget.cpp - mainwindow/rendering/renderwidget.h + mainwindow/rendering/renderlayer.cpp + mainwindow/rendering/renderlayer.h mainwindow/rendering/scenepickinghandler.cpp mainwindow/rendering/scenepickinghandler.h + mainwindow/rendering/viewportwidget.h + mainwindow/rendering/viewportwidget.cpp ) list (APPEND appleseed.studio_sources ${mainwindow_rendering_sources} diff --git a/src/appleseed.studio/mainwindow/mainwindow.cpp b/src/appleseed.studio/mainwindow/mainwindow.cpp index 6dfd7bb664..dc4bb0527a 100644 --- a/src/appleseed.studio/mainwindow/mainwindow.cpp +++ b/src/appleseed.studio/mainwindow/mainwindow.cpp @@ -40,9 +40,9 @@ #include "mainwindow/project/attributeeditor.h" #include "mainwindow/project/projectexplorer.h" #include "mainwindow/pythonconsole/pythonconsolewidget.h" -#include "mainwindow/rendering/lightpathstab.h" #include "mainwindow/rendering/materialdrophandler.h" -#include "mainwindow/rendering/renderwidget.h" +#include "mainwindow/rendering/renderlayer.h" +#include "mainwindow/rendering/viewportwidget.h" #include "utility/interop.h" #include "utility/miscellaneous.h" #include "utility/settingskeys.h" @@ -743,10 +743,10 @@ void MainWindow::update_workspace() m_ui->attribute_editor_scrollarea_contents->setEnabled(true); // Add/remove light paths tab. - if (m_project_manager.is_project_open() && - m_project_manager.get_project()->get_light_path_recorder().get_light_path_count() > 0) - add_light_paths_tab(); - else remove_light_paths_tab(); + //if (m_project_manager.is_project_open() && + // m_project_manager.get_project()->get_light_path_recorder().get_light_path_count() > 0) + // add_light_paths_tab(); + //else remove_light_paths_tab(); } void MainWindow::update_project_explorer() @@ -979,8 +979,8 @@ void MainWindow::add_render_tab(const QString& label) // Connect the render tab to the main window and the rendering manager. connect( - render_tab, SIGNAL(signal_render_widget_context_menu(const QPoint&)), - SLOT(slot_render_widget_context_menu(const QPoint&))); + render_tab->get_viewport_widget(), SIGNAL(signal_viewport_widget_context_menu(const QPoint&)), + SLOT(slot_viewport_widget_context_menu(const QPoint&))); connect( render_tab, SIGNAL(signal_set_render_region(const QRect&)), SLOT(slot_set_render_region(const QRect&))); @@ -1020,41 +1020,6 @@ void MainWindow::add_render_tab(const QString& label) m_tab_index_to_render_tab[tab_index] = render_tab; } -void MainWindow::add_light_paths_tab() -{ - if (m_light_paths_tab == nullptr) - { - // Create light paths tab. - m_light_paths_tab = - new LightPathsTab( - *m_project_manager.get_project(), - m_application_settings); - - // Connect render tabs to the light paths tab. - for (const auto& kv : m_render_tabs) - { - connect( - kv.second, SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), - m_light_paths_tab, SLOT(slot_entity_picked(renderer::ScenePicker::PickingResult))); - connect( - kv.second, SIGNAL(signal_rectangle_selection(const QRect&)), - m_light_paths_tab, SLOT(slot_rectangle_selection(const QRect&))); - } - - // Add the light paths tab to the tab bar. - m_ui->tab_render_channels->addTab(m_light_paths_tab, "Light Paths"); - } -} - -void MainWindow::remove_light_paths_tab() -{ - if (m_light_paths_tab != nullptr) - { - delete m_light_paths_tab; - m_light_paths_tab = nullptr; - } -} - ParamArray MainWindow::get_project_params(const char* configuration_name) const { ParamArray params; @@ -1231,9 +1196,6 @@ void MainWindow::start_rendering(const RenderingMode rendering_mode) set_diagnostics_widgets_enabled(rendering_mode == InteractiveRendering, rendering_mode); m_ui->attribute_editor_scrollarea_contents->setEnabled(rendering_mode == InteractiveRendering); - // Remove light paths tab. - remove_light_paths_tab(); - // Stop monitoring the project file in Final rendering mode. if (rendering_mode == FinalRendering) { @@ -1249,7 +1211,7 @@ void MainWindow::start_rendering(const RenderingMode rendering_mode) // Darken render widgets. for (const_each i = m_render_tabs; i; ++i) { - i->second->darken(); + i->second->get_viewport_widget()->get_render_layer()->darken(); i->second->update(); } @@ -1305,8 +1267,8 @@ void MainWindow::apply_false_colors_settings() // Blit the regular frame into the render widget. for (const_each i = m_render_tabs; i; ++i) { - i->second->get_render_widget()->blit_frame(*frame); - i->second->get_render_widget()->update(); + i->second->get_viewport_widget()->get_render_layer()->blit_frame(*frame); + i->second->get_viewport_widget()->get_render_layer()->update(); } } } @@ -1328,8 +1290,8 @@ void MainWindow::apply_post_processing_stage( // Blit the frame copy into the render widget. for (const_each i = m_render_tabs; i; ++i) { - i->second->get_render_widget()->blit_frame(working_frame); - i->second->get_render_widget()->update(); + i->second->get_viewport_widget()->get_render_layer()->blit_frame(working_frame); + i->second->get_viewport_widget()->get_render_layer()->update(); } } } @@ -1933,7 +1895,7 @@ void MainWindow::slot_set_render_region(const QRect& rect) } } -void MainWindow::slot_render_widget_context_menu(const QPoint& point) +void MainWindow::slot_viewport_widget_context_menu(const QPoint& point) { if (!(QApplication::keyboardModifiers() & Qt::ShiftModifier)) return; @@ -2073,7 +2035,7 @@ void MainWindow::slot_save_render_widget_content() return; // todo: this is sketchy. The render tab should be retrieved from the signal. - m_render_tabs["RGB"]->get_render_widget()->capture().save(filepath); + m_render_tabs["RGB"]->get_viewport_widget()->get_render_layer()->capture().save(filepath); RENDERER_LOG_INFO("wrote image file %s.", filepath.toStdString().c_str()); } @@ -2085,7 +2047,10 @@ void MainWindow::slot_clear_frame() // In the UI, clear all render widgets to black. for (const_each i = m_render_tabs; i; ++i) - i->second->clear(); + { + i->second->get_viewport_widget()->get_render_layer()->clear(); + i->second->get_viewport_widget()->repaint(); + } } void MainWindow::slot_reset_zoom() diff --git a/src/appleseed.studio/mainwindow/mainwindow.h b/src/appleseed.studio/mainwindow/mainwindow.h index c81dcb6703..95fe126619 100644 --- a/src/appleseed.studio/mainwindow/mainwindow.h +++ b/src/appleseed.studio/mainwindow/mainwindow.h @@ -209,8 +209,6 @@ class MainWindow void recreate_render_tabs(); void remove_render_tabs(); void add_render_tab(const QString& label); - void add_light_paths_tab(); - void remove_light_paths_tab(); // Project file handling. renderer::ParamArray get_project_params(const char* configuration_name) const; @@ -287,7 +285,7 @@ class MainWindow void slot_set_render_region(const QRect& rect); // Render widget actions. - void slot_render_widget_context_menu(const QPoint& point); + void slot_viewport_widget_context_menu(const QPoint& point); void slot_save_frame(); void slot_save_frame_and_aovs(); void slot_quicksave_frame_and_aovs(); diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathswidget.cpp b/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp similarity index 64% rename from src/appleseed.studio/mainwindow/rendering/lightpathswidget.cpp rename to src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp index 1b4cff22df..a4b6813fa7 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathswidget.cpp +++ b/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp @@ -27,7 +27,7 @@ // // Interface header. -#include "lightpathswidget.h" +#include "glscenelayer.h" // appleseed.studio headers. #include "utility/miscellaneous.h" @@ -51,6 +51,7 @@ // Qt headers. #include #include +#include #include #include @@ -122,116 +123,56 @@ namespace { }; } -LightPathsWidget::LightPathsWidget( - const Project& project, - const size_t width, - const size_t height) +GLSceneLayer::GLSceneLayer( + const Project& project, + const size_t width, + const size_t height, + QOpenGLFunctions_3_3_Core* functions, + QSurfaceFormat format) : m_project(project) , m_camera(*m_project.get_uncached_active_camera()) , m_backface_culling_enabled(false) - , m_selected_light_path_index(-1) + , m_gl(functions) , m_gl_initialized(false) + , m_format(format) { - setFocusPolicy(Qt::StrongFocus); - setFixedWidth(static_cast(width)); - setFixedHeight(static_cast(height)); - const float time = m_camera.get_shutter_middle_time(); set_transform(m_camera.transform_sequence().evaluate(time)); + + init_gl(); } -QImage LightPathsWidget::capture() +void GLSceneLayer::set_gl_functions(QOpenGLFunctions_3_3_Core* functions) { - return grabFramebuffer(); + m_gl = functions; } -void LightPathsWidget::set_transform(const Transformd& transform) +void GLSceneLayer::set_transform(const Transformd& transform) { m_camera_matrix = transform.get_parent_to_local(); m_gl_view_matrix = transpose(m_camera_matrix); m_camera_position = Vector3f(m_camera_matrix.extract_translation()); } -void LightPathsWidget::set_light_paths(const LightPathArray& light_paths) -{ - m_light_paths = light_paths; - - if (m_light_paths.size() > 1) - { - // Sort paths by descending radiance at the camera. - const auto& light_path_recorder = m_project.get_light_path_recorder(); - sort( - &m_light_paths[0], - &m_light_paths[0] + m_light_paths.size(), - [&light_path_recorder](const LightPath& lhs, const LightPath& rhs) - { - LightPathVertex lhs_v; - light_path_recorder.get_light_path_vertex(lhs.m_vertex_end_index - 1, lhs_v); - - LightPathVertex rhs_v; - light_path_recorder.get_light_path_vertex(rhs.m_vertex_end_index - 1, rhs_v); - - return - sum_value(Color3f::from_array(lhs_v.m_radiance)) > - sum_value(Color3f::from_array(rhs_v.m_radiance)); - }); - } - - // Display all paths by default. - set_selected_light_path_index(-1); - load_light_paths_data(); -} - -void LightPathsWidget::set_selected_light_path_index(const int selected_light_path_index) -{ - m_selected_light_path_index = selected_light_path_index; - - dump_selected_light_path(); - update(); - - emit signal_light_path_selection_changed( - m_selected_light_path_index, - static_cast(m_light_paths.size())); -} - -void LightPathsWidget::slot_display_all_light_paths() -{ - if (m_selected_light_path_index > -1) - set_selected_light_path_index(-1); -} - -void LightPathsWidget::slot_display_previous_light_path() -{ - if (m_selected_light_path_index > -1) - set_selected_light_path_index(m_selected_light_path_index - 1); -} - -void LightPathsWidget::slot_display_next_light_path() -{ - if (m_selected_light_path_index < static_cast(m_light_paths.size()) - 1) - set_selected_light_path_index(m_selected_light_path_index + 1); -} - -void LightPathsWidget::slot_toggle_backface_culling(const bool checked) +void GLSceneLayer::slot_toggle_backface_culling(const bool checked) { m_backface_culling_enabled = checked; - update(); } -void LightPathsWidget::slot_synchronize_camera() +void GLSceneLayer::slot_synchronize_camera() { m_camera.transform_sequence().clear(); m_camera.transform_sequence().set_transform(0.0f, Transformd::from_local_to_parent(inverse(m_camera_matrix))); } -void LightPathsWidget::load_object_instance( +void GLSceneLayer::load_object_instance( const ObjectInstance& object_instance, const Matrix4f& assembly_transform_matrix) { Object* object = object_instance.find_object(); - // This would already be logged in LightPathsWidget::load_scene_data + // This would already be logged in GLSceneLayer::load_scene_data if (object == nullptr) return; @@ -258,13 +199,13 @@ void LightPathsWidget::load_object_instance( reinterpret_cast(&gl_matrix[0])); } -void LightPathsWidget::load_assembly_instance( +void GLSceneLayer::load_assembly_instance( const AssemblyInstance& assembly_instance, const float time) { const Assembly* assembly = assembly_instance.find_assembly(); - // This would already be logged in LightPathsWidget::load_scene_data + // This would already be logged in GLSceneLayer::load_scene_data if (assembly == nullptr) return; @@ -279,7 +220,7 @@ void LightPathsWidget::load_assembly_instance( load_assembly_instance(child_assembly_instance, time); } -void LightPathsWidget::load_object_data(const Object& object) +void GLSceneLayer::load_object_data(const Object& object) { const string obj_name = string(object.get_name()); RENDERER_LOG_DEBUG("opengl: uploading mesh data for object \"%s\"...", obj_name.c_str()); @@ -328,7 +269,7 @@ void LightPathsWidget::load_object_data(const Object& object) } } -void LightPathsWidget::load_assembly_data(const Assembly& assembly) +void GLSceneLayer::load_assembly_data(const Assembly& assembly) { for (const auto& object : assembly.objects()) load_object_data(object); @@ -337,7 +278,7 @@ void LightPathsWidget::load_assembly_data(const Assembly& assembly) load_assembly_data(child_assembly); } -void LightPathsWidget::load_scene_data() +void GLSceneLayer::load_scene_data() { const float time = m_camera.get_shutter_middle_time(); @@ -428,61 +369,6 @@ void LightPathsWidget::load_scene_data() load_assembly_instance(assembly_instance, time); } -void LightPathsWidget::load_light_paths_data() -{ - m_light_paths_index_offsets.clear(); - if (!m_light_paths.empty()) - { - m_light_paths_index_offsets.push_back(0); - - const auto& light_path_recorder = m_project.get_light_path_recorder(); - - const size_t total_gl_vertex_count = 2 * (light_path_recorder.get_vertex_count() - 2) + 2; - - GLsizei total_index_count = 0; - vector buffer; - buffer.reserve(total_gl_vertex_count * LightPathVertexFloatStride); - for (size_t light_path_idx = 0; light_path_idx < m_light_paths.size(); light_path_idx++) - { - const auto& path = m_light_paths[light_path_idx]; - assert(path.m_vertex_end_index - path.m_vertex_begin_index >= 2); - - LightPathVertex prev; - light_path_recorder.get_light_path_vertex(path.m_vertex_begin_index, prev); - for (size_t vertex_idx = path.m_vertex_begin_index + 1; vertex_idx < path.m_vertex_end_index; vertex_idx++) - { - LightPathVertex curr; - light_path_recorder.get_light_path_vertex(vertex_idx, curr); - - auto piece_radiance = Color3f::from_array(curr.m_radiance); - piece_radiance /= piece_radiance + Color3f(1.0f); // Reinhard tone mapping - piece_radiance = linear_rgb_to_srgb(piece_radiance); - - const float temp_store[LightPathVertexLineFloatStride] = - { - prev.m_position[0], prev.m_position[1], prev.m_position[2], - piece_radiance[0], piece_radiance[1], piece_radiance[2], - - curr.m_position[0], curr.m_position[1], curr.m_position[2], - piece_radiance[0], piece_radiance[1], piece_radiance[2], - }; - buffer.insert(buffer.end(), temp_store, temp_store + 12); - - total_index_count += 2; - prev = curr; - } - m_light_paths_index_offsets.push_back(total_index_count); - } - - m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_light_paths_vbo); - m_gl->glBufferData( - GL_ARRAY_BUFFER, - buffer.size() * sizeof(float), - reinterpret_cast(&buffer[0]), - GL_STATIC_DRAW); - } -} - namespace { const string shader_kind_to_string(const GLint shader_kind) { @@ -568,24 +454,17 @@ namespace { } } -void LightPathsWidget::initializeGL() +void GLSceneLayer::init_gl(QSurfaceFormat format) { - m_gl = QOpenGLContext::currentContext()->versionFunctions(); // If there was already previous data, clean up - LightPathsWidget::cleanup_gl_data(); - - const auto qgl_format = format(); + GLSceneLayer::cleanup_gl_data(); - if (!m_gl->initializeOpenGLFunctions()) + bool manual_srgb_conversion = false; + if (format.colorSpace() != QSurfaceFormat::sRGBColorSpace) { - const int major_version = qgl_format.majorVersion(); - const int minor_version = qgl_format.minorVersion(); - RENDERER_LOG_ERROR( - "opengl: could not load required gl functions: loaded version %d.%d, required version 3.3.", - major_version, - minor_version); - m_gl_initialized = false; - return; + manual_srgb_conversion = true; + RENDERER_LOG_WARNING( + "opengl: srgb framebuffer extensions not supported, using slower manual conversion."); } glEnable(GL_DEPTH_TEST); @@ -598,19 +477,10 @@ void LightPathsWidget::initializeGL() load_gl_shader("scene.vert"), load_gl_shader("scene.frag")); - create_shader_program( - m_gl, - m_light_paths_shader_program, - load_gl_shader("lightpaths.vert"), - load_gl_shader("lightpaths.frag")); - m_scene_view_mat_location = m_gl->glGetUniformLocation(m_scene_shader_program, "u_view"); m_scene_proj_mat_location = m_gl->glGetUniformLocation(m_scene_shader_program, "u_proj"); m_scene_camera_pos_location = m_gl->glGetUniformLocation(m_scene_shader_program, "u_camera_pos"); - m_light_paths_view_mat_location = m_gl->glGetUniformLocation(m_light_paths_shader_program, "u_view"); - m_light_paths_proj_mat_location = m_gl->glGetUniformLocation(m_light_paths_shader_program, "u_proj"); - const float z_near = 0.01f; const float z_far = 1000.0f; @@ -631,41 +501,12 @@ void LightPathsWidget::initializeGL() // from the FBO to the default framebuffer, which flips the image. m_gl_proj_matrix = transpose(Matrix4f::make_frustum(top, bottom, left, right, z_near, z_far)); - GLuint temp_light_paths_vao = 0; - GLuint temp_light_paths_vbo = 0; - m_gl->glGenVertexArrays(1, &temp_light_paths_vao); - m_gl->glGenBuffers(1, &temp_light_paths_vbo); - m_light_paths_vao = temp_light_paths_vao; - m_light_paths_vbo = temp_light_paths_vbo; - - m_gl->glBindVertexArray(m_light_paths_vao); - m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_light_paths_vbo); - m_gl->glVertexAttribPointer( - 0, - 3, - GL_FLOAT, - GL_FALSE, - LightPathVertexByteStride, - reinterpret_cast(0)); - m_gl->glVertexAttribPointer( - 1, - 3, - GL_FLOAT, - GL_FALSE, - LightPathVertexByteStride, - reinterpret_cast(LightPathVertexByteStride / 2)); - m_gl->glEnableVertexAttribArray(0); - m_gl->glEnableVertexAttribArray(1); - - m_gl->glBindVertexArray(0); - load_scene_data(); - load_light_paths_data(); m_gl_initialized = true; } -void LightPathsWidget::cleanup_gl_data() +void GLSceneLayer::cleanup_gl_data() { if (!m_scene_object_vaos.empty()) { @@ -692,24 +533,28 @@ void LightPathsWidget::cleanup_gl_data() { m_gl->glDeleteProgram(m_scene_shader_program); } - if (m_light_paths_shader_program != 0) - { - m_gl->glDeleteProgram(m_light_paths_shader_program); - } m_scene_object_index_map.clear(); m_scene_object_data_index_counts.clear(); m_scene_object_instance_counts.clear(); m_scene_object_current_instances.clear(); } -void LightPathsWidget::resizeGL(int w, int h) +void GLSceneLayer::draw() { - glViewport(0, 0, static_cast(w), static_cast(h)); + if (!m_gl_initialized) + return; + + if (m_backface_culling_enabled) + glEnable(GL_CULL_FACE); + else glDisable(GL_CULL_FACE); + + m_gl->glUseProgram(m_scene_shader_program); + render_scene(); } -void LightPathsWidget::paintGL() +void GLSceneLayer::draw_depth_only() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); if (!m_gl_initialized) return; @@ -718,38 +563,13 @@ void LightPathsWidget::paintGL() glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); - render_geometry(); - render_light_paths(); -} - -void LightPathsWidget::keyPressEvent(QKeyEvent* event) -{ - switch (event->key()) - { - // Home key: display all paths. - case Qt::Key_Home: - slot_display_all_light_paths(); - break; - - // Left key: display previous path. - case Qt::Key_Left: - slot_display_previous_light_path(); - break; - - // Right key: display next path. - case Qt::Key_Right: - slot_display_next_light_path(); - break; - - default: - QOpenGLWidget::keyPressEvent(event); - break; - } + m_gl->glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + m_gl->glUseProgram(m_depthonly_shader_program); + render_scene(); } -void LightPathsWidget::render_geometry() +void GLSceneLayer::render_scene() { - m_gl->glUseProgram(m_scene_shader_program); m_gl->glUniformMatrix4fv( m_scene_view_mat_location, 1, @@ -781,81 +601,5 @@ void LightPathsWidget::render_geometry() } } -void LightPathsWidget::render_light_paths() -{ - if (m_light_paths_index_offsets.size() > 1) - { - m_gl->glUseProgram(m_light_paths_shader_program); - m_gl->glUniformMatrix4fv( - m_light_paths_view_mat_location, - 1, - false, - const_cast(&m_gl_view_matrix[0])); - m_gl->glUniformMatrix4fv( - m_light_paths_proj_mat_location, - 1, - false, - const_cast(&m_gl_proj_matrix[0])); - - m_gl->glBindVertexArray(m_light_paths_vao); - - GLint first; - GLsizei count; - assert(m_selected_light_path_index >= -1); - if (m_selected_light_path_index == -1) - { - first = 0; - count = m_light_paths_index_offsets[m_light_paths_index_offsets.size() - 1]; - } - else - { - first = static_cast(m_light_paths_index_offsets[m_selected_light_path_index]); - count = m_light_paths_index_offsets[m_selected_light_path_index + 1] - first; - } - glDrawArrays(GL_LINES, first, count); - } -} - -void LightPathsWidget::dump_selected_light_path() const -{ - if (m_selected_light_path_index == -1) - { - if (m_light_paths.empty()) - RENDERER_LOG_INFO("no light path to display."); - else - { - RENDERER_LOG_INFO("displaying all %s light path%s.", - pretty_uint(m_light_paths.size()).c_str(), - m_light_paths.size() > 1 ? "s" : ""); - } - } - else - { - RENDERER_LOG_INFO("displaying light path %s:", - pretty_int(m_selected_light_path_index + 1).c_str()); - - const auto& light_path_recorder = m_project.get_light_path_recorder(); - const auto& path = m_light_paths[m_selected_light_path_index]; - - for (size_t i = path.m_vertex_begin_index; i < path.m_vertex_end_index; ++i) - { - LightPathVertex v; - light_path_recorder.get_light_path_vertex(i, v); - - const string entity_name = - v.m_entity != nullptr - ? foundation::format("\"{0}\"", v.m_entity->get_path().c_str()) - : "n/a"; - - RENDERER_LOG_INFO(" vertex " FMT_SIZE_T ": entity: %s - position: (%f, %f, %f) - radiance: (%f, %f, %f) - total radiance: %f", - i - path.m_vertex_begin_index + 1, - entity_name.c_str(), - v.m_position[0], v.m_position[1], v.m_position[2], - v.m_radiance[0], v.m_radiance[1], v.m_radiance[2], - v.m_radiance[0] + v.m_radiance[1] + v.m_radiance[2]); - } - } -} - } // namespace studio } // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/glscenelayer.h b/src/appleseed.studio/mainwindow/rendering/glscenelayer.h new file mode 100644 index 0000000000..6278479e8f --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/glscenelayer.h @@ -0,0 +1,144 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2018 Gray Olson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#pragma once + +// appleseed.studio headers. +#include "mainwindow/rendering/renderclipboardhandler.h" + +// appleseed.renderer headers. +#include "renderer/api/lighting.h" + +// appleseed.foundation headers. +#include "foundation/math/matrix.h" +#include "foundation/math/transform.h" +#include "foundation/math/vector.h" + +// Qt headers. +#include +#include + +// Standard headers. +#include +#include +#include +#include + +// Forward declarations. +namespace renderer { class Assembly; } +namespace renderer { class AssemblyInstance; } +namespace renderer { class Camera; } +namespace renderer { class Object; } +namespace renderer { class ObjectInstance; } +namespace renderer { class Project; } +class QKeyEvent; +class QImage; +class QOpenGLFunctions_3_3_Core; +class QSurfaceFormat; + +namespace appleseed { +namespace studio { + +// +// A widget providing an hardware-accelerated visualization of the loaded scene. +// + +class GLSceneLayer + : public QObject +{ + Q_OBJECT + + public: + GLSceneLayer( + const renderer::Project& project, + const size_t width, + const size_t height); + + void set_transform( + const foundation::Transformd& transform); + + void set_gl_functions( + QOpenGLFunctions_3_3_Core* functions); + + void init_gl(QSurfaceFormat format); + + void draw(); + void draw_depth_only(); + + public slots: + void slot_toggle_backface_culling(const bool checked); + void slot_synchronize_camera(); + + private: + const renderer::Project& m_project; + renderer::Camera& m_camera; + foundation::Matrix4d m_camera_matrix; + foundation::Vector3f m_camera_position; + + bool m_backface_culling_enabled; + + QOpenGLFunctions_3_3_Core* m_gl; + + std::vector m_scene_object_data_vbos; + std::vector m_scene_object_data_index_counts; + std::vector m_scene_object_instance_vbos; + std::vector m_scene_object_instance_counts; + std::vector m_scene_object_current_instances; + std::vector m_scene_object_vaos; + std::unordered_map m_scene_object_index_map; + GLuint m_scene_shader_program; + GLuint m_depthonly_shader_program; + GLint m_scene_view_mat_location; + GLint m_scene_proj_mat_location; + GLint m_scene_camera_pos_location; + foundation::Matrix4f m_gl_view_matrix; + foundation::Matrix4f m_gl_proj_matrix; + bool m_gl_initialized; + + void render_scene(); + + void cleanup_gl_data(); + void load_scene_data(); + + void load_assembly_data( + const renderer::Assembly& object); + + void load_assembly_instance( + const renderer::AssemblyInstance& assembly_instance, + const float time); + + void load_object_data( + const renderer::Object& object); + + void load_object_instance( + const renderer::ObjectInstance& object_instance, + const foundation::Matrix4f& assembly_transform_matrix); +}; + +} // namespace studio +} // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp new file mode 100644 index 0000000000..e6fe60571a --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp @@ -0,0 +1,534 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2018 Francois Beaune, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +// Interface header. +#include "lightpathslayer.h" + +// appleseed.studio headers. +#include "utility/miscellaneous.h" + +// appleseed.renderer headers. +#include "renderer/api/camera.h" +#include "renderer/api/entity.h" +#include "renderer/api/object.h" +#include "renderer/api/project.h" +#include "renderer/api/rasterization.h" +#include "renderer/api/scene.h" +#include "renderer/api/utility.h" + +// appleseed.foundation headers. +#include "foundation/image/color.h" +#include "foundation/image/colorspace.h" +#include "foundation/math/scalar.h" +#include "foundation/utility/api/apistring.h" +#include "foundation/utility/string.h" + +// Qt headers. +#include +#include +#include +#include + +// Standard headers. +#include +#include + +using namespace foundation; +using namespace renderer; +using namespace std; + +namespace appleseed { +namespace studio { + +namespace { + // Number of floats per OpenGL vertex for a piece of scene geometry + // Vector3 position and Vector3 normal. + const size_t SceneVertexFloatStride = 6; + // Number of bytes per OpenGL vertex for a piece of scene geometry. + const size_t SceneVertexByteStride = SceneVertexFloatStride * sizeof(float); + // Number of floats per triangle for a piece of scene geometry. + const size_t SceneTriangleFloatStride = SceneVertexFloatStride * 3; + + // Number of floats per OpenGL vertex for a light path + // Vector3 position and Vector3 color. + const size_t LightPathVertexFloatStride = 6; + // Number of bytes per OpenGL vertex for a piece of scene geometry. + const size_t LightPathVertexByteStride = LightPathVertexFloatStride * sizeof(float); + // Number of floats per line for a light path. + const size_t LightPathVertexLineFloatStride = LightPathVertexFloatStride * 2; + + // Number of floats per OpenGL transform matrix. + const size_t TransformFloatStride = 16; + // Number of bytes per OpenGL transform matrix. + const size_t TransformByteStride = TransformFloatStride * sizeof(float); + + struct OpenGLRasterizer + : public ObjectRasterizer + { + vector m_buffer; + size_t m_prim_count; + + void begin_object(const size_t triangle_count_hint) override + { + m_buffer.clear(); + m_buffer.reserve(triangle_count_hint * SceneTriangleFloatStride); + m_prim_count = 0; + } + + void end_object() override {} + + void rasterize(const Triangle& triangle) override + { + const float temp_store[SceneTriangleFloatStride] = + { + static_cast(triangle.m_v0[0]), static_cast(triangle.m_v0[1]), static_cast(triangle.m_v0[2]), + static_cast(triangle.m_n0[0]), static_cast(triangle.m_n0[1]), static_cast(triangle.m_n0[2]), + + static_cast(triangle.m_v1[0]), static_cast(triangle.m_v1[1]), static_cast(triangle.m_v1[2]), + static_cast(triangle.m_n1[0]), static_cast(triangle.m_n1[1]), static_cast(triangle.m_n1[2]), + + static_cast(triangle.m_v2[0]), static_cast(triangle.m_v2[1]), static_cast(triangle.m_v2[2]), + static_cast(triangle.m_n2[0]), static_cast(triangle.m_n2[1]), static_cast(triangle.m_n2[2]), + }; + m_buffer.reserve(m_buffer.size() + SceneTriangleFloatStride); + m_buffer.insert(m_buffer.end(), temp_store, temp_store + SceneTriangleFloatStride); + m_prim_count++; + } + }; +} + +LightPathsLayer::LightPathsLayer( + const Project& project, + const size_t width, + const size_t height) + : m_project(project) + , m_camera(*m_project.get_uncached_active_camera()) + , m_backface_culling_enabled(false) + , m_selected_light_path_index(-1) + , m_gl_initialized(false) +{ + + const float time = m_camera.get_shutter_middle_time(); + set_transform(m_camera.transform_sequence().evaluate(time)); +} + +void LightPathsLayer::set_gl_functions(QOpenGLFunctions_3_3_Core* functions) +{ + m_gl = functions; +} + +void LightPathsLayer::set_transform(const Transformd& transform) +{ + m_camera_matrix = transform.get_parent_to_local(); + m_gl_view_matrix = transpose(m_camera_matrix); + m_camera_position = Vector3f(m_camera_matrix.extract_translation()); +} + +void LightPathsLayer::set_light_paths(const LightPathArray& light_paths) +{ + m_light_paths = light_paths; + + if (m_light_paths.size() > 1) + { + // Sort paths by descending radiance at the camera. + const auto& light_path_recorder = m_project.get_light_path_recorder(); + sort( + &m_light_paths[0], + &m_light_paths[0] + m_light_paths.size(), + [&light_path_recorder](const LightPath& lhs, const LightPath& rhs) + { + LightPathVertex lhs_v; + light_path_recorder.get_light_path_vertex(lhs.m_vertex_end_index - 1, lhs_v); + + LightPathVertex rhs_v; + light_path_recorder.get_light_path_vertex(rhs.m_vertex_end_index - 1, rhs_v); + + return + sum_value(Color3f::from_array(lhs_v.m_radiance)) > + sum_value(Color3f::from_array(rhs_v.m_radiance)); + }); + } + + // Display all paths by default. + set_selected_light_path_index(-1); + load_light_paths_data(); +} + +void LightPathsLayer::set_selected_light_path_index(const int selected_light_path_index) +{ + m_selected_light_path_index = selected_light_path_index; + + dump_selected_light_path(); + + emit signal_light_path_selection_changed( + m_selected_light_path_index, + static_cast(m_light_paths.size())); +} + +void LightPathsLayer::slot_display_all_light_paths() +{ + if (m_selected_light_path_index > -1) + set_selected_light_path_index(-1); +} + +void LightPathsLayer::slot_display_previous_light_path() +{ + if (m_selected_light_path_index > -1) + set_selected_light_path_index(m_selected_light_path_index - 1); +} + +void LightPathsLayer::slot_display_next_light_path() +{ + if (m_selected_light_path_index < static_cast(m_light_paths.size()) - 1) + set_selected_light_path_index(m_selected_light_path_index + 1); +} + +void LightPathsLayer::slot_toggle_backface_culling(const bool checked) +{ + m_backface_culling_enabled = checked; +} + +void LightPathsLayer::slot_synchronize_camera() +{ + m_camera.transform_sequence().clear(); + m_camera.transform_sequence().set_transform(0.0f, + Transformd::from_local_to_parent(inverse(m_camera_matrix))); +} + +void LightPathsLayer::load_light_paths_data() +{ + m_light_paths_index_offsets.clear(); + if (!m_light_paths.empty()) + { + m_light_paths_index_offsets.push_back(0); + + const auto& light_path_recorder = m_project.get_light_path_recorder(); + + const size_t total_gl_vertex_count = 2 * (light_path_recorder.get_vertex_count() - 2) + 2; + + GLsizei total_index_count = 0; + vector buffer; + buffer.reserve(total_gl_vertex_count * LightPathVertexFloatStride); + for (size_t light_path_idx = 0; light_path_idx < m_light_paths.size(); light_path_idx++) + { + const auto& path = m_light_paths[light_path_idx]; + assert(path.m_vertex_end_index - path.m_vertex_begin_index >= 2); + + LightPathVertex prev; + light_path_recorder.get_light_path_vertex(path.m_vertex_begin_index, prev); + for (size_t vertex_idx = path.m_vertex_begin_index + 1; vertex_idx < path.m_vertex_end_index; vertex_idx++) + { + LightPathVertex curr; + light_path_recorder.get_light_path_vertex(vertex_idx, curr); + + auto piece_radiance = Color3f::from_array(curr.m_radiance); + piece_radiance /= piece_radiance + Color3f(1.0f); + piece_radiance = linear_rgb_to_srgb(piece_radiance); + + const float temp_store[LightPathVertexLineFloatStride] = + { + prev.m_position[0], prev.m_position[1], prev.m_position[2], + piece_radiance[0], piece_radiance[1], piece_radiance[2], + + curr.m_position[0], curr.m_position[1], curr.m_position[2], + piece_radiance[0], piece_radiance[1], piece_radiance[2], + }; + buffer.insert(buffer.end(), temp_store, temp_store + 12); + + total_index_count += 2; + prev = curr; + } + m_light_paths_index_offsets.push_back(total_index_count); + } + + m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_light_paths_vbo); + m_gl->glBufferData( + GL_ARRAY_BUFFER, + buffer.size() * sizeof(float), + reinterpret_cast(&buffer[0]), + GL_STATIC_DRAW); + } +} + +namespace { + const string shader_kind_to_string(const GLint shader_kind) + { + switch (shader_kind) { + case GL_VERTEX_SHADER: + return "Vertex"; + case GL_FRAGMENT_SHADER: + return "Fragment"; + default: + return "Unknown Kind"; + } + } + + void compile_shader( + QOpenGLFunctions_3_3_Core* f, + const GLuint shader, + const GLsizei count, + const GLchar** src_string, + const GLint* length) + { + f->glShaderSource(shader, count, src_string, length); + f->glCompileShader(shader); + GLint success; + f->glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + + if (!success) + { + char info_log[1024]; + f->glGetShaderInfoLog(shader, 1024, NULL, info_log); + + GLint shader_kind; + f->glGetShaderiv(shader, GL_SHADER_TYPE, &shader_kind); + string shader_kind_string = shader_kind_to_string(shader_kind); + + RENDERER_LOG_ERROR("opengl: %s shader compilation failed:\n%s", shader_kind_string.c_str(), info_log); + } + } + + void link_shader_program( + QOpenGLFunctions_3_3_Core* f, + const GLuint program, + const GLuint vert, + const GLuint frag) + { + f->glAttachShader(program, vert); + f->glAttachShader(program, frag); + f->glLinkProgram(program); + + GLint success; + f->glGetProgramiv(program, GL_LINK_STATUS, &success); + + if (!success) + { + char info_log[1024]; + f->glGetProgramInfoLog(program, 1024, NULL, info_log); + RENDERER_LOG_ERROR("opengl: shader program linking failed:\n%s", info_log); + } + } + + void create_shader_program( + QOpenGLFunctions_3_3_Core* f, + GLuint& program, + const QByteArray& vert_source, + const QByteArray& frag_source) + { + GLuint vert = f->glCreateShader(GL_VERTEX_SHADER); + GLuint frag = f->glCreateShader(GL_FRAGMENT_SHADER); + + auto gl_vert_source = static_cast(vert_source.constData()); + auto gl_vert_source_length = static_cast(vert_source.size()); + + auto gl_frag_source = static_cast(frag_source.constData()); + auto gl_frag_source_length = static_cast(frag_source.size()); + + compile_shader(f, vert, 1, &gl_vert_source, &gl_vert_source_length); + compile_shader(f, frag, 1, &gl_frag_source, &gl_frag_source_length); + + program = f->glCreateProgram(); + link_shader_program(f, program, vert, frag); + + f->glDeleteShader(vert); + f->glDeleteShader(frag); + } +} + +void LightPathsLayer::init_gl(QSurfaceFormat format) +{ + // If there was already previous data, clean up + LightPathsLayer::cleanup_gl_data(); + + bool manual_srgb_conversion = false; + if (format.colorSpace() != QSurfaceFormat::sRGBColorSpace) + { + manual_srgb_conversion = true; + RENDERER_LOG_WARNING( + "opengl: srgb framebuffer extensions not supported, using slower manual conversion."); + } + + glEnable(GL_DEPTH_TEST); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + create_shader_program( + m_gl, + m_light_paths_shader_program, + load_gl_shader("lightpaths.vert"), + load_gl_shader("lightpaths.frag")); + + m_light_paths_view_mat_location = m_gl->glGetUniformLocation(m_light_paths_shader_program, "u_view"); + m_light_paths_proj_mat_location = m_gl->glGetUniformLocation(m_light_paths_shader_program, "u_proj"); + + const float z_near = 0.01f; + const float z_far = 1000.0f; + + const auto& rc = m_camera.get_rasterization_camera(); + + const float fy = tan(rc.m_hfov / rc.m_aspect_ratio * 0.5) * z_near; + const float fx = fy * rc.m_aspect_ratio; + + const float shift_x = rc.m_shift_x * 2.0 * fx; + const float shift_y = rc.m_shift_y * 2.0 * fy; + + const float left = -fx + shift_x; + const float right = fx + shift_x; + const float top = -fy + shift_y; + const float bottom = fy + shift_y; + + // Top and bottom are flipped because QOpenGLWidget draws to a framebuffer object and then blits + // from the FBO to the default framebuffer, which flips the image. + m_gl_proj_matrix = transpose(Matrix4f::make_frustum(top, bottom, left, right, z_near, z_far)); + + GLuint temp_light_paths_vao = 0; + GLuint temp_light_paths_vbo = 0; + m_gl->glGenVertexArrays(1, &temp_light_paths_vao); + m_gl->glGenBuffers(1, &temp_light_paths_vbo); + m_light_paths_vao = temp_light_paths_vao; + m_light_paths_vbo = temp_light_paths_vbo; + + m_gl->glBindVertexArray(m_light_paths_vao); + m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_light_paths_vbo); + m_gl->glVertexAttribPointer( + 0, + 3, + GL_FLOAT, + GL_FALSE, + LightPathVertexByteStride, + reinterpret_cast(0)); + m_gl->glVertexAttribPointer( + 1, + 3, + GL_FLOAT, + GL_FALSE, + LightPathVertexByteStride, + reinterpret_cast(LightPathVertexByteStride / 2)); + m_gl->glEnableVertexAttribArray(0); + m_gl->glEnableVertexAttribArray(1); + + m_gl->glBindVertexArray(0); + + load_light_paths_data(); + + m_gl_initialized = true; +} + +void LightPathsLayer::cleanup_gl_data() +{ + if (m_light_paths_shader_program != 0) + { + m_gl->glDeleteProgram(m_light_paths_shader_program); + } +} + +void LightPathsLayer::draw() +{ + if (!m_gl_initialized) + return; + + if (m_backface_culling_enabled) + glEnable(GL_CULL_FACE); + else glDisable(GL_CULL_FACE); + + if (m_light_paths_index_offsets.size() > 1) + { + m_gl->glUseProgram(m_light_paths_shader_program); + m_gl->glUniformMatrix4fv( + m_light_paths_view_mat_location, + 1, + false, + const_cast(&m_gl_view_matrix[0])); + m_gl->glUniformMatrix4fv( + m_light_paths_proj_mat_location, + 1, + false, + const_cast(&m_gl_proj_matrix[0])); + + m_gl->glBindVertexArray(m_light_paths_vao); + + GLint first; + GLsizei count; + assert(m_selected_light_path_index >= -1); + if (m_selected_light_path_index == -1) + { + first = 0; + count = m_light_paths_index_offsets[m_light_paths_index_offsets.size() - 1]; + } + else + { + first = static_cast(m_light_paths_index_offsets[m_selected_light_path_index]); + count = m_light_paths_index_offsets[m_selected_light_path_index + 1] - first; + } + glDrawArrays(GL_LINES, first, count); + } +} + +void LightPathsLayer::dump_selected_light_path() const +{ + if (m_selected_light_path_index == -1) + { + if (m_light_paths.empty()) + RENDERER_LOG_INFO("no light path to display."); + else + { + RENDERER_LOG_INFO("displaying all %s light path%s.", + pretty_uint(m_light_paths.size()).c_str(), + m_light_paths.size() > 1 ? "s" : ""); + } + } + else + { + RENDERER_LOG_INFO("displaying light path %s:", + pretty_int(m_selected_light_path_index + 1).c_str()); + + const auto& light_path_recorder = m_project.get_light_path_recorder(); + const auto& path = m_light_paths[m_selected_light_path_index]; + + for (size_t i = path.m_vertex_begin_index; i < path.m_vertex_end_index; ++i) + { + LightPathVertex v; + light_path_recorder.get_light_path_vertex(i, v); + + const string entity_name = + v.m_entity != nullptr + ? foundation::format("\"{0}\"", v.m_entity->get_path().c_str()) + : "n/a"; + + RENDERER_LOG_INFO(" vertex " FMT_SIZE_T ": entity: %s - position: (%f, %f, %f) - radiance: (%f, %f, %f) - total radiance: %f", + i - path.m_vertex_begin_index + 1, + entity_name.c_str(), + v.m_position[0], v.m_position[1], v.m_position[2], + v.m_radiance[0], v.m_radiance[1], v.m_radiance[2], + v.m_radiance[0] + v.m_radiance[1] + v.m_radiance[2]); + } + } +} + +} // namespace studio +} // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathswidget.h b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h similarity index 73% rename from src/appleseed.studio/mainwindow/rendering/lightpathswidget.h rename to src/appleseed.studio/mainwindow/rendering/lightpathslayer.h index 7614f75263..9c611dbe53 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathswidget.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h @@ -67,20 +67,16 @@ namespace studio { // A widget providing an hardware-accelerated visualization of recorded light paths. // -class LightPathsWidget - : public QOpenGLWidget - , public ICapturableWidget +class LightPathsLayer { Q_OBJECT public: - LightPathsWidget( + LightPathsLayer( const renderer::Project& project, const size_t width, const size_t height); - QImage capture() override; - void set_transform( const foundation::Transformd& transform); @@ -90,6 +86,13 @@ class LightPathsWidget void set_selected_light_path_index( const int selected_light_path_index); + void set_gl_functions( + QOpenGLFunctions_3_3_Core* functions); + + void init_gl(QSurfaceFormat format); + + void draw(); + signals: void signal_light_path_selection_changed( const int selected_light_path_index, @@ -115,17 +118,6 @@ class LightPathsWidget QOpenGLFunctions_3_3_Core* m_gl; - std::vector m_scene_object_data_vbos; - std::vector m_scene_object_data_index_counts; - std::vector m_scene_object_instance_vbos; - std::vector m_scene_object_instance_counts; - std::vector m_scene_object_current_instances; - std::vector m_scene_object_vaos; - std::unordered_map m_scene_object_index_map; - GLuint m_scene_shader_program; - GLint m_scene_view_mat_location; - GLint m_scene_proj_mat_location; - GLint m_scene_camera_pos_location; GLuint m_light_paths_vbo; std::vector m_light_paths_index_offsets; GLuint m_light_paths_vao; @@ -136,32 +128,9 @@ class LightPathsWidget foundation::Matrix4f m_gl_proj_matrix; bool m_gl_initialized; - void initializeGL() override; - void resizeGL(int w, int h) override; - void paintGL() override; - void keyPressEvent(QKeyEvent* event) override; - void cleanup_gl_data(); - void load_scene_data(); void load_light_paths_data(); - void load_assembly_data( - const renderer::Assembly& object); - - void load_assembly_instance( - const renderer::AssemblyInstance& assembly_instance, - const float time); - - void load_object_data( - const renderer::Object& object); - - void load_object_instance( - const renderer::ObjectInstance& object_instance, - const foundation::Matrix4f& assembly_transform_matrix); - - void render_geometry(); - void render_light_paths(); - void dump_selected_light_path() const; }; diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp index 4071653db7..4e9715a312 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp @@ -57,7 +57,7 @@ namespace appleseed { namespace studio { LightPathsPickingHandler::LightPathsPickingHandler( - LightPathsWidget* light_paths_widget, + LightPathsLayer* light_paths_widget, const MouseCoordinatesTracker& mouse_tracker, const Project& project) : m_light_paths_widget(light_paths_widget) diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h index 5858fe6e4d..215780c8a9 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h @@ -36,7 +36,7 @@ #include // Forward declarations. -namespace appleseed { namespace studio { class LightPathsWidget; } } +namespace appleseed { namespace studio { class LightPathsLayer; } } namespace appleseed { namespace studio { class MouseCoordinatesTracker; } } namespace renderer { class Project; } class QEvent; @@ -51,7 +51,7 @@ class LightPathsPickingHandler public: LightPathsPickingHandler( - LightPathsWidget* light_paths_widget, + LightPathsLayer* light_paths_widget, const MouseCoordinatesTracker& mouse_tracker, const renderer::Project& project); @@ -63,7 +63,7 @@ class LightPathsPickingHandler void pick(const foundation::AABB2i& rect) const; private: - LightPathsWidget* m_light_paths_widget; + LightPathsLayer* m_light_paths_widget; const MouseCoordinatesTracker& m_mouse_tracker; const renderer::Project& m_project; bool m_enabled; diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathstab.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp similarity index 87% rename from src/appleseed.studio/mainwindow/rendering/lightpathstab.cpp rename to src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp index 125d50a05c..9fbf91a653 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathstab.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp @@ -27,11 +27,11 @@ // // Interface header. -#include "lightpathstab.h" +#include "lightpathsviewportmanager.h" // appleseed.studio headers. #include "mainwindow/rendering/lightpathspickinghandler.h" -#include "mainwindow/rendering/lightpathswidget.h" +#include "mainwindow/rendering/lightpathslayer.h" #include "utility/miscellaneous.h" #include "utility/settingskeys.h" @@ -70,29 +70,20 @@ namespace appleseed { namespace studio { // -// LightPathsTab class implementation. +// LightPathsViewportManager class implementation. // -LightPathsTab::LightPathsTab(Project& project, ParamArray& settings) +LightPathsViewportManager::LightPathsViewportManager(Project& project, ParamArray& settings) : m_project(project) , m_settings(settings) { - setObjectName("render_widget_tab"); - setLayout(new QGridLayout()); - layout()->setSpacing(0); - layout()->setMargin(0); - create_light_paths_widget(); create_toolbar(); - create_scrollarea(); - - layout()->addWidget(m_toolbar); - layout()->addWidget(m_scroll_area); recreate_handlers(); } -void LightPathsTab::slot_entity_picked(const ScenePicker::PickingResult& result) +void LightPathsViewportManager::slot_entity_picked(const ScenePicker::PickingResult& result) { const CanvasProperties& props = m_project.get_frame()->image().properties(); @@ -102,7 +93,7 @@ void LightPathsTab::slot_entity_picked(const ScenePicker::PickingResult& result) result.m_ndc[1] * static_cast(props.m_canvas_height))); } -void LightPathsTab::slot_rectangle_selection(const QRect& rect) +void LightPathsViewportManager::slot_rectangle_selection(const QRect& rect) { m_screen_space_paths_picking_handler->pick( AABB2i( @@ -110,7 +101,7 @@ void LightPathsTab::slot_rectangle_selection(const QRect& rect) Vector2i(rect.x() + rect.width() - 1, rect.y() + rect.height() - 1))); } -void LightPathsTab::slot_light_path_selection_changed( +void LightPathsViewportManager::slot_light_path_selection_changed( const int selected_light_path_index, const int total_light_paths) const { @@ -126,24 +117,17 @@ void LightPathsTab::slot_light_path_selection_changed( } } -void LightPathsTab::slot_context_menu(const QPoint& point) +void LightPathsViewportManager::slot_context_menu(const QPoint& point) { if (!(QApplication::keyboardModifiers() & Qt::ShiftModifier)) return; QMenu* menu = new QMenu(this); - const auto light_path_count = m_project.get_light_path_recorder().get_light_path_count(); - menu->addAction( - QString("Save %1 Light Path%2...") - .arg(QString::fromStdString(pretty_uint(light_path_count))) - .arg(light_path_count > 1 ? "s" : ""), - this, SLOT(slot_save_light_paths())); - - menu->exec(m_light_paths_widget->mapToGlobal(point)); + menu->exec(m_light_paths_layer->mapToGlobal(point)); } -void LightPathsTab::slot_save_light_paths() +void LightPathsViewportManager::slot_save_light_paths() { QString filepath = get_save_filename( @@ -165,18 +149,18 @@ void LightPathsTab::slot_save_light_paths() m_project.get_light_path_recorder().write(filepath.toUtf8().constData()); } -void LightPathsTab::slot_camera_changed() +void LightPathsViewportManager::slot_camera_changed() { - m_light_paths_widget->set_transform(m_camera_controller->get_transform()); - m_light_paths_widget->update(); + m_light_paths_layer->set_transform(m_camera_controller->get_transform()); + m_light_paths_layer->update(); } -void LightPathsTab::create_light_paths_widget() +void LightPathsViewportManager::create_light_paths_widget() { // Create the OpenGL widget. const CanvasProperties& props = m_project.get_frame()->image().properties(); m_light_paths_widget = - new LightPathsWidget( + new LightPathsLayer( m_project, props.m_canvas_width, props.m_canvas_height); @@ -191,7 +175,7 @@ void LightPathsTab::create_light_paths_widget() SLOT(slot_context_menu(const QPoint&))); } -void LightPathsTab::create_toolbar() +void LightPathsViewportManager::create_toolbar() { // Create the render toolbar. m_toolbar = new QToolBar(); @@ -267,7 +251,7 @@ void LightPathsTab::create_toolbar() m_toolbar->addWidget(m_info_label); } -void LightPathsTab::create_scrollarea() +void LightPathsViewportManager::create_scrollarea() { // Encapsulate the OpenGL widget into another widget that adds a margin around it. QWidget* gl_widget_wrapper = new QWidget(); @@ -284,7 +268,7 @@ void LightPathsTab::create_scrollarea() m_scroll_area->setWidget(gl_widget_wrapper); } -void LightPathsTab::recreate_handlers() +void LightPathsViewportManager::recreate_handlers() { // Handler for zooming the render widget in and out with the keyboard or the mouse wheel. m_zoom_handler.reset( diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathstab.h b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h similarity index 92% rename from src/appleseed.studio/mainwindow/rendering/lightpathstab.h rename to src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h index 223c755325..d3f1452529 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathstab.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h @@ -47,7 +47,7 @@ #include // Forward declarations. -namespace appleseed { namespace studio { class LightPathsWidget; } } +namespace appleseed { namespace studio { class LightPathsLayer; } } namespace renderer { class ParamArray; } namespace renderer { class Project; } class QLabel; @@ -61,16 +61,16 @@ namespace appleseed { namespace studio { // -// A tab providing an hardware-accelerated visualization of recorded light paths. +// Manager for the light paths display overlay into the viewport // -class LightPathsTab - : public QWidget +class LightPathsViewportManager + : public QObject { Q_OBJECT public: - LightPathsTab( + LightPathsViewportManager( renderer::Project& project, renderer::ParamArray& settings); @@ -89,7 +89,7 @@ class LightPathsTab private: renderer::Project& m_project; renderer::ParamArray& m_settings; - LightPathsWidget* m_light_paths_widget; + LightPathsLayer* m_light_paths_layer; QScrollArea* m_scroll_area; QToolBar* m_toolbar; QToolButton* m_prev_path_button; diff --git a/src/appleseed.studio/mainwindow/rendering/qttilecallback.cpp b/src/appleseed.studio/mainwindow/rendering/qttilecallback.cpp index 7984d7e39e..bd8520a40e 100644 --- a/src/appleseed.studio/mainwindow/rendering/qttilecallback.cpp +++ b/src/appleseed.studio/mainwindow/rendering/qttilecallback.cpp @@ -31,7 +31,8 @@ #include "qttilecallback.h" // appleseed.studio headers. -#include "mainwindow/rendering/renderwidget.h" +#include "mainwindow/rendering/renderlayer.h" +#include "mainwindow/rendering/viewportwidget.h" // Qt headers. #include @@ -59,12 +60,12 @@ namespace Q_OBJECT public: - explicit QtTileCallback(RenderWidget* render_widget) - : m_render_widget(render_widget) + explicit QtTileCallback(ViewportWidget* viewport_widget) + : m_render_layer(viewport_widget->get_render_layer()) { connect( this, SIGNAL(signal_update()), - m_render_widget, SLOT(update()), + viewport_widget, SLOT(repaint()), Qt::QueuedConnection); } @@ -78,8 +79,8 @@ namespace const size_t tile_x, const size_t tile_y) override { - assert(m_render_widget); - m_render_widget->highlight_tile(*frame, tile_x, tile_y); + assert(m_render_layer); + m_render_layer->highlight_tile(*frame, tile_x, tile_y); emit signal_update(); } @@ -88,16 +89,16 @@ namespace const size_t tile_x, const size_t tile_y) override { - assert(m_render_widget); - m_render_widget->blit_tile(*frame, tile_x, tile_y); + assert(m_render_layer); + m_render_layer->blit_tile(*frame, tile_x, tile_y); emit signal_update(); } void on_progressive_frame_update( const Frame* frame) override { - assert(m_render_widget); - m_render_widget->blit_frame(*frame); + assert(m_render_layer); + m_render_layer->blit_frame(*frame); emit signal_update(); } @@ -105,7 +106,7 @@ namespace void signal_update(); private: - RenderWidget* m_render_widget; + RenderLayer* m_render_layer; }; } @@ -114,8 +115,8 @@ namespace // QtTileCallbackFactory class implementation. // -QtTileCallbackFactory::QtTileCallbackFactory(RenderWidget* render_widget) - : m_render_widget(render_widget) +QtTileCallbackFactory::QtTileCallbackFactory(ViewportWidget* viewport_widget) + : m_viewport_widget(viewport_widget) { } @@ -126,7 +127,7 @@ void QtTileCallbackFactory::release() ITileCallback* QtTileCallbackFactory::create() { - return new QtTileCallback(m_render_widget); + return new QtTileCallback(m_viewport_widget); } } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/qttilecallback.h b/src/appleseed.studio/mainwindow/rendering/qttilecallback.h index 1366a341f5..91c7e3bc3b 100644 --- a/src/appleseed.studio/mainwindow/rendering/qttilecallback.h +++ b/src/appleseed.studio/mainwindow/rendering/qttilecallback.h @@ -36,7 +36,7 @@ #include "foundation/platform/compiler.h" // Forward declarations. -namespace appleseed { namespace studio { class RenderWidget; } } +namespace appleseed { namespace studio { class ViewportWidget; } } namespace appleseed { namespace studio { @@ -46,7 +46,7 @@ class QtTileCallbackFactory { public: // Constructor. - explicit QtTileCallbackFactory(RenderWidget* render_widget); + explicit QtTileCallbackFactory(ViewportWidget* viewport_widget); // Delete this instance. void release() override; @@ -55,7 +55,7 @@ class QtTileCallbackFactory renderer::ITileCallback* create() override; private: - RenderWidget* m_render_widget; + ViewportWidget* m_viewport_widget; }; } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp b/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp index b33848d627..69f1857941 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp +++ b/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp @@ -34,7 +34,7 @@ #include "mainwindow/rendering/cameracontroller.h" #include "mainwindow/rendering/qttilecallback.h" #include "mainwindow/rendering/rendertab.h" -#include "mainwindow/rendering/renderwidget.h" +#include "mainwindow/rendering/viewportwidget.h" #include "mainwindow/statusbar.h" // appleseed.shared headers. @@ -203,14 +203,14 @@ void RenderingManager::start_rendering( m_rendering_mode = rendering_mode; m_render_tab = render_tab; - m_render_tab->get_render_widget()->start_render(); + m_render_tab->get_viewport_widget()->get_render_layer()->start_render(); TileCallbackCollectionFactory* tile_callback_collection_factory = new TileCallbackCollectionFactory(); tile_callback_collection_factory->insert( new QtTileCallbackFactory( - m_render_tab->get_render_widget())); + m_render_tab->get_viewport_widget())); tile_callback_collection_factory->insert( new ProgressTileCallbackFactory( @@ -507,7 +507,7 @@ void RenderingManager::slot_frame_end() m_status_bar.stop_rendering_time_display(); // Ensure that the render widget is up-to-date. - m_render_tab->get_render_widget()->update(); + m_render_tab->get_viewport_widget()->update(); } void RenderingManager::slot_camera_change_begin() diff --git a/src/appleseed.studio/mainwindow/rendering/renderwidget.cpp b/src/appleseed.studio/mainwindow/rendering/renderlayer.cpp similarity index 89% rename from src/appleseed.studio/mainwindow/rendering/renderwidget.cpp rename to src/appleseed.studio/mainwindow/rendering/renderlayer.cpp index 3bd16708fb..6238e5bda3 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderwidget.cpp +++ b/src/appleseed.studio/mainwindow/rendering/renderlayer.cpp @@ -28,7 +28,7 @@ // // Interface header. -#include "renderwidget.h" +#include "renderlayer.h" // appleseed.renderer headers. #include "renderer/api/frame.h" @@ -48,6 +48,7 @@ #include #include #include +#include #include // Standard headers. @@ -62,10 +63,10 @@ namespace appleseed { namespace studio { // -// RenderWidget class implementation. +// RenderLayer class implementation. // -RenderWidget::RenderWidget( +RenderLayer::RenderLayer( const size_t width, const size_t height, OCIO::ConstConfigRcPtr ocio_config, @@ -87,14 +88,19 @@ RenderWidget::RenderWidget( setAcceptDrops(true); } -QImage RenderWidget::capture() +QImage RenderLayer::capture() { QMutexLocker locker(&m_mutex); return m_image.copy(); } -void RenderWidget::resize( +void RenderLayer::darken() +{ + multiply(0.2f); +} + +void RenderLayer::resize( const size_t width, const size_t height) { @@ -112,7 +118,7 @@ void RenderWidget::resize( clear(); } -void RenderWidget::clear() +void RenderLayer::clear() { QMutexLocker locker(&m_mutex); @@ -137,14 +143,14 @@ namespace } } -void RenderWidget::start_render() +void RenderLayer::start_render() { // Clear the image storage. if (m_image_storage) m_image_storage->clear(Color4f(0.0f)); } -void RenderWidget::multiply(const float multiplier) +void RenderLayer::multiply(const float multiplier) { QMutexLocker locker(&m_mutex); @@ -200,7 +206,7 @@ namespace } } -void RenderWidget::highlight_tile( +void RenderLayer::highlight_tile( const Frame& frame, const size_t tile_x, const size_t tile_y) @@ -243,7 +249,7 @@ void RenderWidget::highlight_tile( sizeof(BracketColor)); } -void RenderWidget::blit_tile( +void RenderLayer::blit_tile( const Frame& frame, const size_t tile_x, const size_t tile_y) @@ -256,7 +262,7 @@ void RenderWidget::blit_tile( update_tile_no_lock(tile_x, tile_y); } -void RenderWidget::blit_frame(const Frame& frame) +void RenderLayer::blit_frame(const Frame& frame) { QMutexLocker locker(&m_mutex); @@ -274,7 +280,7 @@ void RenderWidget::blit_frame(const Frame& frame) } } -void RenderWidget::slot_display_transform_changed(const QString& transform) +void RenderLayer::slot_display_transform_changed(const QString& transform) { { QMutexLocker locker(&m_mutex); @@ -321,7 +327,7 @@ namespace } } -void RenderWidget::allocate_working_storage(const CanvasProperties& frame_props) +void RenderLayer::allocate_working_storage(const CanvasProperties& frame_props) { if (!m_image_storage || !is_compatible(*m_image_storage, frame_props)) { @@ -356,7 +362,7 @@ void RenderWidget::allocate_working_storage(const CanvasProperties& frame_props) } } -void RenderWidget::blit_tile_no_lock( +void RenderLayer::blit_tile_no_lock( const Frame& frame, const size_t tile_x, const size_t tile_y) @@ -369,7 +375,7 @@ void RenderWidget::blit_tile_no_lock( dst_tile.copy_from(src_tile); } -void RenderWidget::update_tile_no_lock(const size_t tile_x, const size_t tile_y) +void RenderLayer::update_tile_no_lock(const size_t tile_x, const size_t tile_y) { // Retrieve the source tile. const Tile& src_tile = m_image_storage->tile(tile_x, tile_y); @@ -419,39 +425,11 @@ void RenderWidget::update_tile_no_lock(const size_t tile_x, const size_t tile_y) NativeDrawing::blit(dest, dest_stride, uint8_rgb_tile); } -void RenderWidget::paintEvent(QPaintEvent* event) +void RenderLayer::paint(const QRect& rect, QPainter& painter) { QMutexLocker locker(&m_mutex); - m_painter.begin(this); - m_painter.drawImage(rect(), m_image); - m_painter.end(); -} - -void RenderWidget::dragEnterEvent(QDragEnterEvent* event) -{ - if (event->mimeData()->hasFormat("text/plain")) - event->acceptProposedAction(); -} - -void RenderWidget::dragMoveEvent(QDragMoveEvent* event) -{ - if (pos().x() <= event->pos().x() && pos().y() <= event->pos().y() - && event->pos().x() < pos().x() + width() && event->pos().y() < pos().y() + height()) - { - event->accept(); - } - else - event->ignore(); -} - -void RenderWidget::dropEvent(QDropEvent* event) -{ - emit signal_material_dropped( - Vector2d( - static_cast(event->pos().x()) / width(), - static_cast(event->pos().y()) / height()), - event->mimeData()->text()); + painter.drawImage(rect, m_image); } } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/renderwidget.h b/src/appleseed.studio/mainwindow/rendering/renderlayer.h similarity index 92% rename from src/appleseed.studio/mainwindow/rendering/renderwidget.h rename to src/appleseed.studio/mainwindow/rendering/renderlayer.h index b47f3d90ca..f2920c334d 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderwidget.h +++ b/src/appleseed.studio/mainwindow/rendering/renderlayer.h @@ -59,6 +59,7 @@ class QDragEnterEvent; class QDragMoveEvent; class QDropEvent; class QPaintEvent; +class QRect; namespace appleseed { namespace studio { @@ -67,7 +68,7 @@ namespace studio { // A render widget based on QImage. // -class RenderWidget +class RenderLayer : public QWidget , public ICapturableWidget { @@ -75,7 +76,7 @@ class RenderWidget public: // Constructor. - RenderWidget( + RenderLayer( const size_t width, const size_t height, OCIO::ConstConfigRcPtr ocio_config, @@ -84,6 +85,9 @@ class RenderWidget // Thread-safe. QImage capture() override; + // Thread-safe. + void darken(); + // Thread-safe. void resize( const size_t width, @@ -113,6 +117,9 @@ class RenderWidget // Thread-safe. void blit_frame(const renderer::Frame& frame); + // Thread-safe. Paint self into specified painter. + void paint(const QRect& rect, QPainter& painter); + // Direct access to internals for high-performance drawing. QMutex& mutex(); QImage& image(); @@ -146,24 +153,19 @@ class RenderWidget void update_tile_no_lock( const size_t tile_x, const size_t tile_y); - - void paintEvent(QPaintEvent* event) override; - void dragEnterEvent(QDragEnterEvent* event) override; - void dragMoveEvent(QDragMoveEvent* event) override; - void dropEvent(QDropEvent* event) override; }; // -// RenderWidget class implementation. +// RenderLayer class implementation. // -inline QMutex& RenderWidget::mutex() +inline QMutex& RenderLayer::mutex() { return m_mutex; } -inline QImage& RenderWidget::image() +inline QImage& RenderLayer::image() { return m_image; } diff --git a/src/appleseed.studio/mainwindow/rendering/rendertab.cpp b/src/appleseed.studio/mainwindow/rendering/rendertab.cpp index afa23ce961..6634f7569f 100644 --- a/src/appleseed.studio/mainwindow/rendering/rendertab.cpp +++ b/src/appleseed.studio/mainwindow/rendering/rendertab.cpp @@ -32,7 +32,7 @@ // appleseed.studio headers. #include "mainwindow/project/projectexplorer.h" -#include "mainwindow/rendering/renderwidget.h" +#include "mainwindow/rendering/viewportwidget.h" #include "utility/miscellaneous.h" // appleseed.renderer headers. @@ -88,7 +88,7 @@ RenderTab::RenderTab( layout()->setSpacing(0); layout()->setMargin(0); - create_render_widget(); + create_viewport_widget(); create_toolbar(); create_scrollarea(); @@ -98,9 +98,9 @@ RenderTab::RenderTab( recreate_handlers(); } -RenderWidget* RenderTab::get_render_widget() const +ViewportWidget* RenderTab::get_viewport_widget() const { - return m_render_widget; + return m_viewport_widget; } CameraController* RenderTab::get_camera_controller() const @@ -124,17 +124,6 @@ void RenderTab::set_render_region_buttons_enabled(const bool enabled) m_clear_render_region_button->setEnabled(enabled); } -void RenderTab::clear() -{ - m_render_widget->clear(); - m_render_widget->repaint(); -} - -void RenderTab::darken() -{ - m_render_widget->multiply(0.2f); -} - void RenderTab::reset_zoom() { m_zoom_handler->reset_zoom(); @@ -142,7 +131,7 @@ void RenderTab::reset_zoom() void RenderTab::update() { - m_render_widget->update(); + m_viewport_widget->update(); } void RenderTab::update_size() @@ -151,7 +140,7 @@ void RenderTab::update_size() const CanvasProperties& props = m_project.get_frame()->image().properties(); - m_render_widget->resize( + m_viewport_widget->resize( props.m_canvas_width, props.m_canvas_height); @@ -173,11 +162,6 @@ void RenderTab::load_state(const State& state) m_pan_handler->load_state(state.m_pan_handler_state); } -void RenderTab::slot_render_widget_context_menu(const QPoint& point) -{ - emit signal_render_widget_context_menu(m_render_widget->mapToGlobal(point)); -} - void RenderTab::slot_toggle_render_region(const bool checked) { m_scene_picking_handler->set_enabled(!checked); @@ -199,23 +183,32 @@ void RenderTab::slot_toggle_pixel_inspector(const bool checked) m_pixel_inspector_handler->update_tooltip_visibility(); } -void RenderTab::create_render_widget() +void RenderTab::create_viewport_widget() { const CanvasProperties& props = m_project.get_frame()->image().properties(); - m_render_widget = - new RenderWidget( + m_viewport_widget = + new ViewportWidget( + m_project, props.m_canvas_width, props.m_canvas_height, - m_ocio_config); + m_ocio_config, + this); - m_render_widget->setContextMenuPolicy(Qt::CustomContextMenu); + m_viewport_widget->setContextMenuPolicy(Qt::CustomContextMenu); connect( - m_render_widget, SIGNAL(customContextMenuRequested(const QPoint&)), + m_viewport_widget, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(slot_render_widget_context_menu(const QPoint&))); - m_render_widget->setMouseTracking(true); + connect( + this, SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), + m_viewport_widget->get_render_layer(), SLOT(slot_entity_picked(renderer::ScenePicker::PickingResult))); + connect( + this, SIGNAL(signal_rectangle_selection(const QRect&)), + m_viewport_widget->get_render_layer(), SLOT(slot_rectangle_selection(const QRect&))); + + m_viewport_widget->setMouseTracking(true); } void RenderTab::create_toolbar() @@ -323,7 +316,7 @@ void RenderTab::create_toolbar() m_toolbar->addWidget(display_label); // Create the display combobox. - QComboBox* m_display_transform_combo = new QComboBox(); + m_display_transform_combo = new QComboBox(); m_display_transform_combo->setObjectName("display_combo"); { const char* display_name = m_ocio_config->getDefaultDisplay(); @@ -344,7 +337,7 @@ void RenderTab::create_toolbar() m_toolbar->addWidget(m_display_transform_combo); connect( m_display_transform_combo, SIGNAL(currentIndexChanged(QString)), - m_render_widget, SLOT(slot_display_transform_changed(QString))); + m_viewport_widget->get_render_layer(), SLOT(slot_display_transform_changed(QString))); // Add stretchy spacer. // This places interactive widgets on the left and info on the right. @@ -390,7 +383,7 @@ void RenderTab::create_scrollarea() render_widget_wrapper->setLayout(new QGridLayout()); render_widget_wrapper->layout()->setSizeConstraint(QLayout::SetFixedSize); render_widget_wrapper->layout()->setContentsMargins(20, 20, 20, 20); - render_widget_wrapper->layout()->addWidget(m_render_widget); + render_widget_wrapper->layout()->addWidget(m_viewport_widget); // Wrap the render widget in a scroll area. m_scroll_area = new QScrollArea(); @@ -405,7 +398,7 @@ void RenderTab::recreate_handlers() m_zoom_handler.reset( new WidgetZoomHandler( m_scroll_area, - m_render_widget)); + m_viewport_widget)); // Handler for panning the render widget with the mouse. m_pan_handler.reset( @@ -415,13 +408,13 @@ void RenderTab::recreate_handlers() // Handler for tracking and displaying mouse coordinates. m_mouse_tracker.reset( new MouseCoordinatesTracker( - m_render_widget, + m_viewport_widget, m_info_label)); - // Handle for tracking and displaying the color of the pixel under the mouse cursor. + // Handler for tracking and displaying the color of the pixel under the mouse cursor. m_pixel_color_tracker.reset( new PixelColorTracker( - m_render_widget, + m_viewport_widget, m_r_label, m_g_label, m_b_label, @@ -432,14 +425,14 @@ void RenderTab::recreate_handlers() // Handler for pixel inspection in the render widget. m_pixel_inspector_handler.reset( new PixelInspectorHandler( - m_render_widget, + m_viewport_widget, *m_mouse_tracker.get(), m_project)); // Camera handler. m_camera_controller.reset( new CameraController( - m_render_widget, + m_viewport_widget, m_project)); connect( m_camera_controller.get(), SIGNAL(signal_camera_change_begin()), @@ -457,7 +450,7 @@ void RenderTab::recreate_handlers() // Handler for picking scene entities in the render widget. m_scene_picking_handler.reset( new ScenePickingHandler( - m_render_widget, + m_viewport_widget, m_picking_mode_combo, *m_mouse_tracker.get(), m_project_explorer, @@ -472,7 +465,7 @@ void RenderTab::recreate_handlers() // Handler for setting render regions with the mouse. m_render_region_handler.reset( new RenderRegionHandler( - m_render_widget, + m_viewport_widget, *m_mouse_tracker.get())); connect( m_render_region_handler.get(), SIGNAL(signal_rectangle_selection(const QRect&)), @@ -482,7 +475,7 @@ void RenderTab::recreate_handlers() SLOT(slot_set_render_region(const QRect&))); // Clipboard handler. - m_clipboard_handler.reset(new RenderClipboardHandler(m_render_widget, m_render_widget)); + m_clipboard_handler.reset(new RenderClipboardHandler(m_viewport_widget, m_viewport_widget)); // Set initial state. m_pixel_inspector_handler->set_enabled(false); @@ -496,7 +489,7 @@ void RenderTab::recreate_handlers() m_rendering_manager)); connect( - m_render_widget, + m_viewport_widget, SIGNAL(signal_material_dropped( const foundation::Vector2d&, const QString&)), diff --git a/src/appleseed.studio/mainwindow/rendering/rendertab.h b/src/appleseed.studio/mainwindow/rendering/rendertab.h index 99c8a4ee2f..c0c0bc5a4c 100644 --- a/src/appleseed.studio/mainwindow/rendering/rendertab.h +++ b/src/appleseed.studio/mainwindow/rendering/rendertab.h @@ -54,7 +54,7 @@ namespace OCIO = OCIO_NAMESPACE; // Forward declarations. namespace appleseed { namespace studio { class ProjectExplorer; } } -namespace appleseed { namespace studio { class RenderWidget; } } +namespace appleseed { namespace studio { class ViewportWidget; } } namespace renderer { class Entity; } namespace renderer { class Project; } namespace renderer { class RenderingManager; } @@ -85,15 +85,13 @@ class RenderTab RenderingManager& rendering_manager, OCIO::ConstConfigRcPtr ocio_config); - RenderWidget* get_render_widget() const; + ViewportWidget* get_viewport_widget() const; CameraController* get_camera_controller() const; ScenePickingHandler* get_scene_picking_handler() const; void set_clear_frame_button_enabled(const bool enabled); void set_render_region_buttons_enabled(const bool enabled); - void clear(); - void darken(); void reset_zoom(); void update(); @@ -113,7 +111,6 @@ class RenderTab void signal_quicksave_frame_and_aovs(); void signal_set_render_region(const QRect& rect); void signal_clear_render_region(); - void signal_render_widget_context_menu(const QPoint& point); void signal_reset_zoom(); void signal_clear_frame(); @@ -125,19 +122,19 @@ class RenderTab void signal_rectangle_selection(const QRect& rect); private slots: - void slot_render_widget_context_menu(const QPoint& point); void slot_toggle_render_region(const bool checked); void slot_set_render_region(const QRect& rect); void slot_toggle_pixel_inspector(const bool checked); private: - RenderWidget* m_render_widget; + ViewportWidget* m_viewport_widget; QScrollArea* m_scroll_area; QToolBar* m_toolbar; QToolButton* m_set_render_region_button; QToolButton* m_clear_render_region_button; QToolButton* m_clear_frame_button; QComboBox* m_picking_mode_combo; + QComboBox* m_display_transform_combo; QLabel* m_info_label; QLabel* m_r_label; QLabel* m_g_label; @@ -161,7 +158,7 @@ class RenderTab OCIO::ConstConfigRcPtr m_ocio_config; - void create_render_widget(); + void create_viewport_widget(); void create_toolbar(); void create_scrollarea(); void recreate_handlers(); diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp new file mode 100644 index 0000000000..6cb3bf229a --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp @@ -0,0 +1,210 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2019 Gray Olson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +// Interface header. +#include "viewportwidget.h" + +// appleseed.renderer headers. +#include "renderer/api/frame.h" + +// appleseed.foundation headers. +#include "foundation/image/canvasproperties.h" +#include "foundation/image/image.h" +#include "foundation/image/nativedrawing.h" +#include "foundation/image/tile.h" +#include "foundation/math/scalar.h" +#include "foundation/platform/types.h" + +// Qt headers. +#include +#include +#include +#include +#include +#include +#include +#include + +// Standard headers. +#include +#include + +using namespace foundation; +using namespace renderer; +using namespace std; + +namespace appleseed { +namespace studio { + +// +// ViewportWidget class implementation. +// + +ViewportWidget::ViewportWidget( + const renderer::Project& project, + const size_t width, + const size_t height, + OCIO::ConstConfigRcPtr ocio_config, + QWidget* parent) + : QOpenGLWidget(parent) + , m_project(project) +{ + setFocusPolicy(Qt::StrongFocus); + setFixedWidth(static_cast(width)); + setFixedHeight(static_cast(height)); + setAutoFillBackground(false); + setAttribute(Qt::WA_OpaquePaintEvent, true); + + create_render_layer(ocio_config); + //create_gl_scene_layer(); + //create_light_paths_layer(); + + resize(width, height); + + setAcceptDrops(true); +} + +void ViewportWidget::create_render_layer(OCIO::ConstConfigRcPtr ocio_config) +{ + m_render_layer = + std::unique_ptr(new RenderLayer( + m_width, + m_height, + ocio_config)); +} + +//void ViewportWidget::create_gl_scene_layer() +//{ +// m_gl_scene_layer = +// std::unique_ptr(new GLSceneLayer( +// m_project, +// m_width, +// m_height)); +//} +// +//void ViewportWidget::create_light_paths_layer() +//{ +// m_light_paths_layer = +// std::unique_ptr(new LightPathsLayer( +// m_project, +// m_width, +// m_height)); +//} + +RenderLayer* ViewportWidget::get_render_layer() +{ + return m_render_layer.get(); +} + +//LightPathsLayer* ViewportWidget::get_light_paths_layer() +//{ +// return m_light_paths_layer.get(); +//} +// +//GLSceneLayer* ViewportWidget::get_gl_scene_layer() +//{ +// return m_gl_scene_layer.get(); +//} + +QImage ViewportWidget::capture() +{ + return grabFramebuffer(); +} + +void ViewportWidget::initializeGL() { + m_gl = QOpenGLContext::currentContext()->versionFunctions(); + + const auto qs_format = format(); + if (!m_gl->initializeOpenGLFunctions()) + { + const int major_version = qs_format.majorVersion(); + const int minor_version = qs_format.minorVersion(); + RENDERER_LOG_ERROR( + "opengl: could not load required gl functions. loaded version %d.%d, required version 3.3", + major_version, + minor_version); + return; + } + + //m_gl_scene_layer->set_gl_functions(m_gl); + //m_gl_scene_layer->init_gl(qs_format); + //m_light_paths_layer->set_gl_functions(m_gl); + //m_light_paths_layer->init_gl(qs_format); +} + +void ViewportWidget::resize( + const size_t width, + const size_t height) +{ + m_render_layer->resize(width, height); +} + +void ViewportWidget::paintEvent(QPaintEvent* event) +{ + m_painter.begin(this); + m_render_layer->paint(rect(), m_painter); + m_painter.end(); + //m_painter.beginNativePainting(); + //m_gl_scene_layer->draw_depth_only(); + //m_light_paths_layer->draw(); + //m_painter.endNativePainting(); +} + +void ViewportWidget::dragEnterEvent(QDragEnterEvent* event) +{ + if (event->mimeData()->hasFormat("text/plain")) + event->acceptProposedAction(); +} + +void ViewportWidget::dragMoveEvent(QDragMoveEvent* event) +{ + if (pos().x() <= event->pos().x() && pos().y() <= event->pos().y() + && event->pos().x() < pos().x() + width() && event->pos().y() < pos().y() + height()) + { + event->accept(); + } + else + event->ignore(); +} + +void ViewportWidget::dropEvent(QDropEvent* event) +{ + emit signal_material_dropped( + Vector2d( + static_cast(event->pos().x()) / width(), + static_cast(event->pos().y()) / height()), + event->mimeData()->text()); +} + +void ViewportWidget::slot_viewport_widget_context_menu(const QPoint& point) +{ + emit signal_viewport_widget_context_menu(mapToGlobal(point)); +} + +} // namespace studio +} // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h new file mode 100644 index 0000000000..307b23f804 --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h @@ -0,0 +1,141 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2019 Gray Olson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#pragma once + +// appleseed.studio headers. +#include "mainwindow/rendering/lightpathslayer.h" +#include "mainwindow/rendering/renderclipboardhandler.h" +#include "mainwindow/rendering/renderlayer.h" +#include "mainwindow/rendering/glscenelayer.h" + +// appleseed.foundation headers. +#include "foundation/image/image.h" +#include "foundation/image/tile.h" +#include "foundation/math/vector.h" + +// Qt headers. +#include +#include +#include +#include +#include + +// OpenColorIO headers. +#include +namespace OCIO = OCIO_NAMESPACE; + +// Standard headers. +#include +#include +#include + +// Forward declarations. +namespace foundation { class CanvasProperties; } +namespace renderer { class Frame; } +class QDragEnterEvent; +class QDragMoveEvent; +class QDropEvent; +class QPaintEvent; +class QOpenGLFunctions_3_3_Core; + +namespace appleseed { +namespace studio { + +// +// A render widget based on QImage. +// + +class ViewportWidget + : public QOpenGLWidget + , public ICapturableWidget +{ + Q_OBJECT + + public: + // Constructor. + ViewportWidget( + const renderer::Project& project, + const size_t width, + const size_t height, + OCIO::ConstConfigRcPtr ocio_config, + QWidget* parent = nullptr); + + // Thread-safe. + QImage capture() override; + + // Thread-safe. + void resize( + const size_t width, + const size_t height); + + RenderLayer* get_render_layer(); + //GLSceneLayer* get_gl_scene_layer(); + //LightPathsLayer* get_light_paths_layer(); + + // Thread-safe. + //void highlight_tile( + // const renderer::Frame& frame, + // const size_t tile_x, + // const size_t tile_y); + + signals: + void signal_material_dropped( + const foundation::Vector2d& drop_pos, + const QString& material_name); + void signal_viewport_widget_context_menu(const QPoint& point); + + private slots: + void slot_viewport_widget_context_menu(const QPoint& point); + + private: + const renderer::Project& m_project; + int m_width; + int m_height; + + QOpenGLFunctions_3_3_Core* m_gl; + QPainter m_painter; + + std::unique_ptr m_render_layer; + //std::unique_ptr m_gl_scene_layer; + //std::unique_ptr m_light_paths_layer; + + void create_render_layer(OCIO::ConstConfigRcPtr ocio_config); + //void create_gl_scene_layer(); + //void create_light_paths_layer(); + + void initializeGL() override; + void paintEvent(QPaintEvent* event) override; + void dragEnterEvent(QDragEnterEvent* event) override; + void dragMoveEvent(QDragMoveEvent* event) override; + void dropEvent(QDropEvent* event) override; +}; + + +} // namespace studio +} // namespace appleseed From 2362c848226491190dc07abe8ad038b8abe4f62e Mon Sep 17 00:00:00 2001 From: Gray Olson Date: Wed, 12 Jun 2019 12:53:06 -0700 Subject: [PATCH 2/6] Option to display OpenGL scene view in viewport --- sandbox/settings/appleseed.studio.xml | 2 +- src/appleseed.studio/CMakeLists.txt | 8 +- .../mainwindow/mainwindow.cpp | 117 ++++++++-------- src/appleseed.studio/mainwindow/mainwindow.h | 18 +-- .../mainwindow/rendering/glscenelayer.cpp | 130 +++++++++++------- .../mainwindow/rendering/glscenelayer.h | 12 +- .../mainwindow/rendering/renderingmanager.cpp | 26 ++-- .../mainwindow/rendering/renderingmanager.h | 6 +- .../{rendertab.cpp => viewporttab.cpp} | 92 +++++++++---- .../rendering/{rendertab.h => viewporttab.h} | 11 +- .../mainwindow/rendering/viewportwidget.cpp | 88 ++++++++---- .../mainwindow/rendering/viewportwidget.h | 32 +++-- .../modeling/camera/orthographiccamera.cpp | 22 +-- .../modeling/camera/perspectivecamera.cpp | 28 ++-- 14 files changed, 360 insertions(+), 232 deletions(-) rename src/appleseed.studio/mainwindow/rendering/{rendertab.cpp => viewporttab.cpp} (86%) rename src/appleseed.studio/mainwindow/rendering/{rendertab.h => viewporttab.h} (94%) diff --git a/sandbox/settings/appleseed.studio.xml b/sandbox/settings/appleseed.studio.xml index c6c30570ff..d05b62c17e 100644 --- a/sandbox/settings/appleseed.studio.xml +++ b/sandbox/settings/appleseed.studio.xml @@ -1,7 +1,7 @@ - + diff --git a/src/appleseed.studio/CMakeLists.txt b/src/appleseed.studio/CMakeLists.txt index 7f7e251860..11cebbd8d7 100644 --- a/src/appleseed.studio/CMakeLists.txt +++ b/src/appleseed.studio/CMakeLists.txt @@ -248,8 +248,8 @@ source_group ("mainwindow\\pythonconsole" FILES set (mainwindow_rendering_sources mainwindow/rendering/cameracontroller.cpp mainwindow/rendering/cameracontroller.h - # mainwindow/rendering/glscenelayer.h - # mainwindow/rendering/glscenelayer.cpp + mainwindow/rendering/glscenelayer.h + mainwindow/rendering/glscenelayer.cpp # mainwindow/rendering/lightpathspickinghandler.cpp # mainwindow/rendering/lightpathspickinghandler.h # mainwindow/rendering/lightpathsviewportmanager.cpp @@ -273,12 +273,12 @@ set (mainwindow_rendering_sources mainwindow/rendering/renderingtimer.h mainwindow/rendering/renderregionhandler.cpp mainwindow/rendering/renderregionhandler.h - mainwindow/rendering/rendertab.cpp - mainwindow/rendering/rendertab.h mainwindow/rendering/renderlayer.cpp mainwindow/rendering/renderlayer.h mainwindow/rendering/scenepickinghandler.cpp mainwindow/rendering/scenepickinghandler.h + mainwindow/rendering/viewporttab.cpp + mainwindow/rendering/viewporttab.h mainwindow/rendering/viewportwidget.h mainwindow/rendering/viewportwidget.cpp ) diff --git a/src/appleseed.studio/mainwindow/mainwindow.cpp b/src/appleseed.studio/mainwindow/mainwindow.cpp index dc4bb0527a..c3363e702d 100644 --- a/src/appleseed.studio/mainwindow/mainwindow.cpp +++ b/src/appleseed.studio/mainwindow/mainwindow.cpp @@ -202,7 +202,7 @@ bool MainWindow::open_project(const QString& filepath) m_rendering_manager.wait_until_rendering_end(); } - remove_render_tabs(); + remove_viewport_tabs(); set_file_widgets_enabled(false, NotRendering); set_project_explorer_enabled(false); @@ -217,7 +217,7 @@ bool MainWindow::open_project(const QString& filepath) } else { - recreate_render_tabs(); + recreate_viewport_tabs(); update_workspace(); } @@ -234,7 +234,7 @@ void MainWindow::open_project_async(const QString& filepath) m_rendering_manager.wait_until_rendering_end(); } - remove_render_tabs(); + remove_viewport_tabs(); set_file_widgets_enabled(false, NotRendering); set_project_explorer_enabled(false); @@ -743,10 +743,17 @@ void MainWindow::update_workspace() m_ui->attribute_editor_scrollarea_contents->setEnabled(true); // Add/remove light paths tab. - //if (m_project_manager.is_project_open() && - // m_project_manager.get_project()->get_light_path_recorder().get_light_path_count() > 0) - // add_light_paths_tab(); - //else remove_light_paths_tab(); + if (m_project_manager.is_project_open() && + m_project_manager.get_project()->get_light_path_recorder().get_light_path_count() > 0) + { + for (const_each i = m_viewport_tabs; i; ++i) + i->second->enable_light_paths_toggle(); + } + else + { + for (const_each i = m_viewport_tabs; i; ++i) + i->second->disable_light_paths_toggle(); + } } void MainWindow::update_project_explorer() @@ -891,21 +898,21 @@ void MainWindow::set_rendering_widgets_enabled(const bool is_enabled, const Rend const int current_tab_index = m_ui->tab_render_channels->currentIndex(); if (current_tab_index != -1) { - const auto render_tab_it = m_tab_index_to_render_tab.find(current_tab_index); - if (render_tab_it != m_tab_index_to_render_tab.end()) + const auto viewport_tab_it = m_tab_index_to_viewport_tab.find(current_tab_index); + if (viewport_tab_it != m_tab_index_to_viewport_tab.end()) { - RenderTab* render_tab = render_tab_it->second; + ViewportTab* viewport_tab = viewport_tab_it->second; // Clear frame. - render_tab->set_clear_frame_button_enabled( + viewport_tab->set_clear_frame_button_enabled( is_enabled && is_project_open && rendering_mode == NotRendering); // Set/clear rendering region. - render_tab->set_render_region_buttons_enabled( + viewport_tab->set_render_region_buttons_enabled( is_enabled && is_project_open && rendering_mode != FinalRendering); // Scene picker. - render_tab->get_scene_picking_handler()->set_enabled( + viewport_tab->get_scene_picking_handler()->set_enabled( is_enabled && is_project_open && rendering_mode != FinalRendering); } } @@ -925,18 +932,18 @@ void MainWindow::save_state_before_project_open() m_state_before_project_open->m_is_rendering = m_rendering_manager.is_rendering(); - for (const_each i = m_render_tabs; i; ++i) - m_state_before_project_open->m_render_tab_states[i->first] = i->second->save_state(); + for (const_each i = m_viewport_tabs; i; ++i) + m_state_before_project_open->m_viewport_tab_states[i->first] = i->second->save_state(); } void MainWindow::restore_state_after_project_open() { if (m_state_before_project_open.get()) { - for (const_each i = m_render_tabs; i; ++i) + for (const_each i = m_viewport_tabs; i; ++i) { - const RenderTabStateCollection& tab_states = m_state_before_project_open->m_render_tab_states; - const RenderTabStateCollection::const_iterator tab_state_it = tab_states.find(i->first); + const ViewportTabStateCollection& tab_states = m_state_before_project_open->m_viewport_tab_states; + const ViewportTabStateCollection::const_iterator tab_state_it = tab_states.find(i->first); if (tab_state_it != tab_states.end()) i->second->load_state(tab_state_it->second); @@ -947,31 +954,31 @@ void MainWindow::restore_state_after_project_open() } } -void MainWindow::recreate_render_tabs() +void MainWindow::recreate_viewport_tabs() { - remove_render_tabs(); + remove_viewport_tabs(); if (m_project_manager.is_project_open()) - add_render_tab("RGB"); + add_viewport_tab("RGB"); } -void MainWindow::remove_render_tabs() +void MainWindow::remove_viewport_tabs() { - for (const_each i = m_render_tabs; i; ++i) + for (const_each i = m_viewport_tabs; i; ++i) delete i->second; - m_render_tabs.clear(); - m_tab_index_to_render_tab.clear(); + m_viewport_tabs.clear(); + m_tab_index_to_viewport_tab.clear(); while (m_ui->tab_render_channels->count() > 0) m_ui->tab_render_channels->removeTab(0); } -void MainWindow::add_render_tab(const QString& label) +void MainWindow::add_viewport_tab(const QString& label) { // Create render tab. - RenderTab* render_tab = - new RenderTab( + ViewportTab* viewport_tab = + new ViewportTab( *m_project_explorer, *m_project_manager.get_project(), m_rendering_manager, @@ -979,45 +986,45 @@ void MainWindow::add_render_tab(const QString& label) // Connect the render tab to the main window and the rendering manager. connect( - render_tab->get_viewport_widget(), SIGNAL(signal_viewport_widget_context_menu(const QPoint&)), + viewport_tab, SIGNAL(signal_viewport_widget_context_menu(const QPoint&)), SLOT(slot_viewport_widget_context_menu(const QPoint&))); connect( - render_tab, SIGNAL(signal_set_render_region(const QRect&)), + viewport_tab, SIGNAL(signal_set_render_region(const QRect&)), SLOT(slot_set_render_region(const QRect&))); connect( - render_tab, SIGNAL(signal_clear_render_region()), + viewport_tab, SIGNAL(signal_clear_render_region()), SLOT(slot_clear_render_region())); connect( - render_tab, SIGNAL(signal_save_frame_and_aovs()), + viewport_tab, SIGNAL(signal_save_frame_and_aovs()), SLOT(slot_save_frame_and_aovs())); connect( - render_tab, SIGNAL(signal_quicksave_frame_and_aovs()), + viewport_tab, SIGNAL(signal_quicksave_frame_and_aovs()), SLOT(slot_quicksave_frame_and_aovs())); connect( - render_tab, SIGNAL(signal_reset_zoom()), + viewport_tab, SIGNAL(signal_reset_zoom()), SLOT(slot_reset_zoom())); connect( - render_tab, SIGNAL(signal_clear_frame()), + viewport_tab, SIGNAL(signal_clear_frame()), SLOT(slot_clear_frame())); connect( - render_tab, SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), + viewport_tab, SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), SLOT(slot_clear_filter())); connect( - render_tab, SIGNAL(signal_camera_change_begin()), + viewport_tab, SIGNAL(signal_camera_change_begin()), &m_rendering_manager, SLOT(slot_camera_change_begin())); connect( - render_tab, SIGNAL(signal_camera_change_end()), + viewport_tab, SIGNAL(signal_camera_change_end()), &m_rendering_manager, SLOT(slot_camera_change_end())); connect( - render_tab, SIGNAL(signal_camera_changed()), + viewport_tab, SIGNAL(signal_camera_changed()), &m_rendering_manager, SLOT(slot_camera_changed())); // Add the render tab to the tab bar. - const int tab_index = m_ui->tab_render_channels->addTab(render_tab, label); + const int tab_index = m_ui->tab_render_channels->addTab(viewport_tab, label); // Update mappings. - m_render_tabs[label.toStdString()] = render_tab; - m_tab_index_to_render_tab[tab_index] = render_tab; + m_viewport_tabs[label.toStdString()] = viewport_tab; + m_tab_index_to_viewport_tab[tab_index] = viewport_tab; } ParamArray MainWindow::get_project_params(const char* configuration_name) const @@ -1093,7 +1100,7 @@ bool MainWindow::can_close_project() void MainWindow::on_project_change() { update_project_explorer(); - recreate_render_tabs(); + recreate_viewport_tabs(); update_override_shading_menu_item(); m_false_colors_window.reset(); @@ -1209,7 +1216,7 @@ void MainWindow::start_rendering(const RenderingMode rendering_mode) frame->clear_main_and_aov_images(); // Darken render widgets. - for (const_each i = m_render_tabs; i; ++i) + for (const_each i = m_viewport_tabs; i; ++i) { i->second->get_viewport_widget()->get_render_layer()->darken(); i->second->update(); @@ -1227,7 +1234,7 @@ void MainWindow::start_rendering(const RenderingMode rendering_mode) rendering_mode == InteractiveRendering ? RenderingManager::InteractiveRendering : RenderingManager::FinalRendering, - m_render_tabs["RGB"]); + m_viewport_tabs["RGB"]); } void MainWindow::apply_false_colors_settings() @@ -1265,7 +1272,7 @@ void MainWindow::apply_false_colors_settings() else { // Blit the regular frame into the render widget. - for (const_each i = m_render_tabs; i; ++i) + for (const_each i = m_viewport_tabs; i; ++i) { i->second->get_viewport_widget()->get_render_layer()->blit_frame(*frame); i->second->get_viewport_widget()->get_render_layer()->update(); @@ -1288,7 +1295,7 @@ void MainWindow::apply_post_processing_stage( stage.execute(working_frame); // Blit the frame copy into the render widget. - for (const_each i = m_render_tabs; i; ++i) + for (const_each i = m_viewport_tabs; i; ++i) { i->second->get_viewport_widget()->get_render_layer()->blit_frame(working_frame); i->second->get_viewport_widget()->get_render_layer()->update(); @@ -1339,7 +1346,7 @@ void MainWindow::closeEvent(QCloseEvent* event) if (m_benchmark_window.get()) m_benchmark_window->close(); - remove_render_tabs(); + remove_viewport_tabs(); m_project_manager.close_project(); @@ -1459,7 +1466,7 @@ void MainWindow::slot_open_project_complete(const QString& filepath, const bool else { show_project_file_loading_failed_message_box(this, filepath); - recreate_render_tabs(); + recreate_viewport_tabs(); update_workspace(); } } @@ -2035,7 +2042,7 @@ void MainWindow::slot_save_render_widget_content() return; // todo: this is sketchy. The render tab should be retrieved from the signal. - m_render_tabs["RGB"]->get_viewport_widget()->get_render_layer()->capture().save(filepath); + m_viewport_tabs["RGB"]->get_viewport_widget()->get_render_layer()->capture().save(filepath); RENDERER_LOG_INFO("wrote image file %s.", filepath.toStdString().c_str()); } @@ -2046,7 +2053,7 @@ void MainWindow::slot_clear_frame() frame->clear_main_and_aov_images(); // In the UI, clear all render widgets to black. - for (const_each i = m_render_tabs; i; ++i) + for (const_each i = m_viewport_tabs; i; ++i) { i->second->get_viewport_widget()->get_render_layer()->clear(); i->second->get_viewport_widget()->repaint(); @@ -2056,9 +2063,9 @@ void MainWindow::slot_clear_frame() void MainWindow::slot_reset_zoom() { const int current_tab_index = m_ui->tab_render_channels->currentIndex(); - const auto render_tab_it = m_tab_index_to_render_tab.find(current_tab_index); - if (render_tab_it != m_tab_index_to_render_tab.end()) - render_tab_it->second->reset_zoom(); + const auto viewport_tab_it = m_tab_index_to_viewport_tab.find(current_tab_index); + if (viewport_tab_it != m_tab_index_to_viewport_tab.end()) + viewport_tab_it->second->reset_zoom(); } void MainWindow::slot_filter_text_changed(const QString& pattern) @@ -2074,7 +2081,7 @@ void MainWindow::slot_clear_filter() void MainWindow::slot_frame_modified() { - for (each i = m_render_tabs; i; ++i) + for (each i = m_viewport_tabs; i; ++i) i->second->update_size(); } diff --git a/src/appleseed.studio/mainwindow/mainwindow.h b/src/appleseed.studio/mainwindow/mainwindow.h index 95fe126619..19af943b88 100644 --- a/src/appleseed.studio/mainwindow/mainwindow.h +++ b/src/appleseed.studio/mainwindow/mainwindow.h @@ -37,7 +37,7 @@ #include "mainwindow/project/projectmanager.h" #include "mainwindow/qtlogtarget.h" #include "mainwindow/rendering/renderingmanager.h" -#include "mainwindow/rendering/rendertab.h" +#include "mainwindow/rendering/viewporttab.h" #include "mainwindow/renderingsettingswindow.h" #include "mainwindow/statusbar.h" @@ -159,17 +159,17 @@ class MainWindow AttributeEditor* m_attribute_editor; RenderingManager m_rendering_manager; - typedef std::map RenderTabCollection; - typedef std::map RenderTabStateCollection; + typedef std::map ViewportTabCollection; + typedef std::map ViewportTabStateCollection; - RenderTabCollection m_render_tabs; - std::map m_tab_index_to_render_tab; + ViewportTabCollection m_viewport_tabs; + std::map m_tab_index_to_viewport_tab; LightPathsTab* m_light_paths_tab; struct StateBeforeProjectOpen { bool m_is_rendering; - RenderTabStateCollection m_render_tab_states; + ViewportTabStateCollection m_viewport_tab_states; }; std::unique_ptr m_state_before_project_open; @@ -206,9 +206,9 @@ class MainWindow void restore_state_after_project_open(); // Render tabs. - void recreate_render_tabs(); - void remove_render_tabs(); - void add_render_tab(const QString& label); + void recreate_viewport_tabs(); + void remove_viewport_tabs(); + void add_viewport_tab(const QString& label); // Project file handling. renderer::ParamArray get_project_params(const char* configuration_name) const; diff --git a/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp b/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp index a4b6813fa7..c1d3f89d3b 100644 --- a/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp +++ b/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp @@ -126,20 +126,15 @@ namespace { GLSceneLayer::GLSceneLayer( const Project& project, const size_t width, - const size_t height, - QOpenGLFunctions_3_3_Core* functions, - QSurfaceFormat format) + const size_t height) : m_project(project) , m_camera(*m_project.get_uncached_active_camera()) , m_backface_culling_enabled(false) - , m_gl(functions) - , m_gl_initialized(false) - , m_format(format) + , m_initialized(false) { + m_camera.transform_sequence().prepare(); const float time = m_camera.get_shutter_middle_time(); set_transform(m_camera.transform_sequence().evaluate(time)); - - init_gl(); } void GLSceneLayer::set_gl_functions(QOpenGLFunctions_3_3_Core* functions) @@ -414,7 +409,10 @@ namespace { const GLuint frag) { f->glAttachShader(program, vert); - f->glAttachShader(program, frag); + + if (frag != 0) + f->glAttachShader(program, frag); + f->glLinkProgram(program); GLint success; @@ -431,56 +429,63 @@ namespace { void create_shader_program( QOpenGLFunctions_3_3_Core* f, GLuint& program, - const QByteArray& vert_source, - const QByteArray& frag_source) + const QByteArray* vert_source, + const QByteArray* frag_source) { - GLuint vert = f->glCreateShader(GL_VERTEX_SHADER); - GLuint frag = f->glCreateShader(GL_FRAGMENT_SHADER); + bool has_frag_shader = frag_source != nullptr; - auto gl_vert_source = static_cast(vert_source.constData()); - auto gl_vert_source_length = static_cast(vert_source.size()); + GLuint vert = f->glCreateShader(GL_VERTEX_SHADER); + GLuint frag = has_frag_shader ? f->glCreateShader(GL_FRAGMENT_SHADER) : 0; - auto gl_frag_source = static_cast(frag_source.constData()); - auto gl_frag_source_length = static_cast(frag_source.size()); + auto gl_vert_source = static_cast(vert_source->constData()); + auto gl_vert_source_length = static_cast(vert_source->size()); compile_shader(f, vert, 1, &gl_vert_source, &gl_vert_source_length); - compile_shader(f, frag, 1, &gl_frag_source, &gl_frag_source_length); + + if (has_frag_shader) + { + auto gl_frag_source = static_cast(frag_source->constData()); + auto gl_frag_source_length = static_cast(frag_source->size()); + compile_shader(f, frag, 1, &gl_frag_source, &gl_frag_source_length); + } program = f->glCreateProgram(); link_shader_program(f, program, vert, frag); f->glDeleteShader(vert); - f->glDeleteShader(frag); + if (has_frag_shader) + f->glDeleteShader(frag); } } -void GLSceneLayer::init_gl(QSurfaceFormat format) +void GLSceneLayer::initialize(QSurfaceFormat format) { // If there was already previous data, clean up GLSceneLayer::cleanup_gl_data(); - bool manual_srgb_conversion = false; - if (format.colorSpace() != QSurfaceFormat::sRGBColorSpace) - { - manual_srgb_conversion = true; - RENDERER_LOG_WARNING( - "opengl: srgb framebuffer extensions not supported, using slower manual conversion."); - } - - glEnable(GL_DEPTH_TEST); - - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + auto vertex_shader = load_gl_shader("scene.vert"); + auto fragment_shader = load_gl_shader("scene.frag"); create_shader_program( m_gl, m_scene_shader_program, - load_gl_shader("scene.vert"), - load_gl_shader("scene.frag")); + &vertex_shader, + &fragment_shader); m_scene_view_mat_location = m_gl->glGetUniformLocation(m_scene_shader_program, "u_view"); m_scene_proj_mat_location = m_gl->glGetUniformLocation(m_scene_shader_program, "u_proj"); m_scene_camera_pos_location = m_gl->glGetUniformLocation(m_scene_shader_program, "u_camera_pos"); + create_shader_program( + m_gl, + m_depthonly_shader_program, + &vertex_shader, + nullptr); + + m_depthonly_view_mat_location = m_gl->glGetUniformLocation(m_depthonly_shader_program, "u_view"); + m_depthonly_proj_mat_location = m_gl->glGetUniformLocation(m_depthonly_shader_program, "u_proj"); + m_depthonly_camera_pos_location = m_gl->glGetUniformLocation(m_depthonly_shader_program, "u_camera_pos"); + const float z_near = 0.01f; const float z_far = 1000.0f; @@ -503,7 +508,12 @@ void GLSceneLayer::init_gl(QSurfaceFormat format) load_scene_data(); - m_gl_initialized = true; + m_initialized = true; +} + +bool GLSceneLayer::is_initialized() +{ + return m_initialized; } void GLSceneLayer::cleanup_gl_data() @@ -533,6 +543,10 @@ void GLSceneLayer::cleanup_gl_data() { m_gl->glDeleteProgram(m_scene_shader_program); } + if (m_depthonly_shader_program != 0) + { + m_gl->glDeleteProgram(m_depthonly_shader_program); + } m_scene_object_index_map.clear(); m_scene_object_data_index_counts.clear(); m_scene_object_instance_counts.clear(); @@ -541,22 +555,41 @@ void GLSceneLayer::cleanup_gl_data() void GLSceneLayer::draw() { - if (!m_gl_initialized) + if (!m_initialized) return; if (m_backface_culling_enabled) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); + m_gl->glDepthMask(GL_FALSE); + m_gl->glEnable(GL_DEPTH_TEST); + m_gl->glDepthFunc(GL_LEQUAL); m_gl->glUseProgram(m_scene_shader_program); + + m_gl->glUniformMatrix4fv( + m_scene_view_mat_location, + 1, + false, + const_cast(&m_gl_view_matrix[0])); + m_gl->glUniformMatrix4fv( + m_scene_proj_mat_location, + 1, + false, + const_cast(&m_gl_proj_matrix[0])); + m_gl->glUniform3fv( + m_scene_camera_pos_location, + 1, + const_cast(&m_camera_position[0])); + render_scene(); + + m_gl->glDepthMask(GL_TRUE); } void GLSceneLayer::draw_depth_only() { - glClear(GL_DEPTH_BUFFER_BIT); - - if (!m_gl_initialized) + if (!m_initialized) return; if (m_backface_culling_enabled) @@ -564,27 +597,33 @@ void GLSceneLayer::draw_depth_only() else glDisable(GL_CULL_FACE); m_gl->glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + m_gl->glDepthMask(GL_TRUE); + m_gl->glEnable(GL_DEPTH_TEST); + m_gl->glDepthFunc(GL_LEQUAL); m_gl->glUseProgram(m_depthonly_shader_program); - render_scene(); -} -void GLSceneLayer::render_scene() -{ m_gl->glUniformMatrix4fv( - m_scene_view_mat_location, + m_depthonly_view_mat_location, 1, false, const_cast(&m_gl_view_matrix[0])); m_gl->glUniformMatrix4fv( - m_scene_proj_mat_location, + m_depthonly_proj_mat_location, 1, false, const_cast(&m_gl_proj_matrix[0])); m_gl->glUniform3fv( - m_scene_camera_pos_location, + m_depthonly_camera_pos_location, 1, const_cast(&m_camera_position[0])); + render_scene(); + + m_gl->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); +} + +void GLSceneLayer::render_scene() +{ for (size_t i = 0; i < m_scene_object_data_vbos.size(); i++) { GLuint vao = m_scene_object_vaos[i]; @@ -592,7 +631,6 @@ void GLSceneLayer::render_scene() int instance_count = m_scene_object_instance_counts[i]; m_gl->glBindVertexArray(vao); - m_gl->glDrawArraysInstanced( GL_TRIANGLES, 0, diff --git a/src/appleseed.studio/mainwindow/rendering/glscenelayer.h b/src/appleseed.studio/mainwindow/rendering/glscenelayer.h index 6278479e8f..c3cdbcf2a7 100644 --- a/src/appleseed.studio/mainwindow/rendering/glscenelayer.h +++ b/src/appleseed.studio/mainwindow/rendering/glscenelayer.h @@ -85,7 +85,10 @@ class GLSceneLayer void set_gl_functions( QOpenGLFunctions_3_3_Core* functions); - void init_gl(QSurfaceFormat format); + void initialize( + QSurfaceFormat format); + + bool is_initialized(); void draw(); void draw_depth_only(); @@ -112,13 +115,16 @@ class GLSceneLayer std::vector m_scene_object_vaos; std::unordered_map m_scene_object_index_map; GLuint m_scene_shader_program; - GLuint m_depthonly_shader_program; GLint m_scene_view_mat_location; GLint m_scene_proj_mat_location; GLint m_scene_camera_pos_location; + GLuint m_depthonly_shader_program; + GLint m_depthonly_view_mat_location; + GLint m_depthonly_proj_mat_location; + GLint m_depthonly_camera_pos_location; foundation::Matrix4f m_gl_view_matrix; foundation::Matrix4f m_gl_proj_matrix; - bool m_gl_initialized; + bool m_initialized; void render_scene(); diff --git a/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp b/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp index 69f1857941..a92e7e2b34 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp +++ b/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp @@ -33,7 +33,7 @@ // appleseed.studio headers. #include "mainwindow/rendering/cameracontroller.h" #include "mainwindow/rendering/qttilecallback.h" -#include "mainwindow/rendering/rendertab.h" +#include "mainwindow/rendering/viewporttab.h" #include "mainwindow/rendering/viewportwidget.h" #include "mainwindow/statusbar.h" @@ -125,7 +125,7 @@ namespace RenderingManager::RenderingManager(StatusBar& status_bar) : m_status_bar(status_bar) , m_project(nullptr) - , m_render_tab(nullptr) + , m_viewport_tab(nullptr) { Application::initialize_resource_search_paths(m_resource_search_paths); @@ -196,21 +196,21 @@ void RenderingManager::start_rendering( Project* project, const ParamArray& params, const RenderingMode rendering_mode, - RenderTab* render_tab) + ViewportTab* viewport_tab) { m_project = project; m_params = params; m_rendering_mode = rendering_mode; - m_render_tab = render_tab; + m_viewport_tab = viewport_tab; - m_render_tab->get_viewport_widget()->get_render_layer()->start_render(); + m_viewport_tab->get_viewport_widget()->get_render_layer()->start_render(); TileCallbackCollectionFactory* tile_callback_collection_factory = new TileCallbackCollectionFactory(); tile_callback_collection_factory->insert( new QtTileCallbackFactory( - m_render_tab->get_viewport_widget())); + m_viewport_tab->get_viewport_widget())); tile_callback_collection_factory->insert( new ProgressTileCallbackFactory( @@ -437,7 +437,7 @@ void RenderingManager::slot_rendering_begin() run_scheduled_actions(); if (m_rendering_mode == InteractiveRendering) - m_render_tab->get_camera_controller()->set_enabled(true); + m_viewport_tab->get_camera_controller()->set_enabled(true); m_rendering_timer.clear(); @@ -461,10 +461,10 @@ void RenderingManager::slot_rendering_resume() void RenderingManager::slot_rendering_end() { if (m_rendering_mode == InteractiveRendering) - m_render_tab->get_camera_controller()->set_enabled(false); + m_viewport_tab->get_camera_controller()->set_enabled(false); // Save the controller target point into the camera when rendering ends. - m_render_tab->get_camera_controller()->save_camera_target(); + m_viewport_tab->get_camera_controller()->save_camera_target(); print_final_rendering_time(); @@ -480,10 +480,10 @@ void RenderingManager::slot_rendering_end() void RenderingManager::slot_rendering_failed() { if (m_rendering_mode == InteractiveRendering) - m_render_tab->get_camera_controller()->set_enabled(false); + m_viewport_tab->get_camera_controller()->set_enabled(false); // Save the controller target point into the camera when rendering ends. - m_render_tab->get_camera_controller()->save_camera_target(); + m_viewport_tab->get_camera_controller()->save_camera_target(); } void RenderingManager::slot_frame_begin() @@ -491,7 +491,7 @@ void RenderingManager::slot_frame_begin() // Update the scene's camera before rendering the frame. if (m_has_camera_changed) { - m_render_tab->get_camera_controller()->update_camera_transform(); + m_viewport_tab->get_camera_controller()->update_camera_transform(); m_has_camera_changed = false; } @@ -507,7 +507,7 @@ void RenderingManager::slot_frame_end() m_status_bar.stop_rendering_time_display(); // Ensure that the render widget is up-to-date. - m_render_tab->get_viewport_widget()->update(); + m_viewport_tab->get_viewport_widget()->update(); } void RenderingManager::slot_camera_change_begin() diff --git a/src/appleseed.studio/mainwindow/rendering/renderingmanager.h b/src/appleseed.studio/mainwindow/rendering/renderingmanager.h index 42221c7b19..9dfa7038a7 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderingmanager.h +++ b/src/appleseed.studio/mainwindow/rendering/renderingmanager.h @@ -56,7 +56,7 @@ #include // Forward declarations. -namespace appleseed { namespace studio { class RenderTab; } } +namespace appleseed { namespace studio { class ViewportTab; } } namespace appleseed { namespace studio { class StatusBar; } } namespace foundation { class IAbortSwitch; } namespace renderer { class Frame; } @@ -88,7 +88,7 @@ class RenderingManager renderer::Project* project, const renderer::ParamArray& params, const RenderingMode rendering_mode, - RenderTab* render_tab); + ViewportTab* viewport_tab); // Return true if currently rendering, false otherwise. bool is_rendering() const; @@ -166,7 +166,7 @@ class RenderingManager renderer::ParamArray m_params; foundation::SearchPaths m_resource_search_paths; RenderingMode m_rendering_mode; - RenderTab* m_render_tab; + ViewportTab* m_viewport_tab; std::unique_ptr m_tile_callback_factory; diff --git a/src/appleseed.studio/mainwindow/rendering/rendertab.cpp b/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp similarity index 86% rename from src/appleseed.studio/mainwindow/rendering/rendertab.cpp rename to src/appleseed.studio/mainwindow/rendering/viewporttab.cpp index 6634f7569f..2017f441d6 100644 --- a/src/appleseed.studio/mainwindow/rendering/rendertab.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp @@ -28,7 +28,7 @@ // // Interface header. -#include "rendertab.h" +#include "viewporttab.h" // appleseed.studio headers. #include "mainwindow/project/projectexplorer.h" @@ -70,10 +70,10 @@ namespace appleseed { namespace studio { // -// RenderTab class implementation. +// ViewportTab class implementation. // -RenderTab::RenderTab( +ViewportTab::ViewportTab( ProjectExplorer& project_explorer, Project& project, RenderingManager& rendering_manager, @@ -98,43 +98,49 @@ RenderTab::RenderTab( recreate_handlers(); } -ViewportWidget* RenderTab::get_viewport_widget() const +void ViewportTab::enable_light_paths_toggle() +{} + +void ViewportTab::disable_light_paths_toggle() +{} + +ViewportWidget* ViewportTab::get_viewport_widget() const { return m_viewport_widget; } -CameraController* RenderTab::get_camera_controller() const +CameraController* ViewportTab::get_camera_controller() const { return m_camera_controller.get(); } -ScenePickingHandler* RenderTab::get_scene_picking_handler() const +ScenePickingHandler* ViewportTab::get_scene_picking_handler() const { return m_scene_picking_handler.get(); } -void RenderTab::set_clear_frame_button_enabled(const bool enabled) +void ViewportTab::set_clear_frame_button_enabled(const bool enabled) { m_clear_frame_button->setEnabled(enabled); } -void RenderTab::set_render_region_buttons_enabled(const bool enabled) +void ViewportTab::set_render_region_buttons_enabled(const bool enabled) { m_set_render_region_button->setEnabled(enabled); m_clear_render_region_button->setEnabled(enabled); } -void RenderTab::reset_zoom() +void ViewportTab::reset_zoom() { m_zoom_handler->reset_zoom(); } -void RenderTab::update() +void ViewportTab::update() { m_viewport_widget->update(); } -void RenderTab::update_size() +void ViewportTab::update_size() { m_set_render_region_button->setChecked(false); @@ -147,7 +153,7 @@ void RenderTab::update_size() recreate_handlers(); } -RenderTab::State RenderTab::save_state() const +ViewportTab::State ViewportTab::save_state() const { State state; state.m_zoom_handler_state = m_zoom_handler->save_state(); @@ -155,14 +161,19 @@ RenderTab::State RenderTab::save_state() const return state; } -void RenderTab::load_state(const State& state) +void ViewportTab::load_state(const State& state) { // The order matters here. m_zoom_handler->load_state(state.m_zoom_handler_state); m_pan_handler->load_state(state.m_pan_handler_state); } -void RenderTab::slot_toggle_render_region(const bool checked) +void ViewportTab::slot_viewport_widget_context_menu(const QPoint& point) +{ + emit signal_viewport_widget_context_menu(m_viewport_widget->mapToGlobal(point)); +} + +void ViewportTab::slot_toggle_render_region(const bool checked) { m_scene_picking_handler->set_enabled(!checked); m_render_region_handler->set_mode( @@ -171,19 +182,19 @@ void RenderTab::slot_toggle_render_region(const bool checked) : RenderRegionHandler::RectangleSelectionMode); } -void RenderTab::slot_set_render_region(const QRect& rect) +void ViewportTab::slot_set_render_region(const QRect& rect) { m_set_render_region_button->setChecked(false); emit signal_set_render_region(rect); } -void RenderTab::slot_toggle_pixel_inspector(const bool checked) +void ViewportTab::slot_toggle_pixel_inspector(const bool checked) { m_pixel_inspector_handler->set_enabled(checked); m_pixel_inspector_handler->update_tooltip_visibility(); } -void RenderTab::create_viewport_widget() +void ViewportTab::create_viewport_widget() { const CanvasProperties& props = m_project.get_frame()->image().properties(); @@ -199,25 +210,46 @@ void RenderTab::create_viewport_widget() connect( m_viewport_widget, SIGNAL(customContextMenuRequested(const QPoint&)), - SLOT(slot_render_widget_context_menu(const QPoint&))); - - connect( - this, SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), - m_viewport_widget->get_render_layer(), SLOT(slot_entity_picked(renderer::ScenePicker::PickingResult))); - connect( - this, SIGNAL(signal_rectangle_selection(const QRect&)), - m_viewport_widget->get_render_layer(), SLOT(slot_rectangle_selection(const QRect&))); + SLOT(slot_viewport_widget_context_menu(const QPoint&))); m_viewport_widget->setMouseTracking(true); } -void RenderTab::create_toolbar() +void ViewportTab::create_toolbar() { // Create the render toolbar. m_toolbar = new QToolBar(); m_toolbar->setObjectName("render_toolbar"); m_toolbar->setIconSize(QSize(18, 18)); + // Create the label preceding the scene display combo box + QLabel* scene_layer_label = new QLabel("Scene Display Mode:"); + scene_layer_label->setObjectName("display_mode_label"); + m_toolbar->addWidget(scene_layer_label); + + // Create the scene base layer combo box + m_base_layer_combo = new QComboBox(); + m_base_layer_combo->setObjectName("base_layer_combo"); + for (int i = 0; i < ViewportWidget::BaseLayer::BASE_LAYER_MAX_VALUE; i++) { + m_base_layer_combo->addItem(ViewportWidget::base_layer_string(static_cast(i))); + } + m_toolbar->addWidget(m_base_layer_combo); + connect( + m_base_layer_combo, SIGNAL(activated(int)), + m_viewport_widget, SLOT(slot_base_layer_changed(int)) + ); + + m_light_paths_toggle_button = new QToolButton(); + m_light_paths_toggle_button->setText("Display Light Paths Overlay"); + m_light_paths_toggle_button->setCheckable(true); + m_toolbar->addWidget(m_light_paths_toggle_button); + connect( + m_light_paths_toggle_button, SIGNAL(toggled(bool)), + m_viewport_widget, SLOT(slot_light_paths_toggled(bool)) + ); + + m_toolbar->addSeparator(); + // Save Frame and AOVs button. QToolButton* save_aovs_button = new QToolButton(); save_aovs_button->setIcon(load_icons("rendertab_save_all_aovs")); @@ -311,7 +343,7 @@ void RenderTab::create_toolbar() m_toolbar->addSeparator(); // Create the label preceding the display combobox. - QLabel* display_label = new QLabel("Display:"); + QLabel* display_label = new QLabel("Display Transform:"); display_label->setObjectName("display_label"); m_toolbar->addWidget(display_label); @@ -375,7 +407,7 @@ void RenderTab::create_toolbar() m_toolbar->addWidget(m_a_label); } -void RenderTab::create_scrollarea() +void ViewportTab::create_scrollarea() { // Encapsulate the render widget into another widget that adds a margin around it. QWidget* render_widget_wrapper = new QWidget(); @@ -392,7 +424,7 @@ void RenderTab::create_scrollarea() m_scroll_area->setWidget(render_widget_wrapper); } -void RenderTab::recreate_handlers() +void ViewportTab::recreate_handlers() { // Handler for zooming the render widget in and out with the keyboard or the mouse wheel. m_zoom_handler.reset( @@ -502,4 +534,4 @@ void RenderTab::recreate_handlers() } // namespace studio } // namespace appleseed -#include "mainwindow/rendering/moc_cpp_rendertab.cxx" +#include "mainwindow/rendering/moc_cpp_viewporttab.cxx" diff --git a/src/appleseed.studio/mainwindow/rendering/rendertab.h b/src/appleseed.studio/mainwindow/rendering/viewporttab.h similarity index 94% rename from src/appleseed.studio/mainwindow/rendering/rendertab.h rename to src/appleseed.studio/mainwindow/rendering/viewporttab.h index c0c0bc5a4c..6c358d1d56 100644 --- a/src/appleseed.studio/mainwindow/rendering/rendertab.h +++ b/src/appleseed.studio/mainwindow/rendering/viewporttab.h @@ -73,13 +73,13 @@ namespace studio { // A tab wrapping a render widget and its toolbar. // -class RenderTab +class ViewportTab : public QWidget { Q_OBJECT public: - RenderTab( + ViewportTab( ProjectExplorer& project_explorer, renderer::Project& project, RenderingManager& rendering_manager, @@ -89,6 +89,9 @@ class RenderTab CameraController* get_camera_controller() const; ScenePickingHandler* get_scene_picking_handler() const; + void enable_light_paths_toggle(); + void disable_light_paths_toggle(); + void set_clear_frame_button_enabled(const bool enabled); void set_render_region_buttons_enabled(const bool enabled); @@ -113,6 +116,7 @@ class RenderTab void signal_clear_render_region(); void signal_reset_zoom(); void signal_clear_frame(); + void signal_viewport_widget_context_menu(const QPoint& point); void signal_camera_change_begin(); void signal_camera_changed(); @@ -122,6 +126,7 @@ class RenderTab void signal_rectangle_selection(const QRect& rect); private slots: + void slot_viewport_widget_context_menu(const QPoint& point); void slot_toggle_render_region(const bool checked); void slot_set_render_region(const QRect& rect); void slot_toggle_pixel_inspector(const bool checked); @@ -133,8 +138,10 @@ class RenderTab QToolButton* m_set_render_region_button; QToolButton* m_clear_render_region_button; QToolButton* m_clear_frame_button; + QToolButton* m_light_paths_toggle_button; QComboBox* m_picking_mode_combo; QComboBox* m_display_transform_combo; + QComboBox* m_base_layer_combo; QLabel* m_info_label; QLabel* m_r_label; QLabel* m_g_label; diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp index 6cb3bf229a..068ec97681 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include // Standard headers. @@ -73,6 +74,8 @@ ViewportWidget::ViewportWidget( QWidget* parent) : QOpenGLWidget(parent) , m_project(project) + , m_draw_light_paths(false) + , m_active_base_layer(static_cast(0)) { setFocusPolicy(Qt::StrongFocus); setFixedWidth(static_cast(width)); @@ -81,7 +84,7 @@ ViewportWidget::ViewportWidget( setAttribute(Qt::WA_OpaquePaintEvent, true); create_render_layer(ocio_config); - //create_gl_scene_layer(); + create_gl_scene_layer(); //create_light_paths_layer(); resize(width, height); @@ -89,6 +92,17 @@ ViewportWidget::ViewportWidget( setAcceptDrops(true); } +QString ViewportWidget::base_layer_string(BaseLayer layer) +{ + switch (layer) + { + case BaseLayer::FinalRender: return QString("Final Render"); + case BaseLayer::OpenGL: return QString("OpenGL"); + } + assert(false); + return QString("BaseLayer"); +} + void ViewportWidget::create_render_layer(OCIO::ConstConfigRcPtr ocio_config) { m_render_layer = @@ -98,14 +112,14 @@ void ViewportWidget::create_render_layer(OCIO::ConstConfigRcPtr ocio_config) ocio_config)); } -//void ViewportWidget::create_gl_scene_layer() -//{ -// m_gl_scene_layer = -// std::unique_ptr(new GLSceneLayer( -// m_project, -// m_width, -// m_height)); -//} +void ViewportWidget::create_gl_scene_layer() +{ + m_gl_scene_layer = + std::unique_ptr(new GLSceneLayer( + m_project, + m_width, + m_height)); +} // //void ViewportWidget::create_light_paths_layer() //{ @@ -126,10 +140,10 @@ RenderLayer* ViewportWidget::get_render_layer() // return m_light_paths_layer.get(); //} // -//GLSceneLayer* ViewportWidget::get_gl_scene_layer() -//{ -// return m_gl_scene_layer.get(); -//} +GLSceneLayer* ViewportWidget::get_gl_scene_layer() +{ + return m_gl_scene_layer.get(); +} QImage ViewportWidget::capture() { @@ -137,6 +151,8 @@ QImage ViewportWidget::capture() } void ViewportWidget::initializeGL() { + RENDERER_LOG_INFO("initializing opengl."); + m_gl = QOpenGLContext::currentContext()->versionFunctions(); const auto qs_format = format(); @@ -145,14 +161,13 @@ void ViewportWidget::initializeGL() { const int major_version = qs_format.majorVersion(); const int minor_version = qs_format.minorVersion(); RENDERER_LOG_ERROR( - "opengl: could not load required gl functions. loaded version %d.%d, required version 3.3", + "opengl: could not load required gl functions. loaded version %d.%d, required version 3.3.", major_version, minor_version); return; } - //m_gl_scene_layer->set_gl_functions(m_gl); - //m_gl_scene_layer->init_gl(qs_format); + m_gl_scene_layer->set_gl_functions(m_gl); //m_light_paths_layer->set_gl_functions(m_gl); //m_light_paths_layer->init_gl(qs_format); } @@ -164,15 +179,28 @@ void ViewportWidget::resize( m_render_layer->resize(width, height); } -void ViewportWidget::paintEvent(QPaintEvent* event) +void ViewportWidget::paintGL() { - m_painter.begin(this); - m_render_layer->paint(rect(), m_painter); - m_painter.end(); - //m_painter.beginNativePainting(); - //m_gl_scene_layer->draw_depth_only(); - //m_light_paths_layer->draw(); - //m_painter.endNativePainting(); + if (!m_gl_scene_layer->is_initialized()) + m_gl_scene_layer->initialize(format()); + + if (m_active_base_layer == BaseLayer::FinalRender) + { + m_painter.begin(this); + m_render_layer->paint(rect(), m_painter); + m_painter.end(); + } + + m_gl->glViewport(0, 0, width(), height()); + + if (m_active_base_layer == BaseLayer::OpenGL || m_draw_light_paths) + m_gl_scene_layer->draw_depth_only(); + + if (m_active_base_layer == BaseLayer::OpenGL) + m_gl_scene_layer->draw(); + + //if (m_draw_light_paths) + // m_light_paths_layer->draw(); } void ViewportWidget::dragEnterEvent(QDragEnterEvent* event) @@ -201,9 +229,17 @@ void ViewportWidget::dropEvent(QDropEvent* event) event->mimeData()->text()); } -void ViewportWidget::slot_viewport_widget_context_menu(const QPoint& point) +void ViewportWidget::slot_base_layer_changed(int index) +{ + assert(index < BaseLayer::BASE_LAYER_MAX_VALUE); + m_active_base_layer = static_cast(index); + update(); +} + +void ViewportWidget::slot_light_paths_toggled(bool checked) { - emit signal_viewport_widget_context_menu(mapToGlobal(point)); + m_draw_light_paths = checked; + update(); } } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h index 307b23f804..8147d3ba5d 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h @@ -86,6 +86,14 @@ class ViewportWidget OCIO::ConstConfigRcPtr ocio_config, QWidget* parent = nullptr); + enum BaseLayer { + FinalRender, + OpenGL, + BASE_LAYER_MAX_VALUE + }; + + static QString base_layer_string(BaseLayer layer); + // Thread-safe. QImage capture() override; @@ -95,23 +103,17 @@ class ViewportWidget const size_t height); RenderLayer* get_render_layer(); - //GLSceneLayer* get_gl_scene_layer(); + GLSceneLayer* get_gl_scene_layer(); //LightPathsLayer* get_light_paths_layer(); - // Thread-safe. - //void highlight_tile( - // const renderer::Frame& frame, - // const size_t tile_x, - // const size_t tile_y); - signals: void signal_material_dropped( const foundation::Vector2d& drop_pos, const QString& material_name); - void signal_viewport_widget_context_menu(const QPoint& point); private slots: - void slot_viewport_widget_context_menu(const QPoint& point); + void slot_light_paths_toggled(bool checked); + void slot_base_layer_changed(int index); private: const renderer::Project& m_project; @@ -121,21 +123,23 @@ class ViewportWidget QOpenGLFunctions_3_3_Core* m_gl; QPainter m_painter; - std::unique_ptr m_render_layer; - //std::unique_ptr m_gl_scene_layer; + std::unique_ptr m_render_layer; + std::unique_ptr m_gl_scene_layer; //std::unique_ptr m_light_paths_layer; + bool m_draw_light_paths; + BaseLayer m_active_base_layer; + void create_render_layer(OCIO::ConstConfigRcPtr ocio_config); - //void create_gl_scene_layer(); + void create_gl_scene_layer(); //void create_light_paths_layer(); void initializeGL() override; - void paintEvent(QPaintEvent* event) override; + void paintGL() override; void dragEnterEvent(QDragEnterEvent* event) override; void dragMoveEvent(QDragMoveEvent* event) override; void dropEvent(QDropEvent* event) override; }; - } // namespace studio } // namespace appleseed diff --git a/src/appleseed/renderer/modeling/camera/orthographiccamera.cpp b/src/appleseed/renderer/modeling/camera/orthographiccamera.cpp index 6218fe3eb3..84de3d3ce4 100644 --- a/src/appleseed/renderer/modeling/camera/orthographiccamera.cpp +++ b/src/appleseed/renderer/modeling/camera/orthographiccamera.cpp @@ -81,6 +81,15 @@ namespace const ParamArray& params) : Camera(name, params) { + // Extract the film dimensions from the camera parameters. + m_film_dimensions = extract_film_dimensions(); + + // Extract the abscissa of the near plane from the camera parameters. + m_near_z = extract_near_z(); + + // Precompute reciprocals of film dimensions. + m_rcp_film_width = 1.0 / m_film_dimensions[0]; + m_rcp_film_height = 1.0 / m_film_dimensions[1]; } void release() override @@ -126,19 +135,9 @@ namespace if (!Camera::on_render_begin(project, parent, recorder, abort_switch)) return false; - // Extract the film dimensions from the camera parameters. - m_film_dimensions = extract_film_dimensions(); - - // Extract the abscissa of the near plane from the camera parameters. - m_near_z = extract_near_z(); - // Retrieve the scene diameter that will be used to position the camera. m_safe_scene_diameter = project.get_scene()->get_render_data().m_safe_diameter; - // Precompute reciprocals of film dimensions. - m_rcp_film_width = 1.0 / m_film_dimensions[0]; - m_rcp_film_height = 1.0 / m_film_dimensions[1]; - // Precompute pixel area. const size_t pixel_count = project.get_frame()->image().properties().m_pixel_count; m_rcp_pixel_area = static_cast(pixel_count / (m_film_dimensions[0] * m_film_dimensions[1])); @@ -291,6 +290,9 @@ namespace 0.5 + point.x * m_rcp_film_width, 0.5 - point.y * m_rcp_film_height); } + + private: + bool m_extracted_params; }; } diff --git a/src/appleseed/renderer/modeling/camera/perspectivecamera.cpp b/src/appleseed/renderer/modeling/camera/perspectivecamera.cpp index fb879cf9a3..f92e177d27 100644 --- a/src/appleseed/renderer/modeling/camera/perspectivecamera.cpp +++ b/src/appleseed/renderer/modeling/camera/perspectivecamera.cpp @@ -54,6 +54,18 @@ namespace renderer PerspectiveCamera::PerspectiveCamera(const char* name, const ParamArray& params) : Camera(name, params) { + // Extract the film dimensions from the camera parameters. + m_film_dimensions = extract_film_dimensions(); + + // Extract the focal length from the camera parameters. + m_focal_length = extract_focal_length(m_film_dimensions[0]); + // Extract the abscissa of the near plane from the camera parameters. + m_near_z = extract_near_z(); + // Extract the shift from the camera parameters. + m_shift = extract_shift(); + // Precompute reciprocals of film dimensions. + m_rcp_film_width = 1.0 / m_film_dimensions[0]; + m_rcp_film_height = 1.0 / m_film_dimensions[1]; } const foundation::Vector2d& PerspectiveCamera::get_film_dimensions() const @@ -80,22 +92,6 @@ bool PerspectiveCamera::on_render_begin( if (!Camera::on_render_begin(project, parent, recorder, abort_switch)) return false; - // Extract the film dimensions from the camera parameters. - m_film_dimensions = extract_film_dimensions(); - - // Extract the focal length from the camera parameters. - m_focal_length = extract_focal_length(m_film_dimensions[0]); - - // Extract the abscissa of the near plane from the camera parameters. - m_near_z = extract_near_z(); - - // Extract the shift from the camera parameters. - m_shift = extract_shift(); - - // Precompute reciprocals of film dimensions. - m_rcp_film_width = 1.0 / m_film_dimensions[0]; - m_rcp_film_height = 1.0 / m_film_dimensions[1]; - // Precompute pixel area. const size_t pixel_count = project.get_frame()->image().properties().m_pixel_count; m_pixel_area = m_film_dimensions[0] * m_film_dimensions[1] / pixel_count; From bf27aaf396b813434e1e612bdf7f8ec3f9199760 Mon Sep 17 00:00:00 2001 From: Gray Olson Date: Sun, 23 Jun 2019 03:27:29 -0700 Subject: [PATCH 3/6] Display optional light paths overlay over final render or opengl view --- src/appleseed.studio/CMakeLists.txt | 16 +- .../mainwindow/mainwindow.cpp | 14 +- .../mainwindow/rendering/glscenelayer.cpp | 7 +- .../mainwindow/rendering/glscenelayer.h | 8 +- .../mainwindow/rendering/lightpathslayer.cpp | 48 ++++-- .../mainwindow/rendering/lightpathslayer.h | 14 +- .../rendering/lightpathspickinghandler.cpp | 45 ++---- .../rendering/lightpathspickinghandler.h | 10 +- .../rendering/lightpathsviewportmanager.cpp | 149 +++++++----------- .../rendering/lightpathsviewportmanager.h | 20 +-- .../mainwindow/rendering/renderingmanager.cpp | 5 + .../mainwindow/rendering/renderingmanager.h | 3 + ...cpp => viewportregionselectionhandler.cpp} | 12 +- ...ler.h => viewportregionselectionhandler.h} | 6 +- .../mainwindow/rendering/viewporttab.cpp | 102 ++++++++++-- .../mainwindow/rendering/viewporttab.h | 91 ++++++----- .../mainwindow/rendering/viewportwidget.cpp | 56 ++++--- .../mainwindow/rendering/viewportwidget.h | 13 +- 18 files changed, 338 insertions(+), 281 deletions(-) rename src/appleseed.studio/mainwindow/rendering/{renderregionhandler.cpp => viewportregionselectionhandler.cpp} (91%) rename src/appleseed.studio/mainwindow/rendering/{renderregionhandler.h => viewportregionselectionhandler.h} (95%) diff --git a/src/appleseed.studio/CMakeLists.txt b/src/appleseed.studio/CMakeLists.txt index 11cebbd8d7..6073da93eb 100644 --- a/src/appleseed.studio/CMakeLists.txt +++ b/src/appleseed.studio/CMakeLists.txt @@ -250,12 +250,12 @@ set (mainwindow_rendering_sources mainwindow/rendering/cameracontroller.h mainwindow/rendering/glscenelayer.h mainwindow/rendering/glscenelayer.cpp - # mainwindow/rendering/lightpathspickinghandler.cpp - # mainwindow/rendering/lightpathspickinghandler.h - # mainwindow/rendering/lightpathsviewportmanager.cpp - # mainwindow/rendering/lightpathsviewportmanager.h - # mainwindow/rendering/lightpathslayer.cpp - # mainwindow/rendering/lightpathslayer.h + mainwindow/rendering/lightpathspickinghandler.cpp + mainwindow/rendering/lightpathspickinghandler.h + mainwindow/rendering/lightpathsviewportmanager.cpp + mainwindow/rendering/lightpathsviewportmanager.h + mainwindow/rendering/lightpathslayer.cpp + mainwindow/rendering/lightpathslayer.h mainwindow/rendering/materialdrophandler.cpp mainwindow/rendering/materialdrophandler.h mainwindow/rendering/pixelcolortracker.cpp @@ -271,12 +271,12 @@ set (mainwindow_rendering_sources mainwindow/rendering/renderingmanager.cpp mainwindow/rendering/renderingmanager.h mainwindow/rendering/renderingtimer.h - mainwindow/rendering/renderregionhandler.cpp - mainwindow/rendering/renderregionhandler.h mainwindow/rendering/renderlayer.cpp mainwindow/rendering/renderlayer.h mainwindow/rendering/scenepickinghandler.cpp mainwindow/rendering/scenepickinghandler.h + mainwindow/rendering/viewportregionselectionhandler.cpp + mainwindow/rendering/viewportregionselectionhandler.h mainwindow/rendering/viewporttab.cpp mainwindow/rendering/viewporttab.h mainwindow/rendering/viewportwidget.h diff --git a/src/appleseed.studio/mainwindow/mainwindow.cpp b/src/appleseed.studio/mainwindow/mainwindow.cpp index c3363e702d..d6980c6c5f 100644 --- a/src/appleseed.studio/mainwindow/mainwindow.cpp +++ b/src/appleseed.studio/mainwindow/mainwindow.cpp @@ -742,17 +742,17 @@ void MainWindow::update_workspace() update_pause_resume_checkbox(false); m_ui->attribute_editor_scrollarea_contents->setEnabled(true); - // Add/remove light paths tab. + // Enable/disable light paths if (m_project_manager.is_project_open() && m_project_manager.get_project()->get_light_path_recorder().get_light_path_count() > 0) { for (const_each i = m_viewport_tabs; i; ++i) - i->second->enable_light_paths_toggle(); + i->second->set_light_paths_enabled(true); } else { for (const_each i = m_viewport_tabs; i; ++i) - i->second->disable_light_paths_toggle(); + i->second->set_light_paths_enabled(false); } } @@ -894,7 +894,7 @@ void MainWindow::set_rendering_widgets_enabled(const bool is_enabled, const Rend // Rendering -> Render Settings. m_ui->action_rendering_rendering_settings->setEnabled(allow_start); - // Render tab buttons. + // Viewport tab buttons. const int current_tab_index = m_ui->tab_render_channels->currentIndex(); if (current_tab_index != -1) { @@ -982,7 +982,8 @@ void MainWindow::add_viewport_tab(const QString& label) *m_project_explorer, *m_project_manager.get_project(), m_rendering_manager, - m_ocio_config); + m_ocio_config, + m_application_settings); // Connect the render tab to the main window and the rendering manager. connect( @@ -1218,8 +1219,7 @@ void MainWindow::start_rendering(const RenderingMode rendering_mode) // Darken render widgets. for (const_each i = m_viewport_tabs; i; ++i) { - i->second->get_viewport_widget()->get_render_layer()->darken(); - i->second->update(); + i->second->render_began(); } // Retrieve the appropriate rendering configuration. diff --git a/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp b/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp index c1d3f89d3b..58ab4e115b 100644 --- a/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp +++ b/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp @@ -458,7 +458,7 @@ namespace { } } -void GLSceneLayer::initialize(QSurfaceFormat format) +void GLSceneLayer::init_gl(QSurfaceFormat format) { // If there was already previous data, clean up GLSceneLayer::cleanup_gl_data(); @@ -511,11 +511,6 @@ void GLSceneLayer::initialize(QSurfaceFormat format) m_initialized = true; } -bool GLSceneLayer::is_initialized() -{ - return m_initialized; -} - void GLSceneLayer::cleanup_gl_data() { if (!m_scene_object_vaos.empty()) diff --git a/src/appleseed.studio/mainwindow/rendering/glscenelayer.h b/src/appleseed.studio/mainwindow/rendering/glscenelayer.h index c3cdbcf2a7..6345a7a067 100644 --- a/src/appleseed.studio/mainwindow/rendering/glscenelayer.h +++ b/src/appleseed.studio/mainwindow/rendering/glscenelayer.h @@ -79,17 +79,15 @@ class GLSceneLayer const size_t width, const size_t height); + void init_gl( + QSurfaceFormat format); + void set_transform( const foundation::Transformd& transform); void set_gl_functions( QOpenGLFunctions_3_3_Core* functions); - void initialize( - QSurfaceFormat format); - - bool is_initialized(); - void draw(); void draw_depth_only(); diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp index e6fe60571a..afafce1605 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp @@ -142,11 +142,17 @@ void LightPathsLayer::set_gl_functions(QOpenGLFunctions_3_3_Core* functions) m_gl = functions; } +void LightPathsLayer::update_render_camera_transform() +{ + const float time = m_camera.get_shutter_middle_time(); + m_render_camera_matrix = m_camera.transform_sequence().evaluate(time).get_parent_to_local(); + m_gl_render_view_matrix = transpose(m_render_camera_matrix); +} + void LightPathsLayer::set_transform(const Transformd& transform) { m_camera_matrix = transform.get_parent_to_local(); m_gl_view_matrix = transpose(m_camera_matrix); - m_camera_position = Vector3f(m_camera_matrix.extract_translation()); } void LightPathsLayer::set_light_paths(const LightPathArray& light_paths) @@ -365,23 +371,18 @@ void LightPathsLayer::init_gl(QSurfaceFormat format) // If there was already previous data, clean up LightPathsLayer::cleanup_gl_data(); - bool manual_srgb_conversion = false; - if (format.colorSpace() != QSurfaceFormat::sRGBColorSpace) - { - manual_srgb_conversion = true; - RENDERER_LOG_WARNING( - "opengl: srgb framebuffer extensions not supported, using slower manual conversion."); - } - glEnable(GL_DEPTH_TEST); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + auto vertex_shader = load_gl_shader("lightpaths.vert"); + auto fragment_shader = load_gl_shader("lightpaths.frag"); + create_shader_program( m_gl, m_light_paths_shader_program, - load_gl_shader("lightpaths.vert"), - load_gl_shader("lightpaths.frag")); + vertex_shader, + fragment_shader); m_light_paths_view_mat_location = m_gl->glGetUniformLocation(m_light_paths_shader_program, "u_view"); m_light_paths_proj_mat_location = m_gl->glGetUniformLocation(m_light_paths_shader_program, "u_proj"); @@ -447,23 +448,40 @@ void LightPathsLayer::cleanup_gl_data() } } -void LightPathsLayer::draw() +void LightPathsLayer::draw_render_camera() const +{ + auto gl_view_matrix = const_cast(&m_gl_render_view_matrix[0]); + render_scene(gl_view_matrix); +} + +void LightPathsLayer::draw() const +{ + auto gl_view_matrix = const_cast(&m_gl_view_matrix[0]); + render_scene(gl_view_matrix); +} + +void LightPathsLayer::render_scene(const GLfloat* gl_view_matrix) const { if (!m_gl_initialized) return; if (m_backface_culling_enabled) - glEnable(GL_CULL_FACE); - else glDisable(GL_CULL_FACE); + m_gl->glEnable(GL_CULL_FACE); + else m_gl->glDisable(GL_CULL_FACE); + + m_gl->glDepthMask(GL_TRUE); + m_gl->glEnable(GL_DEPTH_TEST); + m_gl->glDepthFunc(GL_LEQUAL); if (m_light_paths_index_offsets.size() > 1) { m_gl->glUseProgram(m_light_paths_shader_program); + m_gl->glUniformMatrix4fv( m_light_paths_view_mat_location, 1, false, - const_cast(&m_gl_view_matrix[0])); + gl_view_matrix); m_gl->glUniformMatrix4fv( m_light_paths_proj_mat_location, 1, diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h index 9c611dbe53..62ce3e00ce 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h @@ -67,7 +67,7 @@ namespace studio { // A widget providing an hardware-accelerated visualization of recorded light paths. // -class LightPathsLayer +class LightPathsLayer: public QObject { Q_OBJECT @@ -77,6 +77,9 @@ class LightPathsLayer const size_t width, const size_t height); + + void update_render_camera_transform(); + void set_transform( const foundation::Transformd& transform); @@ -91,7 +94,9 @@ class LightPathsLayer void init_gl(QSurfaceFormat format); - void draw(); + void draw() const; + + void draw_render_camera() const; signals: void signal_light_path_selection_changed( @@ -109,7 +114,7 @@ class LightPathsLayer const renderer::Project& m_project; renderer::Camera& m_camera; foundation::Matrix4d m_camera_matrix; - foundation::Vector3f m_camera_position; + foundation::Matrix4d m_render_camera_matrix; bool m_backface_culling_enabled; @@ -124,6 +129,7 @@ class LightPathsLayer GLuint m_light_paths_shader_program; GLint m_light_paths_view_mat_location; GLint m_light_paths_proj_mat_location; + foundation::Matrix4f m_gl_render_view_matrix; foundation::Matrix4f m_gl_view_matrix; foundation::Matrix4f m_gl_proj_matrix; bool m_gl_initialized; @@ -131,6 +137,8 @@ class LightPathsLayer void cleanup_gl_data(); void load_light_paths_data(); + void render_scene(const GLfloat* gl_view_matrix) const; + void dump_selected_light_path() const; }; diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp index 4e9715a312..3f8e1cf8bd 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp @@ -30,7 +30,8 @@ #include "lightpathspickinghandler.h" // appleseed.studio headers. -#include "mainwindow/rendering/lightpathswidget.h" +#include "mainwindow/rendering/lightpathslayer.h" +#include "mainwindow/rendering/viewportwidget.h" #include "utility/mousecoordinatestracker.h" // appleseed.renderer headers. @@ -57,20 +58,13 @@ namespace appleseed { namespace studio { LightPathsPickingHandler::LightPathsPickingHandler( - LightPathsLayer* light_paths_widget, + ViewportWidget* viewport_widget, const MouseCoordinatesTracker& mouse_tracker, const Project& project) - : m_light_paths_widget(light_paths_widget) - , m_mouse_tracker(mouse_tracker) - , m_project(project) + : m_project(project) , m_enabled(true) + , m_viewport_widget(viewport_widget) { - m_light_paths_widget->installEventFilter(this); -} - -LightPathsPickingHandler::~LightPathsPickingHandler() -{ - m_light_paths_widget->removeEventFilter(this); } void LightPathsPickingHandler::set_enabled(const bool enabled) @@ -108,8 +102,8 @@ void LightPathsPickingHandler::pick(const Vector2i& pixel) const pixel.y); } - m_light_paths_widget->set_light_paths(light_paths); - m_light_paths_widget->update(); + m_viewport_widget->get_light_paths_layer()->set_light_paths(light_paths); + m_viewport_widget->update(); } } @@ -156,31 +150,10 @@ void LightPathsPickingHandler::pick(const AABB2i& rect) const final_rect.max.y); } - m_light_paths_widget->set_light_paths(light_paths); - m_light_paths_widget->update(); + m_viewport_widget->get_light_paths_layer()->set_light_paths(light_paths); + m_viewport_widget->update(); } } -bool LightPathsPickingHandler::eventFilter(QObject* object, QEvent* event) -{ - if (m_enabled) - { - if (event->type() == QEvent::MouseButtonPress) - { - const QMouseEvent* mouse_event = static_cast(event); - if (!(mouse_event->modifiers() & (Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier))) - { - if (mouse_event->button() == Qt::LeftButton) - { - pick(m_mouse_tracker.widget_to_pixel(mouse_event->pos())); - return true; - } - } - } - } - - return QObject::eventFilter(object, event); -} - } // namespace studio } // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h index 215780c8a9..736c7eac29 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h @@ -38,6 +38,7 @@ // Forward declarations. namespace appleseed { namespace studio { class LightPathsLayer; } } namespace appleseed { namespace studio { class MouseCoordinatesTracker; } } +namespace appleseed { namespace studio { class ViewportWidget; } } namespace renderer { class Project; } class QEvent; @@ -51,24 +52,19 @@ class LightPathsPickingHandler public: LightPathsPickingHandler( - LightPathsLayer* light_paths_widget, + ViewportWidget* viewport_widget, const MouseCoordinatesTracker& mouse_tracker, const renderer::Project& project); - ~LightPathsPickingHandler() override; - void set_enabled(const bool enabled); void pick(const foundation::Vector2i& pixel) const; void pick(const foundation::AABB2i& rect) const; private: - LightPathsLayer* m_light_paths_widget; - const MouseCoordinatesTracker& m_mouse_tracker; + ViewportWidget* m_viewport_widget; const renderer::Project& m_project; bool m_enabled; - - bool eventFilter(QObject* object, QEvent* event) override; }; } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp index 9fbf91a653..ab67077b70 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp @@ -32,6 +32,8 @@ // appleseed.studio headers. #include "mainwindow/rendering/lightpathspickinghandler.h" #include "mainwindow/rendering/lightpathslayer.h" +#include "mainwindow/rendering/viewporttab.h" +#include "mainwindow/rendering/viewportwidget.h" #include "utility/miscellaneous.h" #include "utility/settingskeys.h" @@ -73,18 +75,45 @@ namespace studio { // LightPathsViewportManager class implementation. // -LightPathsViewportManager::LightPathsViewportManager(Project& project, ParamArray& settings) - : m_project(project) +LightPathsViewportManager::LightPathsViewportManager( + ViewportTab* viewport_tab, + Project& project, + ParamArray& settings) + : m_enabled(false) + , m_project(project) , m_settings(settings) + , m_viewport_tab(viewport_tab) { - create_light_paths_widget(); + LightPathsLayer* light_paths_layer = m_viewport_tab->get_viewport_widget()->get_light_paths_layer(); + connect( + light_paths_layer, SIGNAL(signal_light_path_selection_changed(const int, const int)), + SLOT(slot_light_path_selection_changed)); + create_toolbar(); recreate_handlers(); } +void LightPathsViewportManager::set_enabled(const bool enabled) +{ + m_enabled = enabled; + if (enabled) + m_toolbar->show(); + else + m_toolbar->hide(); + m_toolbar->setDisabled(!enabled); + m_screen_space_paths_picking_handler->set_enabled(enabled); +} + +QToolBar* LightPathsViewportManager::toolbar() const +{ + return m_toolbar; +} + void LightPathsViewportManager::slot_entity_picked(const ScenePicker::PickingResult& result) { + if (!m_enabled) return; + const CanvasProperties& props = m_project.get_frame()->image().properties(); m_screen_space_paths_picking_handler->pick( @@ -93,8 +122,15 @@ void LightPathsViewportManager::slot_entity_picked(const ScenePicker::PickingRes result.m_ndc[1] * static_cast(props.m_canvas_height))); } +void LightPathsViewportManager::slot_light_paths_display_toggled(const bool active) +{ + set_enabled(active); +} + void LightPathsViewportManager::slot_rectangle_selection(const QRect& rect) { + if (!m_enabled) return; + m_screen_space_paths_picking_handler->pick( AABB2i( Vector2i(rect.x(), rect.y()), @@ -117,21 +153,11 @@ void LightPathsViewportManager::slot_light_path_selection_changed( } } -void LightPathsViewportManager::slot_context_menu(const QPoint& point) -{ - if (!(QApplication::keyboardModifiers() & Qt::ShiftModifier)) - return; - - QMenu* menu = new QMenu(this); - - menu->exec(m_light_paths_layer->mapToGlobal(point)); -} - void LightPathsViewportManager::slot_save_light_paths() { QString filepath = get_save_filename( - this, + m_viewport_tab, "Save Light Paths As...", "Light Paths Files (*.aspaths);;All Files (*.*)", m_settings, @@ -151,37 +177,26 @@ void LightPathsViewportManager::slot_save_light_paths() void LightPathsViewportManager::slot_camera_changed() { - m_light_paths_layer->set_transform(m_camera_controller->get_transform()); - m_light_paths_layer->update(); -} - -void LightPathsViewportManager::create_light_paths_widget() -{ - // Create the OpenGL widget. - const CanvasProperties& props = m_project.get_frame()->image().properties(); - m_light_paths_widget = - new LightPathsLayer( - m_project, - props.m_canvas_width, - props.m_canvas_height); - - // Enable context menu on the OpenGL widget. - m_light_paths_widget->setContextMenuPolicy(Qt::CustomContextMenu); - connect( - m_light_paths_widget, SIGNAL(signal_light_path_selection_changed(const int, const int)), - SLOT(slot_light_path_selection_changed(const int, const int))); - connect( - m_light_paths_widget, SIGNAL(customContextMenuRequested(const QPoint&)), - SLOT(slot_context_menu(const QPoint&))); + if (!m_enabled) return; } void LightPathsViewportManager::create_toolbar() { + LightPathsLayer* light_paths_layer = m_viewport_tab->get_viewport_widget()->get_light_paths_layer(); + // Create the render toolbar. m_toolbar = new QToolBar(); m_toolbar->setObjectName("render_toolbar"); m_toolbar->setIconSize(QSize(18, 18)); + //// Pick paths button + //QToolButton* m_pick_paths_button = new QToolButton(); + //m_pick_paths_button->setText("Pick Light Paths"); + //m_pick_paths_button->setToolTip("Pick Light Paths"); + //connect( + // m_pick_paths_button, SIGNAL(clicked()), + // SIGNAL(slot_light_paths_pick_button_clicked)); + // Save Light Paths button. QToolButton* save_light_paths_button = new QToolButton(); save_light_paths_button->setIcon(load_icons("lightpathstab_save_light_paths")); @@ -204,7 +219,7 @@ void LightPathsViewportManager::create_toolbar() m_prev_path_button->setEnabled(false); connect( m_prev_path_button, SIGNAL(clicked()), - m_light_paths_widget, SLOT(slot_display_previous_light_path())); + light_paths_layer, SLOT(slot_display_previous_light_path())); m_toolbar->addWidget(m_prev_path_button); // Next Light Path button. @@ -214,7 +229,7 @@ void LightPathsViewportManager::create_toolbar() m_next_path_button->setEnabled(false); connect( m_next_path_button, SIGNAL(clicked()), - m_light_paths_widget, SLOT(slot_display_next_light_path())); + light_paths_layer, SLOT(slot_display_next_light_path())); m_toolbar->addWidget(m_next_path_button); m_toolbar->addSeparator(); @@ -226,8 +241,8 @@ void LightPathsViewportManager::create_toolbar() backface_culling_button->setCheckable(true); backface_culling_button->setChecked(false); connect( - backface_culling_button, SIGNAL(toggled(bool)), - m_light_paths_widget, SLOT(slot_toggle_backface_culling(const bool))); + backface_culling_button, SIGNAL(toggled()), + light_paths_layer, SLOT(slot_toggle_backface_culling())); m_toolbar->addWidget(backface_culling_button); // Synchronize Camera button. @@ -236,7 +251,7 @@ void LightPathsViewportManager::create_toolbar() sync_camera_button->setToolTip("Synchronize the rendering camera with this camera"); connect( sync_camera_button, SIGNAL(clicked()), - m_light_paths_widget, SLOT(slot_synchronize_camera())); + light_paths_layer, SLOT(slot_synchronize_camera())); m_toolbar->addWidget(sync_camera_button); // Add stretchy spacer. @@ -249,48 +264,17 @@ void LightPathsViewportManager::create_toolbar() m_info_label = new QLabel(); m_info_label->setObjectName("info_label"); m_toolbar->addWidget(m_info_label); -} -void LightPathsViewportManager::create_scrollarea() -{ - // Encapsulate the OpenGL widget into another widget that adds a margin around it. - QWidget* gl_widget_wrapper = new QWidget(); - gl_widget_wrapper->setObjectName("render_widget_wrapper"); - gl_widget_wrapper->setLayout(new QGridLayout()); - gl_widget_wrapper->layout()->setSizeConstraint(QLayout::SetFixedSize); - gl_widget_wrapper->layout()->setContentsMargins(20, 20, 20, 20); - gl_widget_wrapper->layout()->addWidget(m_light_paths_widget); - - // Wrap the OpenGL widget in a scroll area. - m_scroll_area = new QScrollArea(); - m_scroll_area->setObjectName(QString::fromUtf8("render_widget_scrollarea")); - m_scroll_area->setAlignment(Qt::AlignCenter); - m_scroll_area->setWidget(gl_widget_wrapper); + m_toolbar->setDisabled(true); + m_toolbar->hide(); } void LightPathsViewportManager::recreate_handlers() { - // Handler for zooming the render widget in and out with the keyboard or the mouse wheel. - m_zoom_handler.reset( - new WidgetZoomHandler( - m_scroll_area, - m_light_paths_widget)); - - // Handler for panning the render widget with the mouse. - m_pan_handler.reset( - new ScrollAreaPanHandler( - m_scroll_area)); - - // Handler for tracking and displaying mouse coordinates. - m_mouse_tracker.reset( - new MouseCoordinatesTracker( - m_light_paths_widget, - m_info_label)); - // The screen-space paths picking handler is used to pick paths from the render widget. m_screen_space_paths_picking_handler.reset( new LightPathsPickingHandler( - m_light_paths_widget, + m_viewport_tab->get_viewport_widget(), *m_mouse_tracker.get(), m_project)); m_screen_space_paths_picking_handler->set_enabled(false); @@ -304,21 +288,10 @@ void LightPathsViewportManager::recreate_handlers() // m_project)); // Camera handler. - m_light_paths_widget->setMouseTracking(true); - m_camera_controller.reset( - new CameraController( - m_light_paths_widget, - m_project, - m_project.get_uncached_active_camera())); - connect( - m_camera_controller.get(), SIGNAL(signal_camera_changed()), - SLOT(slot_camera_changed())); - - // Clipboard handler. - m_clipboard_handler.reset(new RenderClipboardHandler(m_light_paths_widget, m_light_paths_widget)); + m_viewport_tab->get_viewport_widget()->setMouseTracking(true); } } // namespace studio } // namespace appleseed -#include "mainwindow/rendering/moc_cpp_lightpathstab.cxx" +//#include "mainwindow/rendering/moc_cpp_lightpathsviewportmanager.cxx" diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h index d3f1452529..692b989760 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h @@ -47,7 +47,7 @@ #include // Forward declarations. -namespace appleseed { namespace studio { class LightPathsLayer; } } +namespace appleseed { namespace studio { class ViewportTab; } } namespace renderer { class ParamArray; } namespace renderer { class Project; } class QLabel; @@ -71,42 +71,44 @@ class LightPathsViewportManager public: LightPathsViewportManager( + ViewportTab* viewport_tab, renderer::Project& project, renderer::ParamArray& settings); + QToolBar* toolbar() const; + + void set_enabled(const bool enabled); + public slots: void slot_entity_picked(const renderer::ScenePicker::PickingResult& result); void slot_rectangle_selection(const QRect& rect); + void slot_light_paths_display_toggled(const bool active); private slots: void slot_light_path_selection_changed( const int selected_light_path_index, const int total_light_paths) const; - void slot_context_menu(const QPoint& point); void slot_save_light_paths(); void slot_camera_changed(); private: + bool m_enabled; + renderer::Project& m_project; renderer::ParamArray& m_settings; - LightPathsLayer* m_light_paths_layer; - QScrollArea* m_scroll_area; + ViewportTab* m_viewport_tab; QToolBar* m_toolbar; + //QToolButton* m_pick_paths_button; QToolButton* m_prev_path_button; QToolButton* m_next_path_button; QLabel* m_info_label; - std::unique_ptr m_zoom_handler; std::unique_ptr m_pan_handler; std::unique_ptr m_mouse_tracker; - std::unique_ptr m_camera_controller; std::unique_ptr m_screen_space_paths_picking_handler; std::unique_ptr m_world_space_paths_picking_handler; - std::unique_ptr m_clipboard_handler; - void create_light_paths_widget(); void create_toolbar(); - void create_scrollarea(); void recreate_handlers(); }; diff --git a/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp b/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp index a92e7e2b34..97c0b40165 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp +++ b/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp @@ -192,6 +192,11 @@ RenderingManager::~RenderingManager() clear_sticky_actions(); } +RenderingManager::RenderingMode RenderingManager::get_rendering_mode() const +{ + return m_rendering_mode; +} + void RenderingManager::start_rendering( Project* project, const ParamArray& params, diff --git a/src/appleseed.studio/mainwindow/rendering/renderingmanager.h b/src/appleseed.studio/mainwindow/rendering/renderingmanager.h index 9dfa7038a7..13032d7c7c 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderingmanager.h +++ b/src/appleseed.studio/mainwindow/rendering/renderingmanager.h @@ -90,6 +90,9 @@ class RenderingManager const RenderingMode rendering_mode, ViewportTab* viewport_tab); + // Get current rendering mode + RenderingMode get_rendering_mode() const; + // Return true if currently rendering, false otherwise. bool is_rendering() const; diff --git a/src/appleseed.studio/mainwindow/rendering/renderregionhandler.cpp b/src/appleseed.studio/mainwindow/rendering/viewportregionselectionhandler.cpp similarity index 91% rename from src/appleseed.studio/mainwindow/rendering/renderregionhandler.cpp rename to src/appleseed.studio/mainwindow/rendering/viewportregionselectionhandler.cpp index f014235fbc..6750d8eeee 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderregionhandler.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewportregionselectionhandler.cpp @@ -28,7 +28,7 @@ // // Interface header. -#include "renderregionhandler.h" +#include "viewportregionselectionhandler.h" // appleseed.studio headers. #include "utility/mousecoordinatestracker.h" @@ -54,7 +54,7 @@ using namespace std; namespace appleseed { namespace studio { -RenderRegionHandler::RenderRegionHandler( +ViewportRegionSelectionHandler::ViewportRegionSelectionHandler( QWidget* widget, const MouseCoordinatesTracker& mouse_tracker) : m_widget(widget) @@ -66,22 +66,22 @@ RenderRegionHandler::RenderRegionHandler( m_widget->installEventFilter(this); } -RenderRegionHandler::~RenderRegionHandler() +ViewportRegionSelectionHandler::~ViewportRegionSelectionHandler() { m_widget->removeEventFilter(this); } -void RenderRegionHandler::set_enabled(const bool enabled) +void ViewportRegionSelectionHandler::set_enabled(const bool enabled) { m_enabled = enabled; } -void RenderRegionHandler::set_mode(const Mode mode) +void ViewportRegionSelectionHandler::set_mode(const Mode mode) { m_mode = mode; } -bool RenderRegionHandler::eventFilter(QObject* object, QEvent* event) +bool ViewportRegionSelectionHandler::eventFilter(QObject* object, QEvent* event) { if (m_enabled) { diff --git a/src/appleseed.studio/mainwindow/rendering/renderregionhandler.h b/src/appleseed.studio/mainwindow/rendering/viewportregionselectionhandler.h similarity index 95% rename from src/appleseed.studio/mainwindow/rendering/renderregionhandler.h rename to src/appleseed.studio/mainwindow/rendering/viewportregionselectionhandler.h index 2ad7f77a1e..574a7517a9 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderregionhandler.h +++ b/src/appleseed.studio/mainwindow/rendering/viewportregionselectionhandler.h @@ -43,18 +43,18 @@ class QWidget; namespace appleseed { namespace studio { -class RenderRegionHandler +class ViewportRegionSelectionHandler : public QObject { Q_OBJECT public: // Default mode is RectangleSelectionMode. - RenderRegionHandler( + ViewportRegionSelectionHandler( QWidget* widget, const MouseCoordinatesTracker& mouse_tracker); - ~RenderRegionHandler() override; + ~ViewportRegionSelectionHandler() override; void set_enabled(const bool enabled); diff --git a/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp b/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp index 2017f441d6..37ff7f796c 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp @@ -32,6 +32,8 @@ // appleseed.studio headers. #include "mainwindow/project/projectexplorer.h" +#include "mainwindow/rendering/lightpathsviewportmanager.h" +#include "mainwindow/rendering/renderingmanager.h" #include "mainwindow/rendering/viewportwidget.h" #include "utility/miscellaneous.h" @@ -77,8 +79,10 @@ ViewportTab::ViewportTab( ProjectExplorer& project_explorer, Project& project, RenderingManager& rendering_manager, - OCIO::ConstConfigRcPtr ocio_config) - : m_project_explorer(project_explorer) + OCIO::ConstConfigRcPtr ocio_config, + renderer::ParamArray application_settings) + : m_application_settings(application_settings) + , m_project_explorer(project_explorer) , m_project(project) , m_rendering_manager(rendering_manager) , m_ocio_config(ocio_config) @@ -89,21 +93,17 @@ ViewportTab::ViewportTab( layout()->setMargin(0); create_viewport_widget(); + create_light_paths_manager(m_application_settings); create_toolbar(); create_scrollarea(); layout()->addWidget(m_toolbar); + layout()->addWidget(m_light_paths_manager->toolbar()); layout()->addWidget(m_scroll_area); recreate_handlers(); } -void ViewportTab::enable_light_paths_toggle() -{} - -void ViewportTab::disable_light_paths_toggle() -{} - ViewportWidget* ViewportTab::get_viewport_widget() const { return m_viewport_widget; @@ -130,6 +130,14 @@ void ViewportTab::set_render_region_buttons_enabled(const bool enabled) m_clear_render_region_button->setEnabled(enabled); } +void ViewportTab::render_began() +{ + get_viewport_widget()->get_render_layer()->darken(); + get_viewport_widget()->get_light_paths_layer()->update_render_camera_transform(); + set_light_paths_enabled(false); + update(); +} + void ViewportTab::reset_zoom() { m_zoom_handler->reset_zoom(); @@ -168,18 +176,48 @@ void ViewportTab::load_state(const State& state) m_pan_handler->load_state(state.m_pan_handler_state); } -void ViewportTab::slot_viewport_widget_context_menu(const QPoint& point) +void ViewportTab::set_light_paths_enabled(const bool enabled) { - emit signal_viewport_widget_context_menu(m_viewport_widget->mapToGlobal(point)); + m_light_paths_toggle_button->setDisabled(!enabled); + m_light_paths_manager->set_enabled(enabled); +} + +void ViewportTab::slot_base_layer_changed(int index) +{ + assert(index < ViewportWidget::BaseLayer::BASE_LAYER_MAX_VALUE); + auto base_layer = static_cast(index); + + switch (base_layer) + { + case ViewportWidget::BaseLayer::FinalRender: + if (m_rendering_manager.is_rendering() + && m_rendering_manager.get_rendering_mode() == RenderingManager::RenderingMode::InteractiveRendering) + m_camera_controller.get()->set_enabled(true); + else + m_camera_controller.get()->set_enabled(false); + break; + + case ViewportWidget::BaseLayer::OpenGL: + m_camera_controller.get()->set_enabled(true); + break; + } +} + +void ViewportTab::slot_camera_changed() +{ + + m_viewport_widget->get_light_paths_layer()->set_transform(get_camera_controller()->get_transform()); + m_viewport_widget->get_gl_scene_layer()->set_transform(get_camera_controller()->get_transform()); + update(); } void ViewportTab::slot_toggle_render_region(const bool checked) { m_scene_picking_handler->set_enabled(!checked); - m_render_region_handler->set_mode( + m_viewport_selection_handler->set_mode( checked - ? RenderRegionHandler::RenderRegionMode - : RenderRegionHandler::RectangleSelectionMode); + ? ViewportRegionSelectionHandler::RenderRegionMode + : ViewportRegionSelectionHandler::RectangleSelectionMode); } void ViewportTab::slot_set_render_region(const QRect& rect) @@ -194,6 +232,11 @@ void ViewportTab::slot_toggle_pixel_inspector(const bool checked) m_pixel_inspector_handler->update_tooltip_visibility(); } +void ViewportTab::slot_viewport_widget_context_menu(const QPoint& point) +{ + emit signal_viewport_widget_context_menu(m_viewport_widget->mapToGlobal(point)); +} + void ViewportTab::create_viewport_widget() { const CanvasProperties& props = m_project.get_frame()->image().properties(); @@ -215,6 +258,14 @@ void ViewportTab::create_viewport_widget() m_viewport_widget->setMouseTracking(true); } +void ViewportTab::create_light_paths_manager(renderer::ParamArray application_settings) +{ + m_light_paths_manager = new LightPathsViewportManager( + this, + m_project, + application_settings); +} + void ViewportTab::create_toolbar() { // Create the render toolbar. @@ -238,6 +289,10 @@ void ViewportTab::create_toolbar() m_base_layer_combo, SIGNAL(activated(int)), m_viewport_widget, SLOT(slot_base_layer_changed(int)) ); + connect( + m_base_layer_combo, SIGNAL(activated(int)), + SLOT(slot_base_layer_changed(int)) + ); m_light_paths_toggle_button = new QToolButton(); m_light_paths_toggle_button->setText("Display Light Paths Overlay"); @@ -247,6 +302,10 @@ void ViewportTab::create_toolbar() m_light_paths_toggle_button, SIGNAL(toggled(bool)), m_viewport_widget, SLOT(slot_light_paths_toggled(bool)) ); + connect( + m_light_paths_toggle_button, SIGNAL(toggled(bool)), + m_light_paths_manager, SLOT(slot_light_paths_display_toggled(bool)) + ); m_toolbar->addSeparator(); @@ -475,6 +534,9 @@ void ViewportTab::recreate_handlers() connect( m_camera_controller.get(), SIGNAL(signal_camera_changed()), SIGNAL(signal_camera_changed())); + connect( + m_camera_controller.get(), SIGNAL(signal_camera_changed()), + SLOT(slot_camera_changed())); connect( &m_project_explorer, SIGNAL(signal_frame_modified()), m_camera_controller.get(), SLOT(slot_frame_modified())); @@ -493,17 +555,23 @@ void ViewportTab::recreate_handlers() connect( m_scene_picking_handler.get(), SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), m_camera_controller.get(), SLOT(slot_entity_picked(renderer::ScenePicker::PickingResult))); + connect( + m_scene_picking_handler.get(), SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), + m_light_paths_manager, SLOT(slot_entity_picked(renderer::ScenePicker::PickingResult))); // Handler for setting render regions with the mouse. - m_render_region_handler.reset( - new RenderRegionHandler( + m_viewport_selection_handler.reset( + new ViewportRegionSelectionHandler( m_viewport_widget, *m_mouse_tracker.get())); connect( - m_render_region_handler.get(), SIGNAL(signal_rectangle_selection(const QRect&)), + m_viewport_selection_handler.get(), SIGNAL(signal_rectangle_selection(const QRect&)), SIGNAL(signal_rectangle_selection(const QRect&))); connect( - m_render_region_handler.get(), SIGNAL(signal_render_region(const QRect&)), + m_viewport_selection_handler.get(), SIGNAL(signal_rectangle_selection(const QRect&)), + m_light_paths_manager, SLOT(slot_rectangle_selection(const QRect&))); + connect( + m_viewport_selection_handler.get(), SIGNAL(signal_render_region(const QRect&)), SLOT(slot_set_render_region(const QRect&))); // Clipboard handler. diff --git a/src/appleseed.studio/mainwindow/rendering/viewporttab.h b/src/appleseed.studio/mainwindow/rendering/viewporttab.h index 6c358d1d56..a15230904e 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewporttab.h +++ b/src/appleseed.studio/mainwindow/rendering/viewporttab.h @@ -35,8 +35,8 @@ #include "mainwindow/rendering/pixelcolortracker.h" #include "mainwindow/rendering/pixelinspectorhandler.h" #include "mainwindow/rendering/renderclipboardhandler.h" -#include "mainwindow/rendering/renderregionhandler.h" #include "mainwindow/rendering/scenepickinghandler.h" +#include "mainwindow/rendering/viewportregionselectionhandler.h" #include "utility/mousecoordinatestracker.h" #include "utility/scrollareapanhandler.h" #include "utility/widgetzoomhandler.h" @@ -53,6 +53,7 @@ namespace OCIO = OCIO_NAMESPACE; #include // Forward declarations. +namespace appleseed { namespace studio { class LightPathsViewportManager; } } namespace appleseed { namespace studio { class ProjectExplorer; } } namespace appleseed { namespace studio { class ViewportWidget; } } namespace renderer { class Entity; } @@ -83,18 +84,18 @@ class ViewportTab ProjectExplorer& project_explorer, renderer::Project& project, RenderingManager& rendering_manager, - OCIO::ConstConfigRcPtr ocio_config); + OCIO::ConstConfigRcPtr ocio_config, + renderer::ParamArray application_settings); ViewportWidget* get_viewport_widget() const; CameraController* get_camera_controller() const; ScenePickingHandler* get_scene_picking_handler() const; - void enable_light_paths_toggle(); - void disable_light_paths_toggle(); - + void set_light_paths_enabled(const bool enabled); void set_clear_frame_button_enabled(const bool enabled); void set_render_region_buttons_enabled(const bool enabled); + void render_began(); void reset_zoom(); void update(); @@ -126,48 +127,54 @@ class ViewportTab void signal_rectangle_selection(const QRect& rect); private slots: - void slot_viewport_widget_context_menu(const QPoint& point); - void slot_toggle_render_region(const bool checked); + void slot_camera_changed(); + void slot_base_layer_changed(int index); void slot_set_render_region(const QRect& rect); void slot_toggle_pixel_inspector(const bool checked); + void slot_toggle_render_region(const bool checked); + void slot_viewport_widget_context_menu(const QPoint& point); private: - ViewportWidget* m_viewport_widget; - QScrollArea* m_scroll_area; - QToolBar* m_toolbar; - QToolButton* m_set_render_region_button; - QToolButton* m_clear_render_region_button; - QToolButton* m_clear_frame_button; - QToolButton* m_light_paths_toggle_button; - QComboBox* m_picking_mode_combo; - QComboBox* m_display_transform_combo; - QComboBox* m_base_layer_combo; - QLabel* m_info_label; - QLabel* m_r_label; - QLabel* m_g_label; - QLabel* m_b_label; - QLabel* m_a_label; - - ProjectExplorer& m_project_explorer; - renderer::Project& m_project; - RenderingManager& m_rendering_manager; - - std::unique_ptr m_zoom_handler; - std::unique_ptr m_pan_handler; - std::unique_ptr m_material_drop_handler; - std::unique_ptr m_mouse_tracker; - std::unique_ptr m_pixel_color_tracker; - std::unique_ptr m_pixel_inspector_handler; - std::unique_ptr m_camera_controller; - std::unique_ptr m_scene_picking_handler; - std::unique_ptr m_render_region_handler; - std::unique_ptr m_clipboard_handler; - - OCIO::ConstConfigRcPtr m_ocio_config; - - void create_viewport_widget(); - void create_toolbar(); + ViewportWidget* m_viewport_widget; + LightPathsViewportManager* m_light_paths_manager; + + QScrollArea* m_scroll_area; + QToolBar* m_toolbar; + QToolButton* m_set_render_region_button; + QToolButton* m_clear_render_region_button; + QToolButton* m_clear_frame_button; + QToolButton* m_light_paths_toggle_button; + QComboBox* m_picking_mode_combo; + QComboBox* m_display_transform_combo; + QComboBox* m_base_layer_combo; + QLabel* m_info_label; + QLabel* m_r_label; + QLabel* m_g_label; + QLabel* m_b_label; + QLabel* m_a_label; + + ProjectExplorer& m_project_explorer; + renderer::Project& m_project; + RenderingManager& m_rendering_manager; + renderer::ParamArray m_application_settings; + + std::unique_ptr m_zoom_handler; + std::unique_ptr m_pan_handler; + std::unique_ptr m_material_drop_handler; + std::unique_ptr m_mouse_tracker; + std::unique_ptr m_pixel_color_tracker; + std::unique_ptr m_pixel_inspector_handler; + std::unique_ptr m_camera_controller; + std::unique_ptr m_scene_picking_handler; + std::unique_ptr m_viewport_selection_handler; + std::unique_ptr m_clipboard_handler; + + OCIO::ConstConfigRcPtr m_ocio_config; + + void create_light_paths_manager(renderer::ParamArray application_settings); void create_scrollarea(); + void create_toolbar(); + void create_viewport_widget(); void recreate_handlers(); }; diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp index 068ec97681..2c2797d7c5 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp @@ -85,7 +85,7 @@ ViewportWidget::ViewportWidget( create_render_layer(ocio_config); create_gl_scene_layer(); - //create_light_paths_layer(); + create_light_paths_layer(); resize(width, height); @@ -120,26 +120,26 @@ void ViewportWidget::create_gl_scene_layer() m_width, m_height)); } -// -//void ViewportWidget::create_light_paths_layer() -//{ -// m_light_paths_layer = -// std::unique_ptr(new LightPathsLayer( -// m_project, -// m_width, -// m_height)); -//} + +void ViewportWidget::create_light_paths_layer() +{ + m_light_paths_layer = + std::unique_ptr(new LightPathsLayer( + m_project, + m_width, + m_height)); +} RenderLayer* ViewportWidget::get_render_layer() { return m_render_layer.get(); } -//LightPathsLayer* ViewportWidget::get_light_paths_layer() -//{ -// return m_light_paths_layer.get(); -//} -// +LightPathsLayer* ViewportWidget::get_light_paths_layer() +{ + return m_light_paths_layer.get(); +} + GLSceneLayer* ViewportWidget::get_gl_scene_layer() { return m_gl_scene_layer.get(); @@ -168,8 +168,9 @@ void ViewportWidget::initializeGL() { } m_gl_scene_layer->set_gl_functions(m_gl); - //m_light_paths_layer->set_gl_functions(m_gl); - //m_light_paths_layer->init_gl(qs_format); + m_gl_scene_layer->init_gl(qs_format); + m_light_paths_layer->set_gl_functions(m_gl); + m_light_paths_layer->init_gl(qs_format); } void ViewportWidget::resize( @@ -179,11 +180,14 @@ void ViewportWidget::resize( m_render_layer->resize(width, height); } -void ViewportWidget::paintGL() +void ViewportWidget::set_draw_light_paths_enabled(const bool enabled) { - if (!m_gl_scene_layer->is_initialized()) - m_gl_scene_layer->initialize(format()); + m_draw_light_paths = enabled; + update(); +} +void ViewportWidget::paintGL() +{ if (m_active_base_layer == BaseLayer::FinalRender) { m_painter.begin(this); @@ -199,8 +203,13 @@ void ViewportWidget::paintGL() if (m_active_base_layer == BaseLayer::OpenGL) m_gl_scene_layer->draw(); - //if (m_draw_light_paths) - // m_light_paths_layer->draw(); + if (m_draw_light_paths) + { + if (m_active_base_layer == BaseLayer::FinalRender) + m_light_paths_layer->draw_render_camera(); + else + m_light_paths_layer->draw(); + } } void ViewportWidget::dragEnterEvent(QDragEnterEvent* event) @@ -238,8 +247,7 @@ void ViewportWidget::slot_base_layer_changed(int index) void ViewportWidget::slot_light_paths_toggled(bool checked) { - m_draw_light_paths = checked; - update(); + set_draw_light_paths_enabled(checked); } } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h index 8147d3ba5d..eec1ff6810 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h @@ -30,9 +30,10 @@ // appleseed.studio headers. #include "mainwindow/rendering/lightpathslayer.h" +#include "mainwindow/rendering/glscenelayer.h" #include "mainwindow/rendering/renderclipboardhandler.h" #include "mainwindow/rendering/renderlayer.h" -#include "mainwindow/rendering/glscenelayer.h" + // appleseed.foundation headers. #include "foundation/image/image.h" @@ -104,7 +105,9 @@ class ViewportWidget RenderLayer* get_render_layer(); GLSceneLayer* get_gl_scene_layer(); - //LightPathsLayer* get_light_paths_layer(); + LightPathsLayer* get_light_paths_layer(); + + void set_draw_light_paths_enabled(const bool enabled); signals: void signal_material_dropped( @@ -125,14 +128,14 @@ class ViewportWidget std::unique_ptr m_render_layer; std::unique_ptr m_gl_scene_layer; - //std::unique_ptr m_light_paths_layer; + std::unique_ptr m_light_paths_layer; bool m_draw_light_paths; BaseLayer m_active_base_layer; - void create_render_layer(OCIO::ConstConfigRcPtr ocio_config); + void create_light_paths_layer(); void create_gl_scene_layer(); - //void create_light_paths_layer(); + void create_render_layer(OCIO::ConstConfigRcPtr ocio_config); void initializeGL() override; void paintGL() override; From 9b720239884ea72fa6d066b40206faec952891f9 Mon Sep 17 00:00:00 2001 From: Gray Olson Date: Tue, 25 Jun 2019 17:00:21 -0700 Subject: [PATCH 4/6] new light path drawing using antialisased billboarded quads --- .../mainwindow/rendering/lightpathslayer.cpp | 351 +++++++++++++----- .../mainwindow/rendering/lightpathslayer.h | 22 +- .../mainwindow/rendering/viewportwidget.cpp | 12 +- .../mainwindow/rendering/viewportwidget.h | 1 + .../resources/shaders/lightpaths.frag | 13 +- .../resources/shaders/lightpaths.vert | 84 ++++- .../lighting/directlightingintegrator.cpp | 2 + .../kernel/lighting/lightpathrecorder.cpp | 4 + .../kernel/lighting/lightpathrecorder.h | 1 + .../kernel/lighting/lightpathstream.cpp | 19 +- .../kernel/lighting/lightpathstream.h | 9 +- .../kernel/lighting/pt/ptlightingengine.cpp | 3 +- 12 files changed, 403 insertions(+), 118 deletions(-) diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp index afafce1605..50ed9b135f 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp @@ -57,6 +57,7 @@ // Standard headers. #include #include +#include using namespace foundation; using namespace renderer; @@ -66,59 +67,15 @@ namespace appleseed { namespace studio { namespace { - // Number of floats per OpenGL vertex for a piece of scene geometry - // Vector3 position and Vector3 normal. - const size_t SceneVertexFloatStride = 6; - // Number of bytes per OpenGL vertex for a piece of scene geometry. - const size_t SceneVertexByteStride = SceneVertexFloatStride * sizeof(float); - // Number of floats per triangle for a piece of scene geometry. - const size_t SceneTriangleFloatStride = SceneVertexFloatStride * 3; - - // Number of floats per OpenGL vertex for a light path - // Vector3 position and Vector3 color. - const size_t LightPathVertexFloatStride = 6; - // Number of bytes per OpenGL vertex for a piece of scene geometry. - const size_t LightPathVertexByteStride = LightPathVertexFloatStride * sizeof(float); - // Number of floats per line for a light path. - const size_t LightPathVertexLineFloatStride = LightPathVertexFloatStride * 2; - - // Number of floats per OpenGL transform matrix. - const size_t TransformFloatStride = 16; - // Number of bytes per OpenGL transform matrix. - const size_t TransformByteStride = TransformFloatStride * sizeof(float); - - struct OpenGLRasterizer - : public ObjectRasterizer - { - vector m_buffer; - size_t m_prim_count; - - void begin_object(const size_t triangle_count_hint) override - { - m_buffer.clear(); - m_buffer.reserve(triangle_count_hint * SceneTriangleFloatStride); - m_prim_count = 0; - } - - void end_object() override {} - - void rasterize(const Triangle& triangle) override - { - const float temp_store[SceneTriangleFloatStride] = - { - static_cast(triangle.m_v0[0]), static_cast(triangle.m_v0[1]), static_cast(triangle.m_v0[2]), - static_cast(triangle.m_n0[0]), static_cast(triangle.m_n0[1]), static_cast(triangle.m_n0[2]), - - static_cast(triangle.m_v1[0]), static_cast(triangle.m_v1[1]), static_cast(triangle.m_v1[2]), - static_cast(triangle.m_n1[0]), static_cast(triangle.m_n1[1]), static_cast(triangle.m_n1[2]), - - static_cast(triangle.m_v2[0]), static_cast(triangle.m_v2[1]), static_cast(triangle.m_v2[2]), - static_cast(triangle.m_n2[0]), static_cast(triangle.m_n2[1]), static_cast(triangle.m_n2[2]), - }; - m_buffer.reserve(m_buffer.size() + SceneTriangleFloatStride); - m_buffer.insert(m_buffer.end(), temp_store, temp_store + SceneTriangleFloatStride); - m_prim_count++; - } + // Byte stride of a vec3. + const size_t Vec3ByteStride = sizeof(float) * 3; + + // Struct of an element of the "others" vertex buffer + struct OtherAttributes { + GLfloat v_luminance; + GLint v_distance_start_end; + GLfloat v_color[3]; + GLfloat v_surface_normal[3]; }; } @@ -131,12 +88,23 @@ LightPathsLayer::LightPathsLayer( , m_backface_culling_enabled(false) , m_selected_light_path_index(-1) , m_gl_initialized(false) + , m_width(width) + , m_height(height) + , m_max_thickness(4.0f) + , m_min_thickness(1.0f) + , m_max_luminance(0.0f) { const float time = m_camera.get_shutter_middle_time(); set_transform(m_camera.transform_sequence().evaluate(time)); } +void LightPathsLayer::resize(const size_t width, const size_t height) +{ + m_width = width, + m_height = height; +} + void LightPathsLayer::set_gl_functions(QOpenGLFunctions_3_3_Core* functions) { m_gl = functions; @@ -228,18 +196,42 @@ void LightPathsLayer::slot_synchronize_camera() void LightPathsLayer::load_light_paths_data() { - m_light_paths_index_offsets.clear(); + m_index_offsets.clear(); + m_max_luminance = 0.0f; if (!m_light_paths.empty()) { - m_light_paths_index_offsets.push_back(0); + m_index_offsets.push_back(0); const auto& light_path_recorder = m_project.get_light_path_recorder(); - const size_t total_gl_vertex_count = 2 * (light_path_recorder.get_vertex_count() - 2) + 2; - GLsizei total_index_count = 0; - vector buffer; - buffer.reserve(total_gl_vertex_count * LightPathVertexFloatStride); + + // Vertex count * 4 since we will be adding two vertices for each point along the line and will + // be adding each point twice for the beginning and end parts of each segment + // Add two because we need extra at the front and back for the extra 'previous' and 'next' attributes + const size_t total_gl_vertex_count = 2 * (light_path_recorder.get_vertex_count() + 2); + + vector indices; + vector positions_buffer; + // * 3 since we want 3 floats per position + positions_buffer.reserve(total_gl_vertex_count * 3); + indices.reserve(total_gl_vertex_count); + + // Add an empty vertex at the beginning to serve as first 'previous' + array empty_positions = + { + 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, + }; + positions_buffer.insert( + positions_buffer.end(), + empty_positions.begin(), + empty_positions.end()); + + vector others_buffer; + others_buffer.reserve(total_gl_vertex_count); + array others; + for (size_t light_path_idx = 0; light_path_idx < m_light_paths.size(); light_path_idx++) { const auto& path = m_light_paths[light_path_idx]; @@ -249,34 +241,102 @@ void LightPathsLayer::load_light_paths_data() light_path_recorder.get_light_path_vertex(path.m_vertex_begin_index, prev); for (size_t vertex_idx = path.m_vertex_begin_index + 1; vertex_idx < path.m_vertex_end_index; vertex_idx++) { - LightPathVertex curr; - light_path_recorder.get_light_path_vertex(vertex_idx, curr); + LightPathVertex vert; + light_path_recorder.get_light_path_vertex(vertex_idx, vert); - auto piece_radiance = Color3f::from_array(curr.m_radiance); - piece_radiance /= piece_radiance + Color3f(1.0f); + auto piece_radiance = Color3f::from_array(vert.m_radiance); piece_radiance = linear_rgb_to_srgb(piece_radiance); + auto piece_luminance = luminance(piece_radiance); + m_max_luminance = max(m_max_luminance, piece_luminance); + piece_radiance /= piece_luminance; + //piece_radiance /= piece_radiance + Color3f(1.0); - const float temp_store[LightPathVertexLineFloatStride] = - { + array positions_temp_store = { prev.m_position[0], prev.m_position[1], prev.m_position[2], - piece_radiance[0], piece_radiance[1], piece_radiance[2], - - curr.m_position[0], curr.m_position[1], curr.m_position[2], - piece_radiance[0], piece_radiance[1], piece_radiance[2], + prev.m_position[0], prev.m_position[1], prev.m_position[2], + vert.m_position[0], vert.m_position[1], vert.m_position[2], + vert.m_position[0], vert.m_position[1], vert.m_position[2], + }; + positions_buffer.insert( + positions_buffer.end(), + positions_temp_store.begin(), + positions_temp_store.end()); + + unsigned int start_index = static_cast(others_buffer.size()); + + GLint start = 2; + GLint end = 4; + + others = {{ + { + piece_luminance, + start, + {piece_radiance[0], piece_radiance[1], piece_radiance[2]}, + {prev.m_surface_normal[0], prev.m_surface_normal[1], prev.m_surface_normal[2]} + }, + { + piece_luminance, + 1 | start, + {piece_radiance[0], piece_radiance[1], piece_radiance[2]}, + {prev.m_surface_normal[0], prev.m_surface_normal[1], prev.m_surface_normal[2]} + }, + { + piece_luminance, + end, + {piece_radiance[0], piece_radiance[1], piece_radiance[2]}, + {vert.m_surface_normal[0], vert.m_surface_normal[1], vert.m_surface_normal[2]} + }, + { + piece_luminance, + 1 | end, + {piece_radiance[0], piece_radiance[1], piece_radiance[2]}, + {vert.m_surface_normal[0], vert.m_surface_normal[1], vert.m_surface_normal[2]} + }, + }}; + others_buffer.insert( + others_buffer.end(), + others.begin(), + others.end()); + + array indices_scratch = { + start_index, start_index + 1, start_index + 2, + start_index + 1, start_index + 2, start_index + 3, }; - buffer.insert(buffer.end(), temp_store, temp_store + 12); + indices.insert( + indices.end(), + indices_scratch.begin(), + indices_scratch.end()); - total_index_count += 2; - prev = curr; + total_index_count += 6; + prev = vert; } - m_light_paths_index_offsets.push_back(total_index_count); + m_index_offsets.push_back(total_index_count); } - m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_light_paths_vbo); + // Add an empty vertex at the end to serve as last 'next' + positions_buffer.insert( + positions_buffer.end(), + empty_positions.begin(), + empty_positions.end()); + + // Upload the data to the buffers + m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_positions_vbo); m_gl->glBufferData( GL_ARRAY_BUFFER, - buffer.size() * sizeof(float), - reinterpret_cast(&buffer[0]), + positions_buffer.size() * sizeof(float), + reinterpret_cast(&positions_buffer[0]), + GL_STATIC_DRAW); + m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_others_vbo); + m_gl->glBufferData( + GL_ARRAY_BUFFER, + others_buffer.size() * sizeof(OtherAttributes), + reinterpret_cast(&others_buffer[0]), + GL_STATIC_DRAW); + m_gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices_ebo); + m_gl->glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + indices.size() * sizeof(unsigned int), + reinterpret_cast(&indices[0]), GL_STATIC_DRAW); } } @@ -380,12 +440,16 @@ void LightPathsLayer::init_gl(QSurfaceFormat format) create_shader_program( m_gl, - m_light_paths_shader_program, + m_shader_program, vertex_shader, fragment_shader); - m_light_paths_view_mat_location = m_gl->glGetUniformLocation(m_light_paths_shader_program, "u_view"); - m_light_paths_proj_mat_location = m_gl->glGetUniformLocation(m_light_paths_shader_program, "u_proj"); + m_view_mat_loc = m_gl->glGetUniformLocation(m_shader_program, "u_view"); + m_proj_mat_loc = m_gl->glGetUniformLocation(m_shader_program, "u_proj"); + m_res_loc = m_gl->glGetUniformLocation(m_shader_program, "u_res"); + m_max_luminance_loc = m_gl->glGetUniformLocation(m_shader_program, "u_max_luminance"); + m_max_thickness_loc = m_gl->glGetUniformLocation(m_shader_program, "u_max_thickness"); + m_min_thickness_loc = m_gl->glGetUniformLocation(m_shader_program, "u_min_thickness"); const float z_near = 0.01f; const float z_far = 1000.0f; @@ -408,32 +472,102 @@ void LightPathsLayer::init_gl(QSurfaceFormat format) m_gl_proj_matrix = transpose(Matrix4f::make_frustum(top, bottom, left, right, z_near, z_far)); GLuint temp_light_paths_vao = 0; - GLuint temp_light_paths_vbo = 0; m_gl->glGenVertexArrays(1, &temp_light_paths_vao); - m_gl->glGenBuffers(1, &temp_light_paths_vbo); m_light_paths_vao = temp_light_paths_vao; - m_light_paths_vbo = temp_light_paths_vbo; + + GLuint temp_vbos[3] = {0, 0, 0}; + m_gl->glGenBuffers(3, &temp_vbos[0]); + m_positions_vbo = temp_vbos[0]; + m_others_vbo = temp_vbos[1]; + m_indices_ebo = temp_vbos[2]; m_gl->glBindVertexArray(m_light_paths_vao); - m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_light_paths_vbo); + + m_gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices_ebo); + + // v_previous, v_position, and v_next all reference offsets into the same vertex data buffer. + // v_previous is at vertex offset 0, v_position is at vertex offset 2 and v_next is at vertex offset 4. + // See http://codeflow.org/entries/2012/aug/05/webgl-rendering-of-solid-trails/ for reference. + m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_positions_vbo); + + // vec3 v_previous; m_gl->glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, - LightPathVertexByteStride, + Vec3ByteStride, reinterpret_cast(0)); + m_gl->glEnableVertexAttribArray(0); + + // vec3 v_position; m_gl->glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, - LightPathVertexByteStride, - reinterpret_cast(LightPathVertexByteStride / 2)); - m_gl->glEnableVertexAttribArray(0); + Vec3ByteStride, + reinterpret_cast(Vec3ByteStride * 2)); m_gl->glEnableVertexAttribArray(1); + // vec3 v_next; + m_gl->glVertexAttribPointer( + 2, + 3, + GL_FLOAT, + GL_FALSE, + Vec3ByteStride, + reinterpret_cast(Vec3ByteStride * 4)); + m_gl->glEnableVertexAttribArray(2); + + // The rest of the attributes are stored in a separate data buffer, interleaved. + m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_others_vbo); + + // float v_thickness; + m_gl->glVertexAttribPointer( + 3, + 1, + GL_FLOAT, + GL_FALSE, + sizeof(OtherAttributes), + reinterpret_cast(0)); + m_gl->glEnableVertexAttribArray(3); + + // This attribute stores 3 bools: + // bit 0: normal direction which maps to -1.0 (false) or 1.0 (true) + // bit 1: whether this is the start vertex of a new path + // bit 2: whether this is the end vertex of a path + // int v_direction_start_end; + m_gl->glVertexAttribIPointer( + 4, + 1, + GL_INT, + sizeof(OtherAttributes), + reinterpret_cast(sizeof(GLfloat))); + m_gl->glEnableVertexAttribArray(4); + + // vec3 v_color; + m_gl->glVertexAttribPointer( + 5, + 3, + GL_FLOAT, + GL_FALSE, + sizeof(OtherAttributes), + reinterpret_cast(sizeof(GLfloat) + sizeof(GLint))); + m_gl->glEnableVertexAttribArray(5); + + // vec3 v_surface_normal; + m_gl->glVertexAttribPointer( + 6, + 3, + GL_FLOAT, + GL_FALSE, + sizeof(OtherAttributes), + reinterpret_cast(sizeof(GLfloat) + sizeof(GLint) + 3 * sizeof(GLfloat))); + m_gl->glEnableVertexAttribArray(6); + m_gl->glBindVertexArray(0); + m_gl->glBindBuffer(GL_ARRAY_BUFFER, 0); load_light_paths_data(); @@ -442,22 +576,30 @@ void LightPathsLayer::init_gl(QSurfaceFormat format) void LightPathsLayer::cleanup_gl_data() { - if (m_light_paths_shader_program != 0) + if (m_shader_program != 0) { - m_gl->glDeleteProgram(m_light_paths_shader_program); + m_gl->glDeleteProgram(m_shader_program); } } void LightPathsLayer::draw_render_camera() const { auto gl_view_matrix = const_cast(&m_gl_render_view_matrix[0]); + + m_gl->glEnable(GL_BLEND); + m_gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); render_scene(gl_view_matrix); + m_gl->glDisable(GL_BLEND); } void LightPathsLayer::draw() const { auto gl_view_matrix = const_cast(&m_gl_view_matrix[0]); + + m_gl->glEnable(GL_BLEND); + m_gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); render_scene(gl_view_matrix); + m_gl->glDisable(GL_BLEND); } void LightPathsLayer::render_scene(const GLfloat* gl_view_matrix) const @@ -473,20 +615,33 @@ void LightPathsLayer::render_scene(const GLfloat* gl_view_matrix) const m_gl->glEnable(GL_DEPTH_TEST); m_gl->glDepthFunc(GL_LEQUAL); - if (m_light_paths_index_offsets.size() > 1) + if (m_index_offsets.size() > 1) { - m_gl->glUseProgram(m_light_paths_shader_program); + m_gl->glUseProgram(m_shader_program); m_gl->glUniformMatrix4fv( - m_light_paths_view_mat_location, + m_view_mat_loc, 1, false, gl_view_matrix); m_gl->glUniformMatrix4fv( - m_light_paths_proj_mat_location, + m_proj_mat_loc, 1, false, const_cast(&m_gl_proj_matrix[0])); + m_gl->glUniform1f( + m_max_luminance_loc, + m_max_luminance); + m_gl->glUniform1f( + m_max_thickness_loc, + m_max_thickness); + m_gl->glUniform1f( + m_min_thickness_loc, + m_min_thickness); + m_gl->glUniform2f( + m_res_loc, + (GLfloat)m_width, + (GLfloat)m_height); m_gl->glBindVertexArray(m_light_paths_vao); @@ -496,14 +651,16 @@ void LightPathsLayer::render_scene(const GLfloat* gl_view_matrix) const if (m_selected_light_path_index == -1) { first = 0; - count = m_light_paths_index_offsets[m_light_paths_index_offsets.size() - 1]; + count = m_index_offsets[m_index_offsets.size() - 1] / 3; } else { - first = static_cast(m_light_paths_index_offsets[m_selected_light_path_index]); - count = m_light_paths_index_offsets[m_selected_light_path_index + 1] - first; + first = static_cast(m_index_offsets[m_selected_light_path_index]); + count = m_index_offsets[m_selected_light_path_index + 1] - first; } - glDrawArrays(GL_LINES, first, count); + m_gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indices_ebo); + m_gl->glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, reinterpret_cast(first * sizeof(unsigned int))); + m_gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } } diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h index 62ce3e00ce..6908a399cd 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h @@ -77,6 +77,7 @@ class LightPathsLayer: public QObject const size_t width, const size_t height); + void resize(const size_t width, const size_t height); void update_render_camera_transform(); @@ -120,15 +121,26 @@ class LightPathsLayer: public QObject renderer::LightPathArray m_light_paths; int m_selected_light_path_index; // -1 == display all paths + float m_max_luminance; + float m_max_thickness; + float m_min_thickness; + size_t m_width; + size_t m_height; QOpenGLFunctions_3_3_Core* m_gl; - GLuint m_light_paths_vbo; - std::vector m_light_paths_index_offsets; + GLuint m_positions_vbo; + GLuint m_others_vbo; + GLuint m_indices_ebo; + std::vector m_index_offsets; GLuint m_light_paths_vao; - GLuint m_light_paths_shader_program; - GLint m_light_paths_view_mat_location; - GLint m_light_paths_proj_mat_location; + GLuint m_shader_program; + GLint m_view_mat_loc; + GLint m_proj_mat_loc; + GLint m_res_loc; + GLint m_max_luminance_loc; + GLint m_min_thickness_loc; + GLint m_max_thickness_loc; foundation::Matrix4f m_gl_render_view_matrix; foundation::Matrix4f m_gl_view_matrix; foundation::Matrix4f m_gl_proj_matrix; diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp index 2c2797d7c5..9ca818212c 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp @@ -174,10 +174,18 @@ void ViewportWidget::initializeGL() { } void ViewportWidget::resize( - const size_t width, - const size_t height) + const size_t width, + const size_t height) { m_render_layer->resize(width, height); + m_light_paths_layer->resize(width, height); +} + +void ViewportWidget::resizeGL( + int width, + int height) +{ + m_light_paths_layer->resize(width, height); } void ViewportWidget::set_draw_light_paths_enabled(const bool enabled) diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h index eec1ff6810..43568b2f76 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h @@ -138,6 +138,7 @@ class ViewportWidget void create_render_layer(OCIO::ConstConfigRcPtr ocio_config); void initializeGL() override; + void resizeGL(int width, int height) override; void paintGL() override; void dragEnterEvent(QDragEnterEvent* event) override; void dragMoveEvent(QDragMoveEvent* event) override; diff --git a/src/appleseed.studio/resources/shaders/lightpaths.frag b/src/appleseed.studio/resources/shaders/lightpaths.frag index f67540108f..01d3191617 100644 --- a/src/appleseed.studio/resources/shaders/lightpaths.frag +++ b/src/appleseed.studio/resources/shaders/lightpaths.frag @@ -28,11 +28,20 @@ #version 330 #extension GL_ARB_separate_shader_objects : enable -layout(location = 0) in vec3 v_color; +flat in vec3 f_color; +in float f_aa_norm; +flat in float f_thickness; +flat in float f_total_thickness; +flat in float f_aspect_expansion_len; + +uniform vec2 u_res; out vec4 Target0; void main() { - Target0 = vec4(v_color, 1.0); + float dist = abs(f_aa_norm) * f_total_thickness - 0.5 / f_aspect_expansion_len; + float eps = fwidth(dist); + float a = 1.0 - smoothstep(f_thickness - eps, f_thickness + eps, dist); + Target0 = vec4(f_color, a); } diff --git a/src/appleseed.studio/resources/shaders/lightpaths.vert b/src/appleseed.studio/resources/shaders/lightpaths.vert index 6664383094..579c386a39 100644 --- a/src/appleseed.studio/resources/shaders/lightpaths.vert +++ b/src/appleseed.studio/resources/shaders/lightpaths.vert @@ -26,18 +26,84 @@ // #version 330 -#extension GL_ARB_separate_shader_objects : enable -layout(location = 0) in vec3 a_pos; -layout(location = 1) in vec3 a_color; +const float AA_BUFFER_SIZE = 1.0; + +layout(location = 0) in vec3 v_previous; +layout(location = 1) in vec3 v_position; +layout(location = 2) in vec3 v_next; +layout(location = 3) in float v_luminance; +layout(location = 4) in int v_direction_start_end; +layout(location = 5) in vec3 v_color; +layout(location = 6) in vec3 v_surface_normal; -uniform mat4 u_view; uniform mat4 u_proj; +uniform mat4 u_view; +uniform vec2 u_res; +uniform float u_max_luminance; +uniform float u_max_thickness; +uniform float u_min_thickness; + +flat out vec3 f_color; +out float f_aa_norm; +flat out float f_thickness; +flat out float f_total_thickness; +flat out float f_aspect_expansion_len; + +void main() { + float aspect = u_res.x / u_res.y; + vec2 aspect_vec = vec2(aspect, 1.0); + mat4 vp = u_proj * u_view; + vec4 prev_proj = vp * vec4(v_previous, 1.0); + vec4 curr_proj = vp * vec4(v_position, 1.0); + vec4 next_proj = vp * vec4(v_next, 1.0); + + //get 2D screen space with W divide and aspect correction + vec2 curr_screen = curr_proj.xy / curr_proj.w * aspect_vec; + vec2 prev_screen = prev_proj.xy / prev_proj.w * aspect_vec; + vec2 next_screen = next_proj.xy / next_proj.w * aspect_vec; + + float orientation = 1.0; + if ((v_direction_start_end & 1) == 1) + { + orientation = -1.0; + } + + vec2 dir = vec2(0.0); + if ((v_direction_start_end & 2) == 2) + { + //starting point uses (next - current) + dir = normalize(next_screen - curr_screen); + } + else if ((v_direction_start_end & 4) == 4) + { + //ending point uses (current - v_previous) + dir = normalize(curr_screen - prev_screen); + } + vec2 perp_dir = vec2(-dir.y, dir.x); + + vec4 normal_clip = vp * vec4(v_surface_normal, 0.0); + normal_clip.xy *= aspect_vec; + normal_clip = normalize(normal_clip); + vec2 tang_clip = vec2(-normal_clip.y, normal_clip.x); + + float tdp = dot(tang_clip, perp_dir); + vec2 expansion = perp_dir; + if (tdp > 0.05) + expansion = tang_clip / tdp; + + vec2 norm_exp = normalize(expansion); + vec2 res_exp_dir = vec2(norm_exp.x * u_res.x, norm_exp.y * u_res.y); + f_aspect_expansion_len = length(res_exp_dir); + + f_thickness = (max(max(min(v_luminance / u_max_luminance, 1.0), 0.0) * u_max_thickness, u_min_thickness) / 2.0) / f_aspect_expansion_len; + + f_total_thickness = f_thickness + AA_BUFFER_SIZE / f_aspect_expansion_len; -layout(location = 0) out vec3 v_color; + expansion *= f_total_thickness; + expansion *= orientation; -void main() -{ - v_color = a_color; - gl_Position = u_proj * u_view * vec4(a_pos, 1.0); + gl_Position = vec4((curr_screen + expansion) / aspect_vec, curr_proj.z / curr_proj.w, 1.0); + f_aa_norm = orientation; + f_color = v_color; } diff --git a/src/appleseed/renderer/kernel/lighting/directlightingintegrator.cpp b/src/appleseed/renderer/kernel/lighting/directlightingintegrator.cpp index c88abfc1a1..a49e71c6b7 100644 --- a/src/appleseed/renderer/kernel/lighting/directlightingintegrator.cpp +++ b/src/appleseed/renderer/kernel/lighting/directlightingintegrator.cpp @@ -466,6 +466,7 @@ void DirectLightingIntegrator::add_emitting_shape_sample_contribution( light_path_stream->sampled_emitting_shape( *sample.m_shape, sample.m_point, + sample.m_geometric_normal, material_value.m_beauty, edf_value); } @@ -541,6 +542,7 @@ void DirectLightingIntegrator::add_non_physical_light_sample_contribution( light_path_stream->sampled_non_physical_light( *light, emission_position, + m_material_sampler.get_shading_point().get_geometric_normal(), material_value.m_beauty, light_value); } diff --git a/src/appleseed/renderer/kernel/lighting/lightpathrecorder.cpp b/src/appleseed/renderer/kernel/lighting/lightpathrecorder.cpp index 7e65c6e59b..29eb235de6 100644 --- a/src/appleseed/renderer/kernel/lighting/lightpathrecorder.cpp +++ b/src/appleseed/renderer/kernel/lighting/lightpathrecorder.cpp @@ -276,6 +276,10 @@ void LightPathRecorder::get_light_path_vertex( result.m_radiance[0] = source_vertex.m_radiance[0]; result.m_radiance[1] = source_vertex.m_radiance[1]; result.m_radiance[2] = source_vertex.m_radiance[2]; + + result.m_surface_normal[0] = source_vertex.m_surface_normal[0]; + result.m_surface_normal[1] = source_vertex.m_surface_normal[1]; + result.m_surface_normal[2] = source_vertex.m_surface_normal[2]; } bool LightPathRecorder::write(const char* filename) const diff --git a/src/appleseed/renderer/kernel/lighting/lightpathrecorder.h b/src/appleseed/renderer/kernel/lighting/lightpathrecorder.h index cebcebc3d9..93e094c774 100644 --- a/src/appleseed/renderer/kernel/lighting/lightpathrecorder.h +++ b/src/appleseed/renderer/kernel/lighting/lightpathrecorder.h @@ -68,6 +68,7 @@ struct LightPathVertex const Entity* m_entity; float m_position[3]; float m_radiance[3]; + float m_surface_normal[3]; }; diff --git a/src/appleseed/renderer/kernel/lighting/lightpathstream.cpp b/src/appleseed/renderer/kernel/lighting/lightpathstream.cpp index 8b20aab94c..61c9ed0323 100644 --- a/src/appleseed/renderer/kernel/lighting/lightpathstream.cpp +++ b/src/appleseed/renderer/kernel/lighting/lightpathstream.cpp @@ -77,7 +77,8 @@ void LightPathStream::clear() void LightPathStream::begin_path( const PixelContext& pixel_context, const Camera* camera, - const Vector3d& camera_vertex_position) + const Vector3d& camera_vertex_position, + const Vector3d& camera_vertex_normal) { assert(m_events.empty()); assert(m_hit_reflector_data.empty()); @@ -90,6 +91,7 @@ void LightPathStream::begin_path( m_camera = camera; m_camera_vertex_position = Vector3f(camera_vertex_position); + m_camera_vertex_normal = Vector3f(camera_vertex_normal); m_pixel_coords = pixel_context.get_pixel_coords(); m_sample_position = Vector2f(pixel_context.get_sample_position()); } @@ -107,6 +109,7 @@ void LightPathStream::hit_reflector(const PathVertex& vertex) HitReflectorData data; data.m_object_instance = &vertex.m_shading_point->get_object_instance(); data.m_vertex_position = Vector3f(vertex.get_point()); + data.m_surface_normal = Vector3f(vertex.get_geometric_normal()); data.m_path_throughput = vertex.m_throughput.to_rgb(g_std_lighting_conditions); m_hit_reflector_data.push_back(data); } @@ -126,6 +129,7 @@ void LightPathStream::hit_emitter( HitEmitterData data; data.m_object_instance = &vertex.m_shading_point->get_object_instance(); data.m_vertex_position = Vector3f(vertex.get_point()); + data.m_surface_normal = Vector3f(vertex.get_geometric_normal()); data.m_path_throughput = vertex.m_throughput.to_rgb(g_std_lighting_conditions); data.m_emitted_radiance = emitted_radiance.to_rgb(g_std_lighting_conditions); m_hit_emitter_data.push_back(data); @@ -134,6 +138,7 @@ void LightPathStream::hit_emitter( void LightPathStream::sampled_emitting_shape( const EmittingShape& shape, const Vector3d& emission_position, + const Vector3d& emission_normal, const Spectrum& material_value, const Spectrum& emitted_radiance) { @@ -147,6 +152,7 @@ void LightPathStream::sampled_emitting_shape( shape.get_assembly_instance()->get_assembly().object_instances().get_by_index( shape.get_object_instance_index()); data.m_vertex_position = Vector3f(emission_position); + data.m_surface_normal = Vector3f(emission_normal); data.m_material_value = material_value.to_rgb(g_std_lighting_conditions); data.m_emitted_radiance = emitted_radiance.to_rgb(g_std_lighting_conditions); m_sampled_emitter_data.push_back(data); @@ -155,6 +161,7 @@ void LightPathStream::sampled_emitting_shape( void LightPathStream::sampled_non_physical_light( const Light& light, const Vector3d& emission_position, + const Vector3d& emission_normal, const Spectrum& material_value, const Spectrum& emitted_radiance) { @@ -166,6 +173,7 @@ void LightPathStream::sampled_non_physical_light( SampledEmitterData data; data.m_entity = &light; data.m_vertex_position = Vector3f(emission_position); + data.m_surface_normal = Vector3f(emission_normal); data.m_material_value = material_value.to_rgb(g_std_lighting_conditions); data.m_emitted_radiance = emitted_radiance.to_rgb(g_std_lighting_conditions); m_sampled_emitter_data.push_back(data); @@ -244,6 +252,7 @@ void LightPathStream::create_path_from_hit_emitter(const size_t emitter_event_in StoredPathVertex emitter_vertex; emitter_vertex.m_entity = hit_emitter_data.m_object_instance; emitter_vertex.m_position = hit_emitter_data.m_vertex_position; + emitter_vertex.m_surface_normal = hit_emitter_data.m_surface_normal; emitter_vertex.m_radiance = hit_emitter_data.m_emitted_radiance; m_vertices.push_back(emitter_vertex); @@ -264,6 +273,7 @@ void LightPathStream::create_path_from_hit_emitter(const size_t emitter_event_in StoredPathVertex reflector_vertex; reflector_vertex.m_entity = event_data.m_object_instance; reflector_vertex.m_position = event_data.m_vertex_position; + reflector_vertex.m_surface_normal = event_data.m_surface_normal; reflector_vertex.m_radiance = current_radiance; m_vertices.push_back(reflector_vertex); @@ -288,6 +298,7 @@ void LightPathStream::create_path_from_hit_emitter(const size_t emitter_event_in StoredPathVertex camera_vertex; camera_vertex.m_entity = m_camera; camera_vertex.m_position = m_camera_vertex_position; + camera_vertex.m_surface_normal = m_camera_vertex_normal; camera_vertex.m_radiance = current_radiance; m_vertices.push_back(camera_vertex); @@ -319,6 +330,7 @@ void LightPathStream::create_path_from_sampled_emitter(const size_t emitter_even StoredPathVertex emitter_vertex; emitter_vertex.m_entity = sampled_emitter_data.m_entity; emitter_vertex.m_position = sampled_emitter_data.m_vertex_position; + emitter_vertex.m_surface_normal = sampled_emitter_data.m_surface_normal; emitter_vertex.m_radiance = sampled_emitter_data.m_emitted_radiance; m_vertices.push_back(emitter_vertex); @@ -339,6 +351,7 @@ void LightPathStream::create_path_from_sampled_emitter(const size_t emitter_even StoredPathVertex reflector_vertex; reflector_vertex.m_entity = event_data.m_object_instance; reflector_vertex.m_position = event_data.m_vertex_position; + reflector_vertex.m_surface_normal = event_data.m_surface_normal; reflector_vertex.m_radiance = current_radiance; m_vertices.push_back(reflector_vertex); @@ -363,6 +376,7 @@ void LightPathStream::create_path_from_sampled_emitter(const size_t emitter_even StoredPathVertex camera_vertex; camera_vertex.m_entity = m_camera; camera_vertex.m_position = m_camera_vertex_position; + camera_vertex.m_surface_normal = m_camera_vertex_normal; camera_vertex.m_radiance = current_radiance; m_vertices.push_back(camera_vertex); @@ -394,6 +408,7 @@ void LightPathStream::create_path_from_sampled_environment(const size_t env_even StoredPathVertex emitter_vertex; emitter_vertex.m_entity = sampled_env_data.m_environment_edf; emitter_vertex.m_position = last_reflector_data.m_vertex_position + m_scene_diameter * sampled_env_data.m_emission_direction; + emitter_vertex.m_surface_normal = -sampled_env_data.m_emission_direction; emitter_vertex.m_radiance = sampled_env_data.m_emitted_radiance; m_vertices.push_back(emitter_vertex); @@ -414,6 +429,7 @@ void LightPathStream::create_path_from_sampled_environment(const size_t env_even StoredPathVertex reflector_vertex; reflector_vertex.m_entity = event_data.m_object_instance; reflector_vertex.m_position = event_data.m_vertex_position; + reflector_vertex.m_surface_normal = event_data.m_surface_normal; reflector_vertex.m_radiance = current_radiance; m_vertices.push_back(reflector_vertex); @@ -438,6 +454,7 @@ void LightPathStream::create_path_from_sampled_environment(const size_t env_even StoredPathVertex camera_vertex; camera_vertex.m_entity = m_camera; camera_vertex.m_position = m_camera_vertex_position; + camera_vertex.m_surface_normal = m_camera_vertex_normal; camera_vertex.m_radiance = current_radiance; m_vertices.push_back(camera_vertex); diff --git a/src/appleseed/renderer/kernel/lighting/lightpathstream.h b/src/appleseed/renderer/kernel/lighting/lightpathstream.h index 10488fae25..ce7e9bbdfe 100644 --- a/src/appleseed/renderer/kernel/lighting/lightpathstream.h +++ b/src/appleseed/renderer/kernel/lighting/lightpathstream.h @@ -67,7 +67,8 @@ class LightPathStream void begin_path( const PixelContext& pixel_context, const Camera* camera, - const foundation::Vector3d& camera_vertex_position); + const foundation::Vector3d& camera_vertex_position, + const foundation::Vector3d& camera_vertex_normal); void hit_reflector( const PathVertex& vertex); @@ -79,12 +80,14 @@ class LightPathStream void sampled_emitting_shape( const EmittingShape& shape, const foundation::Vector3d& emission_position, + const foundation::Vector3d& emission_normal, const Spectrum& material_value, const Spectrum& emitted_radiance); void sampled_non_physical_light( const Light& light, const foundation::Vector3d& emission_position, + const foundation::Vector3d& emission_normal, const Spectrum& material_value, const Spectrum& emitted_radiance); @@ -117,6 +120,7 @@ class LightPathStream { const ObjectInstance* m_object_instance; // object instance that was hit foundation::Vector3f m_vertex_position; // world space position of the hit point on the reflector + foundation::Vector3f m_surface_normal; // world space normal of the surface of the reflector foundation::Color3f m_path_throughput; // cumulative path throughput up to but excluding this vertex, in reverse order (i.e. in the order from camera to light source) }; @@ -130,6 +134,7 @@ class LightPathStream { const Entity* m_entity; // object instance or non-physical light that was sampled foundation::Vector3f m_vertex_position; // world space position of the emitting point on the emitter + foundation::Vector3f m_surface_normal; // world space normal of the surface of the emitter foundation::Color3f m_material_value; // BSDF value at the previous vertex foundation::Color3f m_emitted_radiance; // emitted radiance in W.sr^-1.m^-2 }; @@ -157,6 +162,7 @@ class LightPathStream const Entity* m_entity; // object instance or non-physical light foundation::Vector3f m_position; // world space position of this vertex foundation::Color3f m_radiance; // radiance arriving at this vertex, in W.sr^-1.m^-2 + foundation::Vector3f m_surface_normal; }; // Scene. @@ -168,6 +174,7 @@ class LightPathStream foundation::Vector2i m_pixel_coords; foundation::Vector2f m_sample_position; foundation::Vector3f m_camera_vertex_position; + foundation::Vector3f m_camera_vertex_normal; // Scattering events (transient). std::vector m_events; diff --git a/src/appleseed/renderer/kernel/lighting/pt/ptlightingengine.cpp b/src/appleseed/renderer/kernel/lighting/pt/ptlightingengine.cpp index d14766e8ef..b312f60db5 100644 --- a/src/appleseed/renderer/kernel/lighting/pt/ptlightingengine.cpp +++ b/src/appleseed/renderer/kernel/lighting/pt/ptlightingengine.cpp @@ -169,7 +169,8 @@ namespace m_light_path_stream->begin_path( pixel_context, shading_point.get_scene().get_active_camera(), - shading_point.get_ray().m_org); + shading_point.get_ray().m_org, + shading_point.get_ray().m_dir); } if (m_params.m_next_event_estimation) From 2729bde94cdf165f8b897482586288e4ce7b9e9c Mon Sep 17 00:00:00 2001 From: Gray Olson Date: Wed, 10 Jul 2019 15:18:19 -0700 Subject: [PATCH 5/6] implement weighted blended order independent transparency --- src/appleseed.studio/CMakeLists.txt | 2 + src/appleseed.studio/main/main.cpp | 2 +- .../mainwindow/rendering/glscenelayer.cpp | 105 +---------- .../mainwindow/rendering/glscenelayer.h | 9 +- .../mainwindow/rendering/lightpathslayer.cpp | 101 +---------- .../mainwindow/rendering/lightpathslayer.h | 6 +- .../rendering/lightpathsviewportmanager.cpp | 12 +- .../rendering/lightpathsviewportmanager.h | 2 - .../mainwindow/rendering/renderlayer.cpp | 71 +++++++- .../mainwindow/rendering/renderlayer.h | 16 +- .../mainwindow/rendering/viewporttab.cpp | 4 +- .../mainwindow/rendering/viewportwidget.cpp | 169 +++++++++++++++++- .../mainwindow/rendering/viewportwidget.h | 19 +- src/appleseed.studio/resources/resources.qrc | 3 + .../resources/shaders/final_render.frag | 41 +++++ .../resources/shaders/fullscreen_tri.vert | 48 +++++ .../resources/shaders/lightpaths.frag | 20 ++- .../resources/shaders/lightpaths.vert | 2 +- .../resources/shaders/oit_resolve.frag | 52 ++++++ .../resources/shaders/scene.frag | 2 +- .../resources/shaders/scene.vert | 2 +- src/appleseed.studio/utility/gl.cpp | 149 +++++++++++++++ src/appleseed.studio/utility/gl.h | 75 ++++++++ .../utility/miscellaneous.cpp | 10 -- src/appleseed.studio/utility/miscellaneous.h | 3 - 25 files changed, 673 insertions(+), 252 deletions(-) create mode 100644 src/appleseed.studio/resources/shaders/final_render.frag create mode 100644 src/appleseed.studio/resources/shaders/fullscreen_tri.vert create mode 100644 src/appleseed.studio/resources/shaders/oit_resolve.frag create mode 100644 src/appleseed.studio/utility/gl.cpp create mode 100644 src/appleseed.studio/utility/gl.h diff --git a/src/appleseed.studio/CMakeLists.txt b/src/appleseed.studio/CMakeLists.txt index 6073da93eb..38102430c6 100644 --- a/src/appleseed.studio/CMakeLists.txt +++ b/src/appleseed.studio/CMakeLists.txt @@ -365,6 +365,8 @@ set (utility_sources utility/doubleslider.h utility/foldablepanelwidget.cpp utility/foldablepanelwidget.h + utility/gl.cpp + utility/gl.h utility/inputwidgetproxies.cpp utility/inputwidgetproxies.h utility/interop.h diff --git a/src/appleseed.studio/main/main.cpp b/src/appleseed.studio/main/main.cpp index 61cc17f893..af52903c9e 100644 --- a/src/appleseed.studio/main/main.cpp +++ b/src/appleseed.studio/main/main.cpp @@ -329,7 +329,7 @@ int main(int argc, char* argv[]) // Set default surface format before creating application instance. This is // required on macOS in order to use an OpenGL Core profile context. QSurfaceFormat default_format; - default_format.setVersion(3, 3); + default_format.setVersion(4, 1); default_format.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(default_format); diff --git a/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp b/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp index 58ab4e115b..67832c8714 100644 --- a/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp +++ b/src/appleseed.studio/mainwindow/rendering/glscenelayer.cpp @@ -30,7 +30,7 @@ #include "glscenelayer.h" // appleseed.studio headers. -#include "utility/miscellaneous.h" +#include "utility/gl.h" // appleseed.renderer headers. #include "renderer/api/camera.h" @@ -50,7 +50,7 @@ // Qt headers. #include -#include +#include #include #include #include @@ -137,7 +137,12 @@ GLSceneLayer::GLSceneLayer( set_transform(m_camera.transform_sequence().evaluate(time)); } -void GLSceneLayer::set_gl_functions(QOpenGLFunctions_3_3_Core* functions) +GLSceneLayer::~GLSceneLayer() +{ + cleanup_gl_data(); +} + +void GLSceneLayer::set_gl_functions(QOpenGLFunctions_4_1_Core* functions) { m_gl = functions; } @@ -364,100 +369,6 @@ void GLSceneLayer::load_scene_data() load_assembly_instance(assembly_instance, time); } -namespace { - const string shader_kind_to_string(const GLint shader_kind) - { - switch (shader_kind) { - case GL_VERTEX_SHADER: - return "Vertex"; - case GL_FRAGMENT_SHADER: - return "Fragment"; - default: - return "Unknown Kind"; - } - } - - void compile_shader( - QOpenGLFunctions_3_3_Core* f, - const GLuint shader, - const GLsizei count, - const GLchar** src_string, - const GLint* length) - { - f->glShaderSource(shader, count, src_string, length); - f->glCompileShader(shader); - GLint success; - f->glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - - if (!success) - { - char info_log[1024]; - f->glGetShaderInfoLog(shader, 1024, NULL, info_log); - - GLint shader_kind; - f->glGetShaderiv(shader, GL_SHADER_TYPE, &shader_kind); - string shader_kind_string = shader_kind_to_string(shader_kind); - - RENDERER_LOG_ERROR("opengl: %s shader compilation failed:\n%s", shader_kind_string.c_str(), info_log); - } - } - - void link_shader_program( - QOpenGLFunctions_3_3_Core* f, - const GLuint program, - const GLuint vert, - const GLuint frag) - { - f->glAttachShader(program, vert); - - if (frag != 0) - f->glAttachShader(program, frag); - - f->glLinkProgram(program); - - GLint success; - f->glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (!success) - { - char info_log[1024]; - f->glGetProgramInfoLog(program, 1024, NULL, info_log); - RENDERER_LOG_ERROR("opengl: shader program linking failed:\n%s", info_log); - } - } - - void create_shader_program( - QOpenGLFunctions_3_3_Core* f, - GLuint& program, - const QByteArray* vert_source, - const QByteArray* frag_source) - { - bool has_frag_shader = frag_source != nullptr; - - GLuint vert = f->glCreateShader(GL_VERTEX_SHADER); - GLuint frag = has_frag_shader ? f->glCreateShader(GL_FRAGMENT_SHADER) : 0; - - auto gl_vert_source = static_cast(vert_source->constData()); - auto gl_vert_source_length = static_cast(vert_source->size()); - - compile_shader(f, vert, 1, &gl_vert_source, &gl_vert_source_length); - - if (has_frag_shader) - { - auto gl_frag_source = static_cast(frag_source->constData()); - auto gl_frag_source_length = static_cast(frag_source->size()); - compile_shader(f, frag, 1, &gl_frag_source, &gl_frag_source_length); - } - - program = f->glCreateProgram(); - link_shader_program(f, program, vert, frag); - - f->glDeleteShader(vert); - if (has_frag_shader) - f->glDeleteShader(frag); - } -} - void GLSceneLayer::init_gl(QSurfaceFormat format) { // If there was already previous data, clean up diff --git a/src/appleseed.studio/mainwindow/rendering/glscenelayer.h b/src/appleseed.studio/mainwindow/rendering/glscenelayer.h index 6345a7a067..372208a261 100644 --- a/src/appleseed.studio/mainwindow/rendering/glscenelayer.h +++ b/src/appleseed.studio/mainwindow/rendering/glscenelayer.h @@ -58,7 +58,7 @@ namespace renderer { class ObjectInstance; } namespace renderer { class Project; } class QKeyEvent; class QImage; -class QOpenGLFunctions_3_3_Core; +class QOpenGLFunctions_4_1_Core; class QSurfaceFormat; namespace appleseed { @@ -79,6 +79,8 @@ class GLSceneLayer const size_t width, const size_t height); + ~GLSceneLayer(); + void init_gl( QSurfaceFormat format); @@ -86,7 +88,7 @@ class GLSceneLayer const foundation::Transformd& transform); void set_gl_functions( - QOpenGLFunctions_3_3_Core* functions); + QOpenGLFunctions_4_1_Core* functions); void draw(); void draw_depth_only(); @@ -103,7 +105,7 @@ class GLSceneLayer bool m_backface_culling_enabled; - QOpenGLFunctions_3_3_Core* m_gl; + QOpenGLFunctions_4_1_Core* m_gl; std::vector m_scene_object_data_vbos; std::vector m_scene_object_data_index_counts; @@ -125,7 +127,6 @@ class GLSceneLayer bool m_initialized; void render_scene(); - void cleanup_gl_data(); void load_scene_data(); diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp index 50ed9b135f..592f4fb630 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp @@ -30,7 +30,7 @@ #include "lightpathslayer.h" // appleseed.studio headers. -#include "utility/miscellaneous.h" +#include "utility/gl.h" // appleseed.renderer headers. #include "renderer/api/camera.h" @@ -50,7 +50,7 @@ // Qt headers. #include -#include +#include #include #include @@ -105,7 +105,7 @@ void LightPathsLayer::resize(const size_t width, const size_t height) m_height = height; } -void LightPathsLayer::set_gl_functions(QOpenGLFunctions_3_3_Core* functions) +void LightPathsLayer::set_gl_functions(QOpenGLFunctions_4_1_Core* functions) { m_gl = functions; } @@ -341,91 +341,6 @@ void LightPathsLayer::load_light_paths_data() } } -namespace { - const string shader_kind_to_string(const GLint shader_kind) - { - switch (shader_kind) { - case GL_VERTEX_SHADER: - return "Vertex"; - case GL_FRAGMENT_SHADER: - return "Fragment"; - default: - return "Unknown Kind"; - } - } - - void compile_shader( - QOpenGLFunctions_3_3_Core* f, - const GLuint shader, - const GLsizei count, - const GLchar** src_string, - const GLint* length) - { - f->glShaderSource(shader, count, src_string, length); - f->glCompileShader(shader); - GLint success; - f->glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - - if (!success) - { - char info_log[1024]; - f->glGetShaderInfoLog(shader, 1024, NULL, info_log); - - GLint shader_kind; - f->glGetShaderiv(shader, GL_SHADER_TYPE, &shader_kind); - string shader_kind_string = shader_kind_to_string(shader_kind); - - RENDERER_LOG_ERROR("opengl: %s shader compilation failed:\n%s", shader_kind_string.c_str(), info_log); - } - } - - void link_shader_program( - QOpenGLFunctions_3_3_Core* f, - const GLuint program, - const GLuint vert, - const GLuint frag) - { - f->glAttachShader(program, vert); - f->glAttachShader(program, frag); - f->glLinkProgram(program); - - GLint success; - f->glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (!success) - { - char info_log[1024]; - f->glGetProgramInfoLog(program, 1024, NULL, info_log); - RENDERER_LOG_ERROR("opengl: shader program linking failed:\n%s", info_log); - } - } - - void create_shader_program( - QOpenGLFunctions_3_3_Core* f, - GLuint& program, - const QByteArray& vert_source, - const QByteArray& frag_source) - { - GLuint vert = f->glCreateShader(GL_VERTEX_SHADER); - GLuint frag = f->glCreateShader(GL_FRAGMENT_SHADER); - - auto gl_vert_source = static_cast(vert_source.constData()); - auto gl_vert_source_length = static_cast(vert_source.size()); - - auto gl_frag_source = static_cast(frag_source.constData()); - auto gl_frag_source_length = static_cast(frag_source.size()); - - compile_shader(f, vert, 1, &gl_vert_source, &gl_vert_source_length); - compile_shader(f, frag, 1, &gl_frag_source, &gl_frag_source_length); - - program = f->glCreateProgram(); - link_shader_program(f, program, vert, frag); - - f->glDeleteShader(vert); - f->glDeleteShader(frag); - } -} - void LightPathsLayer::init_gl(QSurfaceFormat format) { // If there was already previous data, clean up @@ -441,8 +356,8 @@ void LightPathsLayer::init_gl(QSurfaceFormat format) create_shader_program( m_gl, m_shader_program, - vertex_shader, - fragment_shader); + &vertex_shader, + &fragment_shader); m_view_mat_loc = m_gl->glGetUniformLocation(m_shader_program, "u_view"); m_proj_mat_loc = m_gl->glGetUniformLocation(m_shader_program, "u_proj"); @@ -586,20 +501,14 @@ void LightPathsLayer::draw_render_camera() const { auto gl_view_matrix = const_cast(&m_gl_render_view_matrix[0]); - m_gl->glEnable(GL_BLEND); - m_gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); render_scene(gl_view_matrix); - m_gl->glDisable(GL_BLEND); } void LightPathsLayer::draw() const { auto gl_view_matrix = const_cast(&m_gl_view_matrix[0]); - m_gl->glEnable(GL_BLEND); - m_gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); render_scene(gl_view_matrix); - m_gl->glDisable(GL_BLEND); } void LightPathsLayer::render_scene(const GLfloat* gl_view_matrix) const diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h index 6908a399cd..a3a5d38dc4 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h @@ -58,7 +58,7 @@ namespace renderer { class ObjectInstance; } namespace renderer { class Project; } class QKeyEvent; class QImage; -class QOpenGLFunctions_3_3_Core; +class QOpenGLFunctions_4_1_Core; namespace appleseed { namespace studio { @@ -91,7 +91,7 @@ class LightPathsLayer: public QObject const int selected_light_path_index); void set_gl_functions( - QOpenGLFunctions_3_3_Core* functions); + QOpenGLFunctions_4_1_Core* functions); void init_gl(QSurfaceFormat format); @@ -127,7 +127,7 @@ class LightPathsLayer: public QObject size_t m_width; size_t m_height; - QOpenGLFunctions_3_3_Core* m_gl; + QOpenGLFunctions_4_1_Core* m_gl; GLuint m_positions_vbo; GLuint m_others_vbo; diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp index ab67077b70..d9c6911276 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp @@ -87,7 +87,7 @@ LightPathsViewportManager::LightPathsViewportManager( LightPathsLayer* light_paths_layer = m_viewport_tab->get_viewport_widget()->get_light_paths_layer(); connect( light_paths_layer, SIGNAL(signal_light_path_selection_changed(const int, const int)), - SLOT(slot_light_path_selection_changed)); + SLOT(slot_light_path_selection_changed(const int, const int))); create_toolbar(); @@ -101,6 +101,7 @@ void LightPathsViewportManager::set_enabled(const bool enabled) m_toolbar->show(); else m_toolbar->hide(); + m_toolbar->setDisabled(!enabled); m_screen_space_paths_picking_handler->set_enabled(enabled); } @@ -115,7 +116,6 @@ void LightPathsViewportManager::slot_entity_picked(const ScenePicker::PickingRes if (!m_enabled) return; const CanvasProperties& props = m_project.get_frame()->image().properties(); - m_screen_space_paths_picking_handler->pick( Vector2i( result.m_ndc[0] * static_cast(props.m_canvas_width), @@ -189,14 +189,6 @@ void LightPathsViewportManager::create_toolbar() m_toolbar->setObjectName("render_toolbar"); m_toolbar->setIconSize(QSize(18, 18)); - //// Pick paths button - //QToolButton* m_pick_paths_button = new QToolButton(); - //m_pick_paths_button->setText("Pick Light Paths"); - //m_pick_paths_button->setToolTip("Pick Light Paths"); - //connect( - // m_pick_paths_button, SIGNAL(clicked()), - // SIGNAL(slot_light_paths_pick_button_clicked)); - // Save Light Paths button. QToolButton* save_light_paths_button = new QToolButton(); save_light_paths_button->setIcon(load_icons("lightpathstab_save_light_paths")); diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h index 692b989760..d61746d4d5 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h @@ -98,7 +98,6 @@ class LightPathsViewportManager renderer::ParamArray& m_settings; ViewportTab* m_viewport_tab; QToolBar* m_toolbar; - //QToolButton* m_pick_paths_button; QToolButton* m_prev_path_button; QToolButton* m_next_path_button; QLabel* m_info_label; @@ -110,7 +109,6 @@ class LightPathsViewportManager void create_toolbar(); void recreate_handlers(); - }; } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/renderlayer.cpp b/src/appleseed.studio/mainwindow/rendering/renderlayer.cpp index 6238e5bda3..93fafdd588 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderlayer.cpp +++ b/src/appleseed.studio/mainwindow/rendering/renderlayer.cpp @@ -40,6 +40,7 @@ #include "foundation/image/tile.h" #include "foundation/math/scalar.h" #include "foundation/platform/types.h" +#include "utility/gl.h" // Qt headers. #include @@ -48,6 +49,8 @@ #include #include #include +#include +#include #include #include @@ -74,11 +77,14 @@ RenderLayer::RenderLayer( : QWidget(parent) , m_mutex(QMutex::Recursive) , m_ocio_config(ocio_config) + , m_gl_initialized(false) { setFocusPolicy(Qt::StrongFocus); setAutoFillBackground(false); setAttribute(Qt::WA_OpaquePaintEvent, true); + m_gl_tex = new QOpenGLTexture(QOpenGLTexture::Target2D); + resize(width, height); const char* display_name = m_ocio_config->getDefaultDisplay(); @@ -88,6 +94,64 @@ RenderLayer::RenderLayer( setAcceptDrops(true); } +void RenderLayer::draw(GLuint empty_vao, bool paths_display_active) +{ + QMutexLocker locker(&m_mutex); + + if (m_gl_tex->width() != m_image.width() || m_gl_tex->height() != m_image.height()) + { + if (m_gl_tex->isCreated()) + m_gl_tex->destroy(); + + m_gl_tex->create(); + m_gl_tex->setSize(m_image.width(), m_image.height()); + m_gl_tex->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Nearest); + } + + m_gl_tex->setData(m_image, QOpenGLTexture::MipMapGeneration::DontGenerateMipMaps); + + m_gl->glUseProgram(m_shader_program); + + GLfloat mult = paths_display_active ? 0.6 : 1.0; + m_gl->glUniform1f(m_mult_loc, mult); + + m_gl->glActiveTexture(GL_TEXTURE0); + m_gl_tex->bind(); + m_gl->glDisable(GL_DEPTH_TEST); + m_gl->glDepthMask(GL_FALSE); + m_gl->glBindVertexArray(empty_vao); + m_gl->glDrawArrays(GL_TRIANGLES, 0, 3); + m_gl->glDepthMask(GL_TRUE); +} + + +void RenderLayer::init_gl(QSurfaceFormat format) +{ + if (!m_gl) + { + RENDERER_LOG_ERROR("Attempted to initialize GL without first setting GL functions"); + return; + } + + auto vertex_shader = load_gl_shader("fullscreen_tri.vert"); + auto fragment_shader = load_gl_shader("final_render.frag"); + + create_shader_program( + m_gl, + m_shader_program, + &vertex_shader, + &fragment_shader); + + m_mult_loc = m_gl->glGetUniformLocation(m_shader_program, "u_mult"); + + m_gl_initialized = true; +} + +void RenderLayer::set_gl_functions(QOpenGLFunctions_4_1_Core* functions) +{ + m_gl = functions; +} + QImage RenderLayer::capture() { QMutexLocker locker(&m_mutex); @@ -425,12 +489,5 @@ void RenderLayer::update_tile_no_lock(const size_t tile_x, const size_t tile_y) NativeDrawing::blit(dest, dest_stride, uint8_rgb_tile); } -void RenderLayer::paint(const QRect& rect, QPainter& painter) -{ - QMutexLocker locker(&m_mutex); - - painter.drawImage(rect, m_image); -} - } // namespace studio } // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/renderlayer.h b/src/appleseed.studio/mainwindow/rendering/renderlayer.h index f2920c334d..c6af7778f9 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderlayer.h +++ b/src/appleseed.studio/mainwindow/rendering/renderlayer.h @@ -44,6 +44,7 @@ namespace OCIO = OCIO_NAMESPACE; // Qt headers. #include #include +#include #include #include @@ -58,6 +59,8 @@ namespace renderer { class Frame; } class QDragEnterEvent; class QDragMoveEvent; class QDropEvent; +class QOpenGLFunctions_4_1_Core; +class QOpenGLTexture; class QPaintEvent; class QRect; @@ -117,8 +120,10 @@ class RenderLayer // Thread-safe. void blit_frame(const renderer::Frame& frame); - // Thread-safe. Paint self into specified painter. - void paint(const QRect& rect, QPainter& painter); + void draw(GLuint empty_vao, bool paths_display_active); + void init_gl(QSurfaceFormat format); + void set_gl_functions( + QOpenGLFunctions_4_1_Core* functions); // Direct access to internals for high-performance drawing. QMutex& mutex(); @@ -135,11 +140,16 @@ class RenderLayer private: mutable QMutex m_mutex; QImage m_image; - QPainter m_painter; std::unique_ptr m_float_tile_storage; std::unique_ptr m_uint8_tile_storage; std::unique_ptr m_image_storage; + QOpenGLFunctions_4_1_Core* m_gl; + QOpenGLTexture* m_gl_tex; + GLuint m_shader_program; + GLint m_mult_loc; + bool m_gl_initialized; + OCIO::ConstConfigRcPtr m_ocio_config; OCIO::ConstProcessorRcPtr m_ocio_processor; diff --git a/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp b/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp index 37ff7f796c..b91d1a935b 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp @@ -132,8 +132,8 @@ void ViewportTab::set_render_region_buttons_enabled(const bool enabled) void ViewportTab::render_began() { - get_viewport_widget()->get_render_layer()->darken(); - get_viewport_widget()->get_light_paths_layer()->update_render_camera_transform(); + m_viewport_widget->get_render_layer()->darken(); + m_viewport_widget->get_light_paths_layer()->update_render_camera_transform(); set_light_paths_enabled(false); update(); } diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp index 9ca818212c..01b69c4425 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp @@ -29,6 +29,9 @@ // Interface header. #include "viewportwidget.h" +// appleseed.studio headers. +#include "utility/gl.h" + // appleseed.renderer headers. #include "renderer/api/frame.h" @@ -47,7 +50,8 @@ #include #include #include -#include +#include +#include #include #include @@ -76,6 +80,12 @@ ViewportWidget::ViewportWidget( , m_project(project) , m_draw_light_paths(false) , m_active_base_layer(static_cast(0)) + , m_resolve_program(0) + , m_accum_loc(0) + , m_accum_tex(0) + , m_revealage_loc(0) + , m_revealage_tex(0) + , m_accum_revealage_fb(0) { setFocusPolicy(Qt::StrongFocus); setFixedWidth(static_cast(width)); @@ -92,6 +102,17 @@ ViewportWidget::ViewportWidget( setAcceptDrops(true); } +ViewportWidget::~ViewportWidget() +{ + m_gl->glDeleteProgram(m_resolve_program); + m_gl->glDeleteTextures(1, &m_accum_tex); + m_gl->glDeleteTextures(1, &m_revealage_tex); + m_gl->glDeleteTextures(1, &m_color_tex); + m_gl->glDeleteTextures(1, &m_depth_tex); + m_gl->glDeleteFramebuffers(1, &m_accum_revealage_fb); + m_gl->glDeleteFramebuffers(1, &m_main_fb); +} + QString ViewportWidget::base_layer_string(BaseLayer layer) { switch (layer) @@ -153,7 +174,7 @@ QImage ViewportWidget::capture() void ViewportWidget::initializeGL() { RENDERER_LOG_INFO("initializing opengl."); - m_gl = QOpenGLContext::currentContext()->versionFunctions(); + m_gl = QOpenGLContext::currentContext()->versionFunctions(); const auto qs_format = format(); if (!m_gl->initializeOpenGLFunctions()) @@ -167,6 +188,60 @@ void ViewportWidget::initializeGL() { return; } + m_gl->glGenVertexArrays(1, &m_empty_vao); + m_gl->glBindVertexArray(m_empty_vao); + m_gl->glGenBuffers(1, &m_empty_vbo); + m_gl->glBindBuffer(GL_ARRAY_BUFFER, m_empty_vbo); + float vals[3]{ 0.0f, 0.0f, 0.0f }; + m_gl->glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3, static_cast(vals), GL_STATIC_DRAW); + m_gl->glVertexAttribPointer(0, sizeof(float), GL_FLOAT, GL_FALSE, sizeof(float), static_cast(0)); + m_gl->glEnableVertexAttribArray(0); + + auto vertex_shader = load_gl_shader("fullscreen_tri.vert"); + auto fragment_shader = load_gl_shader("oit_resolve.frag"); + + create_shader_program( + m_gl, + m_resolve_program, + &vertex_shader, + &fragment_shader); + + m_accum_loc = m_gl->glGetUniformLocation(m_resolve_program, "u_accum_tex"); + m_revealage_loc = m_gl->glGetUniformLocation(m_resolve_program, "u_revealage_tex"); + + GLuint temp_fbs[2]; + m_gl->glGenFramebuffers(2, temp_fbs); + + m_main_fb = temp_fbs[0]; + m_accum_revealage_fb = temp_fbs[1]; + + GLuint temp_texs[4]; + m_gl->glGenTextures(4, temp_texs); + + m_color_tex = temp_texs[0]; + m_depth_tex = temp_texs[1]; + m_accum_tex = temp_texs[2]; + m_revealage_tex = temp_texs[3]; + + resizeGL(width(), height()); + + m_gl->glBindFramebuffer(GL_FRAMEBUFFER, m_main_fb); + m_gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_color_tex, 0); + m_gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_depth_tex, 0); + + m_gl->glBindFramebuffer(GL_FRAMEBUFFER, m_accum_revealage_fb); + m_gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_accum_tex, 0); + m_gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, m_revealage_tex, 0); + m_gl->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_depth_tex, 0); + + m_gl->glBindFramebuffer(GL_FRAMEBUFFER, 0); + + m_gl->glUseProgram(m_resolve_program); + m_gl->glUniform1i(m_accum_loc, 0); + m_gl->glUniform1i(m_revealage_loc, 1); + + m_render_layer->set_gl_functions(m_gl); + m_render_layer->init_gl(qs_format); m_gl_scene_layer->set_gl_functions(m_gl); m_gl_scene_layer->init_gl(qs_format); m_light_paths_layer->set_gl_functions(m_gl); @@ -186,6 +261,28 @@ void ViewportWidget::resizeGL( int height) { m_light_paths_layer->resize(width, height); + + m_gl->glBindTexture(GL_TEXTURE_2D, m_color_tex); + m_gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + m_gl->glBindTexture(GL_TEXTURE_2D, m_depth_tex); + m_gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL); + m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + m_gl->glBindTexture(GL_TEXTURE_2D, m_accum_tex); + m_gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_HALF_FLOAT, NULL); + m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + m_gl->glBindTexture(GL_TEXTURE_2D, m_revealage_tex); + m_gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, width, height, 0, GL_RED, GL_HALF_FLOAT, NULL); + m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + m_gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + m_gl->glBindTexture(GL_TEXTURE_2D, 0); } void ViewportWidget::set_draw_light_paths_enabled(const bool enabled) @@ -196,14 +293,25 @@ void ViewportWidget::set_draw_light_paths_enabled(const bool enabled) void ViewportWidget::paintGL() { + + double dpr = static_cast(m_render_layer->image().devicePixelRatio()); + GLsizei w = static_cast(width() * dpr); + GLsizei h = static_cast(height() * dpr); + m_gl->glViewport(0, 0, w, h); + + m_gl->glBindFramebuffer(GL_FRAMEBUFFER, m_main_fb); + // Clear the main framebuffers + GLfloat main_clear[]{ 0.0, 0.0, 0.0, 0.0 }; + m_gl->glClearBufferfv(GL_COLOR, 0, main_clear); + GLfloat depth_clear = 1.0; + m_gl->glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0, 0); + if (m_active_base_layer == BaseLayer::FinalRender) { - m_painter.begin(this); - m_render_layer->paint(rect(), m_painter); - m_painter.end(); + m_render_layer->draw(m_empty_vao, m_draw_light_paths); } - m_gl->glViewport(0, 0, width(), height()); + QOpenGLContext *ctx = const_cast(QOpenGLContext::currentContext()); if (m_active_base_layer == BaseLayer::OpenGL || m_draw_light_paths) m_gl_scene_layer->draw_depth_only(); @@ -213,11 +321,60 @@ void ViewportWidget::paintGL() if (m_draw_light_paths) { + // Bind accum/revealage framebuffer + m_gl->glBindFramebuffer(GL_FRAMEBUFFER, m_accum_revealage_fb); + + // Set both attachments as active draw buffers + const GLenum buffers[]{ GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; + m_gl->glDrawBuffers(2, buffers); + + // Clear the buffers + GLfloat accum_clear_col[]{ 0.0, 0.0, 0.0, 0.0 }; + m_gl->glClearBufferfv(GL_COLOR, 0, accum_clear_col); + GLfloat revealage_clear_col[]{ 1.0, 0.0, 0.0, 0.0 }; + m_gl->glClearBufferfv(GL_COLOR, 1, revealage_clear_col); + + // Enable proper blending for each + m_gl->glEnable(GL_BLEND); + m_gl->glBlendFunci(0, GL_ONE, GL_ONE); + m_gl->glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + m_gl->glEnable(GL_DEPTH_TEST); + m_gl->glDepthMask(GL_FALSE); + if (m_active_base_layer == BaseLayer::FinalRender) m_light_paths_layer->draw_render_camera(); else m_light_paths_layer->draw(); + + m_gl->glUseProgram(m_resolve_program); + + // Set default framebuffer object + m_gl->glBindFramebuffer(GL_FRAMEBUFFER, m_main_fb); + m_gl->glDrawBuffer(GL_COLOR_ATTACHMENT0); + + m_gl->glBindVertexArray(m_empty_vao); + + m_gl->glActiveTexture(GL_TEXTURE0); + m_gl->glBindTexture(GL_TEXTURE_2D, m_accum_tex); + m_gl->glActiveTexture(GL_TEXTURE1); + m_gl->glBindTexture(GL_TEXTURE_2D, m_revealage_tex); + + m_gl->glDisable(GL_DEPTH_TEST); + m_gl->glDepthMask(GL_FALSE); + m_gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + m_gl->glDrawArrays(GL_TRIANGLES, 0, 3); + + m_gl->glActiveTexture(GL_TEXTURE1); + m_gl->glBindTexture(GL_TEXTURE_2D, 0); + m_gl->glActiveTexture(GL_TEXTURE0); + m_gl->glBindTexture(GL_TEXTURE_2D, 0); + m_gl->glDepthMask(GL_TRUE); } + + m_gl->glBindFramebuffer(GL_READ_FRAMEBUFFER, m_main_fb); + m_gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->defaultFramebufferObject()); + m_gl->glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); } void ViewportWidget::dragEnterEvent(QDragEnterEvent* event) diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h index 43568b2f76..94f02aef89 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.h @@ -63,7 +63,7 @@ class QDragEnterEvent; class QDragMoveEvent; class QDropEvent; class QPaintEvent; -class QOpenGLFunctions_3_3_Core; +class QOpenGLFunctions_4_1_Core; namespace appleseed { namespace studio { @@ -87,6 +87,8 @@ class ViewportWidget OCIO::ConstConfigRcPtr ocio_config, QWidget* parent = nullptr); + ~ViewportWidget(); + enum BaseLayer { FinalRender, OpenGL, @@ -123,9 +125,22 @@ class ViewportWidget int m_width; int m_height; - QOpenGLFunctions_3_3_Core* m_gl; + QOpenGLFunctions_4_1_Core* m_gl; QPainter m_painter; + GLuint m_depth_tex; + GLuint m_color_tex; + GLuint m_accum_tex; + GLuint m_revealage_tex; + GLuint m_main_fb; + GLuint m_accum_revealage_fb; + GLuint m_empty_vao; + GLuint m_empty_vbo; + + GLuint m_resolve_program; + GLint m_accum_loc; + GLint m_revealage_loc; + std::unique_ptr m_render_layer; std::unique_ptr m_gl_scene_layer; std::unique_ptr m_light_paths_layer; diff --git a/src/appleseed.studio/resources/resources.qrc b/src/appleseed.studio/resources/resources.qrc index a55b80d91f..d4833e1d22 100644 --- a/src/appleseed.studio/resources/resources.qrc +++ b/src/appleseed.studio/resources/resources.qrc @@ -1,8 +1,11 @@ images/appleseed-logo-256.png + shaders/final_render.frag + shaders/fullscreen_tri.vert shaders/lightpaths.frag shaders/lightpaths.vert + shaders/oit_resolve.frag shaders/scene.frag shaders/scene.vert widgets/checkbox_checked_disabled.png diff --git a/src/appleseed.studio/resources/shaders/final_render.frag b/src/appleseed.studio/resources/shaders/final_render.frag new file mode 100644 index 0000000000..6f9eadf6d7 --- /dev/null +++ b/src/appleseed.studio/resources/shaders/final_render.frag @@ -0,0 +1,41 @@ +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2019 Gray Olson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#version 410 + +in vec2 f_uv; + +uniform sampler2D u_render_tex; +uniform float u_mult; + +out vec4 Target0; + +void main() { + vec3 col = texture(u_render_tex, f_uv, 0).rgb; + + Target0 = vec4(col * u_mult, 1.0); +} diff --git a/src/appleseed.studio/resources/shaders/fullscreen_tri.vert b/src/appleseed.studio/resources/shaders/fullscreen_tri.vert new file mode 100644 index 0000000000..7dbb4b2100 --- /dev/null +++ b/src/appleseed.studio/resources/shaders/fullscreen_tri.vert @@ -0,0 +1,48 @@ +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2019 Gray Olson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#version 410 + +const vec2 verts[3] = vec2[]( + vec2(3.0, 1.0), + vec2(-1.0, -3.0), + vec2(-1.0, 1.0) +); + +const vec2 uvs[3] = vec2[]( + vec2(2.0, 0.0), + vec2(0.0, 2.0), + vec2(0.0, 0.0) +); + +out vec2 f_uv; + +void main() +{ + f_uv = uvs[gl_VertexID]; + gl_Position = vec4(verts[gl_VertexID], 0.0, 1.0); +} \ No newline at end of file diff --git a/src/appleseed.studio/resources/shaders/lightpaths.frag b/src/appleseed.studio/resources/shaders/lightpaths.frag index 01d3191617..ea8d3dc0ee 100644 --- a/src/appleseed.studio/resources/shaders/lightpaths.frag +++ b/src/appleseed.studio/resources/shaders/lightpaths.frag @@ -25,7 +25,7 @@ // THE SOFTWARE. // -#version 330 +#version 410 #extension GL_ARB_separate_shader_objects : enable flat in vec3 f_color; @@ -36,12 +36,26 @@ flat in float f_aspect_expansion_len; uniform vec2 u_res; -out vec4 Target0; +layout(location = 0) out vec4 accum_target; +layout(location = 1) out float revealage_target; +void write_pixel(vec4 premultiplied_col, vec3 transmit) { + // premultiplied_col.a *= 1.0 - clamp((transmit.r + transmit.g + transmit.b) * (1.0 / 3.0), 0, 1); + + float a = min(1.0, premultiplied_col.a) * 8.0 + 0.01; + float b = -gl_FragCoord.z * 0.95 + 1.0; + + float w = clamp(a * a * a * 1e8 * b * b * b, 1e-2, 3e2); + + accum_target = premultiplied_col * w; + revealage_target = premultiplied_col.a; +} void main() { float dist = abs(f_aa_norm) * f_total_thickness - 0.5 / f_aspect_expansion_len; float eps = fwidth(dist); float a = 1.0 - smoothstep(f_thickness - eps, f_thickness + eps, dist); - Target0 = vec4(f_color, a); + + vec4 premult = vec4(f_color * a, a); + write_pixel(premult, vec3(1.0)); } diff --git a/src/appleseed.studio/resources/shaders/lightpaths.vert b/src/appleseed.studio/resources/shaders/lightpaths.vert index 579c386a39..35a409ae54 100644 --- a/src/appleseed.studio/resources/shaders/lightpaths.vert +++ b/src/appleseed.studio/resources/shaders/lightpaths.vert @@ -25,7 +25,7 @@ // THE SOFTWARE. // -#version 330 +#version 410 const float AA_BUFFER_SIZE = 1.0; diff --git a/src/appleseed.studio/resources/shaders/oit_resolve.frag b/src/appleseed.studio/resources/shaders/oit_resolve.frag new file mode 100644 index 0000000000..3a091797f8 --- /dev/null +++ b/src/appleseed.studio/resources/shaders/oit_resolve.frag @@ -0,0 +1,52 @@ +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2019 Gray Olson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#version 410 + +uniform sampler2D u_accum_tex; +uniform sampler2D u_revealage_tex; + +out vec4 Target0; + +float max4(vec4 v) { + return max(max(max(v.x, v.y), v.z), v.w); +} + +void main() { + ivec2 coord = ivec2(gl_FragCoord.xy); + + float revealage = texelFetch(u_revealage_tex, coord, 0).r; + + vec4 accum = texelFetch(u_accum_tex, coord, 0); + // Suppress overflow + if (isinf(max4(abs(accum)))) { + accum.rgb = vec3(accum.a); + } + vec3 averageColor = accum.rgb / max(accum.a, 0.00001); + + Target0 = vec4(averageColor, 1.0 - revealage); +} diff --git a/src/appleseed.studio/resources/shaders/scene.frag b/src/appleseed.studio/resources/shaders/scene.frag index 2dc350f5d2..d58363f361 100644 --- a/src/appleseed.studio/resources/shaders/scene.frag +++ b/src/appleseed.studio/resources/shaders/scene.frag @@ -25,7 +25,7 @@ // THE SOFTWARE. // -#version 330 +#version 410 #extension GL_ARB_separate_shader_objects : enable layout(location = 0) in vec3 v_world_pos; diff --git a/src/appleseed.studio/resources/shaders/scene.vert b/src/appleseed.studio/resources/shaders/scene.vert index 18f61388f8..a1bdde9adc 100644 --- a/src/appleseed.studio/resources/shaders/scene.vert +++ b/src/appleseed.studio/resources/shaders/scene.vert @@ -25,7 +25,7 @@ // THE SOFTWARE. // -#version 330 +#version 410 #extension GL_ARB_separate_shader_objects : enable layout(location = 0) in vec3 a_pos; diff --git a/src/appleseed.studio/utility/gl.cpp b/src/appleseed.studio/utility/gl.cpp new file mode 100644 index 0000000000..3ed09c6725 --- /dev/null +++ b/src/appleseed.studio/utility/gl.cpp @@ -0,0 +1,149 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2019 Gray Olson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#include "gl.h" + +// appleseed.studio headers. +#include "renderer/api/utility.h" +#include "utility/miscellaneous.h" + +// Qt headers. +#include +#include +#include + +using namespace std; +using namespace renderer; + +namespace appleseed { +namespace studio { + +const string shader_kind_to_string(const GLint shader_kind) +{ + switch (shader_kind) { + case GL_VERTEX_SHADER: + return "Vertex"; + case GL_FRAGMENT_SHADER: + return "Fragment"; + } + return "Unknown Kind"; +} + +void compile_shader( + QOpenGLFunctions_4_1_Core* f, + const GLuint shader, + const GLsizei count, + const GLchar** src_string, + const GLint* length) +{ + f->glShaderSource(shader, count, src_string, length); + f->glCompileShader(shader); + GLint success; + f->glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + + if (!success) + { + char info_log[1024]; + f->glGetShaderInfoLog(shader, 1024, NULL, info_log); + + GLint shader_kind; + f->glGetShaderiv(shader, GL_SHADER_TYPE, &shader_kind); + string shader_kind_string = shader_kind_to_string(shader_kind); + + RENDERER_LOG_ERROR("opengl: %s shader compilation failed:\n%s", shader_kind_string.c_str(), info_log); + } +} + +void link_shader_program( + QOpenGLFunctions_4_1_Core* f, + const GLuint program, + const GLuint vert, + const GLuint frag) +{ + f->glAttachShader(program, vert); + + if (frag != 0) + f->glAttachShader(program, frag); + + f->glLinkProgram(program); + + GLint success; + f->glGetProgramiv(program, GL_LINK_STATUS, &success); + + if (!success) + { + char info_log[1024]; + f->glGetProgramInfoLog(program, 1024, NULL, info_log); + RENDERER_LOG_ERROR("opengl: shader program linking failed:\n%s", info_log); + } +} + +void create_shader_program( + QOpenGLFunctions_4_1_Core* f, + GLuint& program, + const QByteArray* vert_source, + const QByteArray* frag_source) +{ + assert(vert_source != nullptr); + bool has_frag_shader = frag_source != nullptr; + + GLuint vert = f->glCreateShader(GL_VERTEX_SHADER); + GLuint frag = has_frag_shader ? f->glCreateShader(GL_FRAGMENT_SHADER) : 0; + + auto gl_vert_source = static_cast(vert_source->constData()); + auto gl_vert_source_length = static_cast(vert_source->size()); + + compile_shader(f, vert, 1, &gl_vert_source, &gl_vert_source_length); + + if (has_frag_shader) + { + auto gl_frag_source = static_cast(frag_source->constData()); + auto gl_frag_source_length = static_cast(frag_source->size()); + compile_shader(f, frag, 1, &gl_frag_source, &gl_frag_source_length); + } + + program = f->glCreateProgram(); + link_shader_program(f, program, vert, frag); + + f->glDeleteShader(vert); + if (has_frag_shader) + f->glDeleteShader(frag); +} + +QByteArray load_gl_shader(const QString& base_name) +{ + const QString resource_path(QString(":/shaders/%1").arg(base_name)); + + QFile file(resource_path); + file.open(QFile::ReadOnly); + + return file.readAll(); +} + +} // namespace studio +} // namespace appleseed diff --git a/src/appleseed.studio/utility/gl.h b/src/appleseed.studio/utility/gl.h new file mode 100644 index 0000000000..b63b4c583c --- /dev/null +++ b/src/appleseed.studio/utility/gl.h @@ -0,0 +1,75 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2019 Gray Olson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#pragma once + +// Qt headers. +#include +#include + +// standard headers. +#include + +// Forward declarations. +class QByteArray; +class QString; + +namespace appleseed { +namespace studio { + +// Get a string from an OpenGL shader kind value. +const std::string shader_kind_to_string(const GLint shader_kind); + +// Compile a GL shader. +void compile_shader( + QOpenGLFunctions_4_1_Core* f, + const GLuint shader, + const GLsizei count, + const GLchar** src_string, + const GLint* length); + +// Link a GL shader program. +void link_shader_program( + QOpenGLFunctions_4_1_Core* f, + const GLuint program, + const GLuint vert, + const GLuint frag); + +// Create a GL shader program with a vertex and optional fragment shader. +void create_shader_program( + QOpenGLFunctions_4_1_Core* f, + GLuint& program, + const QByteArray* vert_source, + const QByteArray* frag_source); + +// Load a GLSL shader from file into a QByteArray. +QByteArray load_gl_shader(const QString& base_name); + +} // namespace studio +} // namespace appleseed + diff --git a/src/appleseed.studio/utility/miscellaneous.cpp b/src/appleseed.studio/utility/miscellaneous.cpp index af29d1b525..f26be7f75b 100644 --- a/src/appleseed.studio/utility/miscellaneous.cpp +++ b/src/appleseed.studio/utility/miscellaneous.cpp @@ -197,16 +197,6 @@ bool file_exists(const QString& path) return info.exists() && info.isFile(); } -QByteArray load_gl_shader(const QString& base_name) -{ - const QString resource_path(QString(":/shaders/%1").arg(base_name)); - - QFile file(resource_path); - file.open(QFile::ReadOnly); - - return file.readAll(); -} - QIcon load_icons(const QString& base_name) { const QString base_icon_filepath(make_app_path("icons/%1.png").arg(base_name)); diff --git a/src/appleseed.studio/utility/miscellaneous.h b/src/appleseed.studio/utility/miscellaneous.h index 2558cb9c13..361eadafef 100644 --- a/src/appleseed.studio/utility/miscellaneous.h +++ b/src/appleseed.studio/utility/miscellaneous.h @@ -80,9 +80,6 @@ QString combine_name_and_shortcut(const QString& name, const QKeySequence& short // Check whether a file exists. bool file_exists(const QString& path); -// Load a GLSL shader from file into a QByteArray. -QByteArray load_gl_shader(const QString& base_name); - // Load an icon and its variants (hover, disabled...) from the application's icons directory. QIcon load_icons(const QString& base_name); From 0d9dc7fb59c2e89dbc6186ff52f700ae2d26467b Mon Sep 17 00:00:00 2001 From: Gray Olson Date: Fri, 9 Aug 2019 17:45:34 -0700 Subject: [PATCH 6/6] fix light paths always being drawn with depth test enabled --- .../mainwindow/rendering/lightpathslayer.cpp | 14 -------------- .../mainwindow/rendering/lightpathslayer.h | 3 --- .../mainwindow/rendering/viewportwidget.cpp | 1 - 3 files changed, 18 deletions(-) diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp index 592f4fb630..75dd01ee52 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp @@ -85,7 +85,6 @@ LightPathsLayer::LightPathsLayer( const size_t height) : m_project(project) , m_camera(*m_project.get_uncached_active_camera()) - , m_backface_culling_enabled(false) , m_selected_light_path_index(-1) , m_gl_initialized(false) , m_width(width) @@ -182,11 +181,6 @@ void LightPathsLayer::slot_display_next_light_path() set_selected_light_path_index(m_selected_light_path_index + 1); } -void LightPathsLayer::slot_toggle_backface_culling(const bool checked) -{ - m_backface_culling_enabled = checked; -} - void LightPathsLayer::slot_synchronize_camera() { m_camera.transform_sequence().clear(); @@ -516,14 +510,6 @@ void LightPathsLayer::render_scene(const GLfloat* gl_view_matrix) const if (!m_gl_initialized) return; - if (m_backface_culling_enabled) - m_gl->glEnable(GL_CULL_FACE); - else m_gl->glDisable(GL_CULL_FACE); - - m_gl->glDepthMask(GL_TRUE); - m_gl->glEnable(GL_DEPTH_TEST); - m_gl->glDepthFunc(GL_LEQUAL); - if (m_index_offsets.size() > 1) { m_gl->glUseProgram(m_shader_program); diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h index a3a5d38dc4..a7264fefce 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h @@ -108,7 +108,6 @@ class LightPathsLayer: public QObject void slot_display_all_light_paths(); void slot_display_previous_light_path(); void slot_display_next_light_path(); - void slot_toggle_backface_culling(const bool checked); void slot_synchronize_camera(); private: @@ -117,8 +116,6 @@ class LightPathsLayer: public QObject foundation::Matrix4d m_camera_matrix; foundation::Matrix4d m_render_camera_matrix; - bool m_backface_culling_enabled; - renderer::LightPathArray m_light_paths; int m_selected_light_path_index; // -1 == display all paths float m_max_luminance; diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp index 01b69c4425..d852b894e0 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp @@ -303,7 +303,6 @@ void ViewportWidget::paintGL() // Clear the main framebuffers GLfloat main_clear[]{ 0.0, 0.0, 0.0, 0.0 }; m_gl->glClearBufferfv(GL_COLOR, 0, main_clear); - GLfloat depth_clear = 1.0; m_gl->glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0, 0); if (m_active_base_layer == BaseLayer::FinalRender)