├── .clang-format ├── .gitignore ├── .gitmodules ├── .idea ├── .gitignore ├── .name ├── codeStyles │ └── codeStyleConfig.xml ├── misc.xml ├── modules.xml ├── texture_map_optimization.iml └── vcs.xml ├── CMakeLists.txt ├── Contrib └── CMakeLists.txt ├── Optimization ├── CMakeLists.txt ├── Cost.h ├── KeyFrame.cpp ├── KeyFrame.h ├── Optimization.cpp ├── Optimization.h ├── RenderPass.cpp └── RenderPass.h ├── README.md ├── ScopedTimer ├── CMakeLists.txt ├── ScopedTimer.cpp └── ScopedTimer.h ├── Shaders ├── CMakeLists.txt ├── Combine.comp ├── Combine.cpp ├── Combine.h ├── DepthFilter.comp ├── DepthFilter.cpp ├── DepthFilter.h ├── Diff.cpp ├── Diff.frag ├── Diff.h ├── Diff.vert ├── FullScreenTriangle.cpp ├── FullScreenTriangle.frag ├── FullScreenTriangle.h ├── FullScreenTriangle.vert ├── Reduction.comp ├── Reduction.cpp ├── Reduction.h ├── Remap.comp ├── Remap.cpp ├── Remap.h ├── TextureCoordinates.cpp ├── TextureCoordinates.frag ├── TextureCoordinates.h ├── TextureCoordinates.vert ├── Vis.comp ├── Vis.cpp ├── Vis.h ├── generic.glsl └── resources.conf ├── Utilities ├── Allocate.h ├── CMakeLists.txt ├── RemoveIf.h ├── Types.h ├── UniqueFunction.h └── Utilities.h ├── Viewer ├── ArcBall.cpp ├── ArcBall.h ├── CMakeLists.txt ├── IO.cpp ├── IO.h ├── SourceSansPro-Regular.ttf ├── Viewer.cpp ├── Viewer.h └── resources.conf ├── assets └── fountain_small │ ├── .DS_Store │ ├── image │ ├── .DS_Store │ ├── 0000010-000001228920.jpg │ ├── 0000031-000004096400.jpg │ ├── 0000044-000005871507.jpg │ ├── 0000064-000008602440.jpg │ ├── 0000110-000014883587.jpg │ ├── 0000156-000021164733.jpg │ ├── 0000200-000027172787.jpg │ ├── 0000215-000029220987.jpg │ ├── 0000255-000034682853.jpg │ ├── 0000299-000040690907.jpg │ ├── 0000331-000045060400.jpg │ ├── 0000368-000050112627.jpg │ ├── 0000412-000056120680.jpg │ ├── 0000429-000058441973.jpg │ ├── 0000474-000064586573.jpg │ ├── 0000487-000066361680.jpg │ ├── 0000526-000071687000.jpg │ ├── 0000549-000074827573.jpg │ ├── 0000582-000079333613.jpg │ ├── 0000630-000085887853.jpg │ ├── 0000655-000089301520.jpg │ ├── 0000703-000095855760.jpg │ ├── 0000722-000098450147.jpg │ ├── 0000771-000105140933.jpg │ ├── 0000792-000108008413.jpg │ ├── 0000818-000111558627.jpg │ ├── 0000849-000115791573.jpg │ ├── 0000883-000120434160.jpg │ ├── 0000896-000122209267.jpg │ ├── 0000935-000127534587.jpg │ ├── 0000985-000134361920.jpg │ ├── 0001028-000140233427.jpg │ └── 0001061-000144739467.jpg │ └── scene │ ├── .DS_Store │ ├── key.log │ └── mesh.ply ├── main.cpp ├── modules ├── FindAssimp.cmake └── FindGLFW.cmake ├── render.png └── texture.png /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignOperands: true 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: Always 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: Always 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 0 37 | CompactNamespaces: true 38 | ContinuationIndentWidth: 8 39 | IndentCaseLabels: true 40 | IndentPPDirectives: None 41 | IndentWidth: 4 42 | KeepEmptyLinesAtTheStartOfBlocks: true 43 | MaxEmptyLinesToKeep: 2 44 | NamespaceIndentation: None 45 | ObjCSpaceAfterProperty: false 46 | ObjCSpaceBeforeProtocolList: true 47 | PointerAlignment: Right 48 | ReflowComments: false 49 | SpaceAfterCStyleCast: true 50 | SpaceAfterLogicalNot: false 51 | SpaceAfterTemplateKeyword: false 52 | SpaceBeforeAssignmentOperators: true 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: Never 57 | SpaceBeforeRangeBasedForLoopColon: true 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 0 60 | SpacesInAngles: false 61 | SpacesInCStyleCastParentheses: false 62 | SpacesInContainerLiterals: false 63 | SpacesInParentheses: false 64 | SpacesInSquareBrackets: false 65 | TabWidth: 4 66 | UseTab: Never 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /cmake* 2 | /build 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Contrib/imgui"] 2 | path = Contrib/imgui 3 | url = https://github.com/Janos95/imgui 4 | branch = docking 5 | [submodule "Contrib/magnum-integration"] 6 | path = Contrib/magnum-integration 7 | url = https://github.com/mosra/magnum-integration.git 8 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | TextureOptimization -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/texture_map_optimization.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(TextureOptimization LANGUAGES CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 20) 5 | 6 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/modules) 7 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 8 | 9 | find_package(Corrade REQUIRED PluginManager Containers TestSuite Utility) 10 | find_package(Magnum REQUIRED GL MeshTools GlfwApplication Shaders Primitives DebugTools) 11 | find_package(Ceres) 12 | find_package(MagnumPlugins REQUIRED AssimpImporter) 13 | 14 | add_subdirectory(Contrib) 15 | add_subdirectory(ScopedTimer) 16 | add_subdirectory(Shaders) 17 | add_subdirectory(Viewer) 18 | add_subdirectory(Optimization) 19 | add_subdirectory(Utilities) 20 | 21 | add_executable(App main.cpp) 22 | 23 | target_link_libraries(App PUBLIC Magnum::Magnum Tmo::Viewer Tmo::Optimization) -------------------------------------------------------------------------------- /Contrib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(IMGUI_SOURCES 2 | imgui/imconfig.h 3 | imgui/imgui.cpp 4 | imgui/imgui.h 5 | imgui/imgui_demo.cpp 6 | imgui/imgui_draw.cpp 7 | imgui/imgui_internal.h 8 | imgui/imgui_widgets.cpp 9 | imgui/imstb_rectpack.h 10 | imgui/imstb_textedit.h 11 | imgui/imstb_truetype.h) 12 | 13 | add_library(imgui SHARED ${IMGUI_SOURCES}) 14 | target_include_directories(imgui SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui) 15 | target_compile_options(imgui PRIVATE -w) 16 | target_include_directories(imgui PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui ${CORRADE_INCLUDE_DIR}) 17 | add_library(ImGui::ImGui ALIAS imgui) 18 | 19 | add_library(ImGui::Sources INTERFACE IMPORTED) 20 | set_property(TARGET ImGui::Sources APPEND PROPERTY 21 | INTERFACE_LINK_LIBRARIES ImGui::ImGui) 22 | 23 | set(IMGUI_DIR "${CMAKE_CURRENT_SOURCE_DIR}/imgui" CACHE "" INTERNAL) 24 | set(WITH_IMGUI ON CACHE "" INTERNAL) 25 | 26 | add_subdirectory(magnum-integration) 27 | 28 | -------------------------------------------------------------------------------- /Optimization/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(Optimization 2 | Cost.h 3 | Optimization.h 4 | Optimization.cpp 5 | KeyFrame.h 6 | KeyFrame.cpp 7 | RenderPass.h 8 | RenderPass.cpp 9 | ) 10 | 11 | target_include_directories(Optimization INTERFACE ${CMAKE_CURRENT_LIST_DIR}) 12 | target_link_libraries(Optimization 13 | PUBLIC 14 | Magnum::Magnum 15 | Magnum::GL 16 | Tmo::Utilities 17 | Ceres::ceres 18 | PRIVATE 19 | Tmo::Shaders 20 | ) 21 | 22 | add_library(Tmo::Optimization ALIAS Optimization) -------------------------------------------------------------------------------- /Optimization/Cost.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 27.11.19. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "RenderPass.h" 8 | 9 | #include 10 | 11 | namespace TextureMapOptimization { 12 | 13 | class PhotometricCost : public ceres::SizedCostFunction<1, 6> { 14 | public: 15 | 16 | explicit PhotometricCost(size_t idx, RenderPass& renderPass) : m_kfIdx(idx), m_renderPass(renderPass) {} 17 | 18 | bool Evaluate(double const* const* parameters, 19 | double* residuals, 20 | double** jacobians) const override { 21 | double* grad = jacobians ? *jacobians : nullptr ; 22 | m_renderPass.optimizationPass(m_kfIdx, *parameters, *residuals, grad); 23 | return true; 24 | } 25 | 26 | private: 27 | 28 | size_t m_kfIdx; 29 | RenderPass& m_renderPass; 30 | }; 31 | 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /Optimization/KeyFrame.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/22/20. 3 | // 4 | 5 | #include "KeyFrame.h" 6 | 7 | #include 8 | #include 9 | 10 | using namespace Magnum; 11 | using namespace Corrade; 12 | 13 | namespace TextureMapOptimization { 14 | 15 | StaticArray<6,double> compressTransformationMatrix(const Matrix4& pose) { 16 | Matrix3 rot{pose[0].xyz(), pose[1].xyz(), pose[2].xyz()}; 17 | Quaternion q = Quaternion::fromMatrix(rot); 18 | Rad angle = q.angle(); 19 | auto axis = q.axis(); 20 | 21 | CORRADE_CONSTEXPR_ASSERT(angle <= Rad{2.f*M_PI} && angle >= Rad{0}, "angle negative"); 22 | 23 | Vector3 rotation = axis*float(angle); 24 | Vector3 translation = pose.translation(); 25 | 26 | StaticArray<6, double> pose6D; 27 | for(int i = 0; i < 3; ++i) { 28 | pose6D[i] = rotation[i]; 29 | pose6D[i + 3] = translation[i]; 30 | } 31 | return pose6D; 32 | } 33 | 34 | Matrix4 uncompress6DTransformation(const StaticArrayView<6, const double>& pose6D) { 35 | Vector3 rotation; 36 | Vector3 translation; 37 | for(int i = 0; i < 3; ++i) { 38 | rotation[i] = pose6D[i]; 39 | translation[i] = pose6D[i + 3]; 40 | } 41 | return Matrix4::translation(translation)*Matrix4::rotation(Rad{rotation.length()}, rotation.normalized()); 42 | } 43 | 44 | void KeyFrame::compressPose() { 45 | tf6D = compressTransformationMatrix(tf); 46 | } 47 | 48 | void KeyFrame::uncompressPose() { 49 | tf = uncompress6DTransformation(tf6D); 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /Optimization/KeyFrame.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/22/20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "Types.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace TextureMapOptimization { 15 | 16 | /** 17 | * Compress a 4x4 rigid transformation matrix into a 18 | * six dimensional angle axis + translation. 19 | * @param Transformation to compress 20 | * @return static array of length 6. First three entries 21 | * represent the rotation axis and the last three components 22 | * the translation. The length of the rotation axis encodes 23 | * the angle of the rotation. 24 | */ 25 | StaticArray<6,double> compressTransformationMatrix(const Matrix4& tf); 26 | 27 | /** 28 | * Does the inverse to compressTransformationMatrix. 29 | * @return a 4x4 rigid transformation matrix. 30 | */ 31 | Matrix4 uncompress6DTransformation(const StaticArrayView<6, const double>&); 32 | 33 | struct KeyFrame { 34 | GL::Texture2D image; 35 | 36 | Matrix4 tf; 37 | StaticArray<6, double> tf6D; 38 | 39 | /** 40 | * shorthand for calling compressTransformationMatrix on member data 41 | */ 42 | void compressPose(); 43 | 44 | /** 45 | * shorthand for calling uncomporess6DTransformation on member data 46 | */ 47 | void uncompressPose(); 48 | }; 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Optimization/Optimization.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 05.02.20. 3 | // 4 | 5 | #include "Optimization.h" 6 | #include "Cost.h" 7 | #include "ScopedTimer.h" 8 | #include "UniqueFunction.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace TextureMapOptimization { 20 | 21 | struct Callback : public ceres::IterationCallback { 22 | 23 | explicit Callback(UniqueFunction cb_) : cb(std::move(cb_)) {} 24 | 25 | ceres::CallbackReturnType operator()(ceres::IterationSummary const& summary) override { 26 | return cb(); 27 | } 28 | 29 | UniqueFunction cb; 30 | }; 31 | 32 | bool runOptimization( 33 | Array& kfs, 34 | GL::Texture2D& texture, 35 | RenderPass& renderPass, 36 | UniqueFunction&& cb) { 37 | 38 | //m_renderPass.setTexture(*m_texture); 39 | 40 | Callback callback{[&]{ 41 | for(auto& kf : kfs) 42 | kf.uncompressPose(); 43 | 44 | renderPass.averagingPass(); 45 | if(cb()){ 46 | return ceres::CallbackReturnType::SOLVER_CONTINUE; 47 | } else { 48 | return ceres::CallbackReturnType::SOLVER_ABORT; 49 | } 50 | }}; 51 | 52 | ceres::Problem problem; 53 | 54 | for(std::size_t i = 0; i < kfs.size(); ++i) { 55 | problem.AddResidualBlock(new PhotometricCost{i, renderPass}, new ceres::TrivialLoss{}, kfs[i].tf6D.data()); 56 | } 57 | 58 | ceres::Solver::Options options; 59 | options.linear_solver_type = ceres::SPARSE_SCHUR; 60 | options.minimizer_progress_to_stdout = true; 61 | options.update_state_every_iteration = true; 62 | options.callbacks.push_back(&callback); 63 | 64 | ceres::Solver::Summary summary; 65 | 66 | ceres::Solve(options, &problem, &summary); 67 | 68 | Debug{} << summary.BriefReport().c_str(); 69 | 70 | return summary.termination_type != ceres::USER_FAILURE; 71 | } 72 | 73 | } 74 | 75 | -------------------------------------------------------------------------------- /Optimization/Optimization.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 03.02.20. 3 | // 4 | 5 | 6 | #pragma once 7 | 8 | #include "KeyFrame.h" 9 | #include "RenderPass.h" 10 | #include "Utilities.h" 11 | 12 | namespace TextureMapOptimization { 13 | 14 | /** 15 | * 16 | * @param keyFrames array of keyframes 17 | * @param texture, which should be optimized. 18 | * @param renderPass encapsulates some rendering state and implements 19 | * both the averaging pass and the calculation of the gradients. 20 | * @param cb, callback which is passed through to the optimization algorithm. 21 | * @return false if terminated by the user, false otherwise 22 | */ 23 | bool runOptimization( 24 | Array& keyFrames, 25 | GL::Texture2D& texture, 26 | RenderPass& renderPass, 27 | UniqueFunction&& cb); 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /Optimization/RenderPass.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/23/20. 3 | // 4 | 5 | #include "RenderPass.h" 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | namespace TextureMapOptimization { 22 | 23 | namespace { 24 | 25 | void setupTexture(GL::Texture2D& texture, Vector2i const& size, GL::TextureFormat format, bool generateMipMap = false) { 26 | 27 | if(generateMipMap) 28 | texture.setMinificationFilter(GL::SamplerFilter::Linear, GL::SamplerMipmap::Linear); 29 | else 30 | texture.setMinificationFilter(GL::SamplerFilter::Linear); 31 | 32 | texture.setMagnificationFilter(GL::SamplerFilter::Linear) 33 | .setWrapping(GL::SamplerWrapping::ClampToEdge); 34 | 35 | if(generateMipMap) { 36 | texture.setStorage(Mg::Math::log2(size.max()) + 1, format, size); 37 | } else { 38 | texture.setStorage(1, format, size); 39 | } 40 | } 41 | 42 | } 43 | 44 | RenderPass::RenderPass(GL::Mesh& mesh, Array& keyFrames) : m_mesh(mesh), m_keyFrames(keyFrames) { 45 | 46 | m_imageSize = keyFrames.front().image.imageSize(0); 47 | m_fb = GL::Framebuffer{{{}, m_imageSize}}; 48 | 49 | //m_mesh.addVertexBufferInstanced(m_instancedTransformations, 1, 0, Shaders::Diff::TransformationMatrix{}); 50 | 51 | /* textures for intermediate steps in gradient computation */ 52 | Int layerCount = m_keyFrames.size(); 53 | setupTexture(m_depth, m_imageSize, GL::TextureFormat::DepthComponent32F); 54 | setupTexture(m_costs, m_imageSize, GL::TextureFormat::RG32F, true); 55 | setupTexture(m_gradientRotations, m_imageSize, GL::TextureFormat::RGBA32F, true); 56 | setupTexture(m_gradientTranslations, m_imageSize, GL::TextureFormat::RGBA32F, true); 57 | 58 | setupTexture(m_texCoordsTexture, m_imageSize, GL::TextureFormat::RGBA32F); 59 | 60 | const auto map = Mg::DebugTools::ColorMap::turbo(); 61 | const Vector2i size{Int(map.size()), 1}; 62 | 63 | m_turbo 64 | .setMinificationFilter(GL::SamplerFilter::Linear) 65 | .setMagnificationFilter(GL::SamplerFilter::Linear) 66 | .setWrapping(GL::SamplerWrapping::ClampToEdge) // or Repeat 67 | .setStorage(1, GL::TextureFormat::RGB8, size) // or SRGB8 68 | .setSubImage(0, {}, Mg::ImageView2D{Mg::PixelFormat::RGB8Srgb, size, map}); 69 | } 70 | 71 | void RenderPass::setTexture(GL::Texture2D& texture) { 72 | m_texture = &texture; 73 | m_textureSize = m_texture->imageSize(0); 74 | 75 | /* texture for averaging image colors in texture */ 76 | setupTexture(m_red, m_textureSize, GL::TextureFormat::R32F); 77 | setupTexture(m_green, m_textureSize, GL::TextureFormat::R32F); 78 | setupTexture(m_blue, m_textureSize, GL::TextureFormat::R32F); 79 | setupTexture(m_count, m_textureSize, GL::TextureFormat::R32F); 80 | } 81 | 82 | void RenderPass::setFramebufferMode(FramebufferMode mode) { 83 | 84 | if(m_fbMode != mode && mode == FramebufferMode::ColorAveragingPass) { 85 | m_fb.attachTexture(GL::Framebuffer::BufferAttachment::Depth, m_depth, 0) 86 | .attachTexture(GL::Framebuffer::ColorAttachment{0}, m_texCoordsTexture, 0) 87 | .mapForDraw(GL::Framebuffer::ColorAttachment{0}); 88 | } 89 | 90 | if(m_fbMode != mode && mode == FramebufferMode::OptimizationPass) { 91 | m_fb.attachTexture(GL::Framebuffer::BufferAttachment::Depth, m_depth, 0) 92 | .attachTexture(GL::Framebuffer::ColorAttachment{0}, m_costs, 0) 93 | .attachTexture(GL::Framebuffer::ColorAttachment{1}, m_gradientRotations, 0) 94 | .attachTexture(GL::Framebuffer::ColorAttachment{2}, m_gradientTranslations, 0) 95 | .mapForDraw({{0, GL::Framebuffer::ColorAttachment{0}}, {1, GL::Framebuffer::ColorAttachment{1}}, {2, GL::Framebuffer::ColorAttachment{2}}}); 96 | } 97 | 98 | m_fb.bind(); 99 | CORRADE_INTERNAL_ASSERT(m_fb.checkStatus(GL::FramebufferTarget::Draw) == GL::Framebuffer::Status::Complete); 100 | m_fbMode = mode; 101 | } 102 | 103 | void RenderPass::optimizationPass(size_t idx, const double* params, double& residual, double* gradient) { 104 | m_profilerComputeGradient.beginFrame(); 105 | 106 | setFramebufferMode(FramebufferMode::OptimizationPass); 107 | m_fb.clear(GL::FramebufferClear::Depth | GL::FramebufferClear::Color); 108 | 109 | Vector3 rotation(params[0], params[1], params[2]); 110 | Vector3 translation(params[3], params[4], params[5]); 111 | 112 | auto view = uncompress6DTransformation(StaticArrayView<6, const double>{params}); 113 | 114 | m_diff.setTranslation(translation) 115 | .setRotation(rotation) 116 | .setProjectionTransformationMatrix(m_projection*view) 117 | .setCameraParameters(m_fx, m_fy, m_cx, m_cy) 118 | .bindGroundTruthTexture(m_keyFrames[idx].image) 119 | .bindOptimizationTexture(*m_texture) 120 | .draw(m_mesh); 121 | 122 | //TODO: replace this with a proper reduction shader 123 | //building a flatter mip chain. 124 | m_costs.generateMipmap(); 125 | m_gradientRotations.generateMipmap(); 126 | m_gradientTranslations.generateMipmap(); 127 | 128 | /* download the last mip level */ 129 | float costHom[2]; 130 | float gradRotHom[4]; 131 | float gradTransHom[4]; 132 | 133 | Mg::MutableImageView2D costView{GL::PixelFormat::RG, GL::PixelType::Float, {1, 1}, costHom}; 134 | Mg::MutableImageView2D rotView{GL::PixelFormat::RGBA, GL::PixelType::Float, {1, 1}, gradRotHom}; 135 | Mg::MutableImageView2D transView{GL::PixelFormat::RGBA, GL::PixelType::Float, {1, 1}, gradTransHom}; 136 | 137 | Int lastMipIdx = Math::log2(m_imageSize.max()); 138 | m_costs.image(lastMipIdx, costView); 139 | m_gradientRotations.image(lastMipIdx, rotView); 140 | m_gradientTranslations.image(lastMipIdx, transView); 141 | 142 | residual = costHom[0]/costHom[1]; 143 | if(gradient) { 144 | for(int j = 0; j < 3; ++j) { 145 | gradient[j] = gradRotHom[j]/gradRotHom[3]; 146 | gradient[3 + j] = gradTransHom[j]/gradTransHom[3]; 147 | } 148 | } 149 | 150 | m_profilerComputeGradient.endFrame(); 151 | //m_profilerComputeGradient.printStatistics(10); 152 | } 153 | 154 | void RenderPass::averagingPass() { 155 | ScopedTimer t{"Averaging all colors", true}; 156 | 157 | setFramebufferMode(FramebufferMode::ColorAveragingPass); 158 | 159 | m_fb.clear(GL::FramebufferClear::Depth | GL::FramebufferClear::Color); 160 | 161 | Vector3ui wgCount1(m_imageSize.x(), m_imageSize.y(), 1); 162 | Vector3ui wgCount2(m_textureSize.x(), m_textureSize.y(), 1); 163 | 164 | m_fb.clearColor(0, Color4{}); 165 | 166 | for(auto& kf : m_keyFrames) { 167 | kf.uncompressPose(); 168 | m_fb.clear(GL::FramebufferClear::Color | GL::FramebufferClear::Depth); 169 | 170 | m_texCoordsShader.setTransformationProjectionMatrix(m_projection*kf.tf) 171 | .draw(m_mesh); 172 | 173 | m_remap.bindTextureR(m_red) 174 | .bindTextureG(m_green) 175 | .bindTextureB(m_blue) 176 | .bindTextureA(m_count) 177 | .bindImage(kf.image) 178 | .bindTextureCoordinates(m_texCoordsTexture) 179 | .dispatchCompute(wgCount1); 180 | } 181 | 182 | glMemoryBarrier(GL_ALL_BARRIER_BITS); 183 | 184 | m_combine.bindTextureR(m_red) 185 | .bindTextureG(m_green) 186 | .bindTextureB(m_blue) 187 | .bindTextureA(m_count) 188 | .bindRgbaImage(*m_texture) 189 | .dispatchCompute(wgCount2); 190 | 191 | //GL::Renderer::setMemoryBarrier(Mg::GL::Renderer::MemoryBarrier::TextureFetch); 192 | glMemoryBarrier(GL_ALL_BARRIER_BITS); 193 | } 194 | 195 | void RenderPass::renderIntoTexture(GL::Texture2D& image, size_t idx, VisualizatonFlag flag) { 196 | if(flag == VisualizatonFlag::RenderedImage) { 197 | m_fb.attachTexture(GL::Framebuffer::BufferAttachment::Depth, m_depth, 0) 198 | .attachTexture(GL::Framebuffer::ColorAttachment{0}, image, 0) 199 | .mapForDraw(GL::Framebuffer::ColorAttachment{0}) 200 | .bind(); 201 | 202 | CORRADE_INTERNAL_ASSERT(m_fb.checkStatus(GL::FramebufferTarget::Draw) == GL::Framebuffer::Status::Complete); 203 | auto& kf = m_keyFrames[idx]; 204 | 205 | m_fb.clear(GL::FramebufferClear::Depth | GL::FramebufferClear::Color); 206 | Mg::Shaders::Flat3D flat{Mg::Shaders::Flat3D::Flag::Textured}; 207 | assert(m_texture); 208 | flat.bindTexture(*m_texture) 209 | .setTransformationProjectionMatrix(m_projection*kf.tf) 210 | .draw(m_mesh); 211 | 212 | return; 213 | } else { 214 | setFramebufferMode(FramebufferMode::OptimizationPass); 215 | } 216 | m_fb.clear(GL::FramebufferClear::Depth | GL::FramebufferClear::Color); 217 | 218 | StaticArrayView<6, const double> params = m_keyFrames[idx].tf6D; 219 | Vector3 rotation(params[0], params[1], params[2]); 220 | Vector3 translation(params[3], params[4], params[5]); 221 | 222 | Shaders::Diff diff; 223 | 224 | diff.setTranslation(translation) 225 | .setRotation(rotation) 226 | .setProjectionTransformationMatrix(m_projection*m_keyFrames[idx].tf) 227 | .setCameraParameters(m_fx, m_fy, m_cx, m_cy) 228 | .bindGroundTruthTexture(m_keyFrames[idx].image) 229 | .bindOptimizationTexture(*m_texture) 230 | .draw(m_mesh); 231 | 232 | bool fetchCost = flag == VisualizatonFlag::Cost; 233 | bool fetchRot = flag == VisualizatonFlag::RotationGradient; 234 | bool fetchTrans = flag == VisualizatonFlag::TranslationGradient; 235 | 236 | Array costData(NoInit, 2*sizeof(float)*m_imageSize.product()); 237 | Array rotData(4*sizeof(float)*m_imageSize.product()); 238 | Array transData(NoInit, 4*sizeof(float)*m_imageSize.product()); 239 | 240 | if(fetchCost) 241 | m_costs.image(0, Mg::MutableImageView2D{GL::PixelFormat::RG, GL::PixelType::Float, m_imageSize, costData}); 242 | if(fetchRot) 243 | m_gradientRotations.image(0,Mg::MutableImageView2D{GL::PixelFormat::RGBA, GL::PixelType::Float, m_imageSize, rotData}); 244 | if(fetchTrans) 245 | m_gradientTranslations.image(0, Mg::MutableImageView2D{GL::PixelFormat::RGBA, GL::PixelType::Float, m_imageSize, transData}); 246 | 247 | float min = std::numeric_limits::max(); 248 | float max = -std::numeric_limits::max(); 249 | for(size_t i = 0; i < m_imageSize.product(); ++i) { 250 | float value; 251 | 252 | if(fetchCost) 253 | value = arrayCast(costData)[i].x(); 254 | if(fetchRot) 255 | value = arrayCast(rotData)[i].xyz().length(); 256 | if(fetchTrans) 257 | value = arrayCast(transData)[i].xyz().length(); 258 | 259 | if(value > std::numeric_limits::epsilon()) { 260 | min = Math::min(value, min); 261 | max = Math::max(value, max); 262 | } 263 | } 264 | 265 | float scale = 1.f/(max - min); 266 | float offset = 1 - max*scale; 267 | 268 | Vector3ui wgCount(m_imageSize.x(), m_imageSize.y(), 1); 269 | m_vis.setColorMapTransform(scale, offset) 270 | .bindColorMap(m_turbo) 271 | .bindOutputImage(image); 272 | 273 | if(fetchCost) 274 | m_vis.bindCostImage(m_costs); 275 | if(fetchTrans) 276 | m_vis.bindGradientImage(m_gradientTranslations); 277 | if(fetchRot) 278 | m_vis.bindGradientImage(m_gradientRotations); 279 | 280 | m_vis.dispatchCompute(wgCount); 281 | } 282 | 283 | void RenderPass::reloadShader() { 284 | Cr::Utility::Resource::overrideGroup("tmo-data", "/home/janos/TextureMapOptimization/Shaders/resources.conf"); 285 | m_diff = Shaders::Diff(); 286 | m_texCoordsShader = Shaders::TextureCoordinates(); 287 | m_remap = Shaders::Remap(); 288 | m_combine = Shaders::Combine(); 289 | m_vis = Shaders::Vis(); 290 | } 291 | 292 | } -------------------------------------------------------------------------------- /Optimization/RenderPass.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/23/20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "KeyFrame.h" 8 | #include "Diff.h" 9 | #include "Reduction.h" 10 | #include "Vis.h" 11 | #include "TextureCoordinates.h" 12 | #include "Remap.h" 13 | #include "Combine.h" 14 | #include "DepthFilter.h" 15 | #include "Types.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace Mg = Magnum; 27 | namespace Cr = Corrade; 28 | 29 | namespace TextureMapOptimization { 30 | 31 | class RenderPass { 32 | public: 33 | 34 | enum class FramebufferMode : Mg::UnsignedInt { 35 | ColorAveragingPass = 1, 36 | OptimizationPass = 2 37 | }; 38 | 39 | enum class Flag : Mg::UnsignedInt { 40 | DepthFiltering 41 | }; 42 | 43 | using Flags = Cr::Containers::EnumSet; 44 | 45 | CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) 46 | 47 | RenderPass(GL::Mesh&, Array&); 48 | 49 | void setTexture(GL::Texture2D& texture); 50 | 51 | void optimizationPass(size_t idx, double const* params, double& cost, double* gradient); 52 | 53 | /** 54 | * For each key frame computes dense texture coordinates. 55 | * Then uses the texture coordinates to map color values 56 | * from the ground truth image into the texture. Since this 57 | * has do be done atomically, the texture is split into its 58 | * three rgb channels and then combined later, when all 59 | * key frames have been processed. 60 | */ 61 | void averagingPass(); 62 | 63 | /** 64 | * prepares the framebuffer for either running 65 | * an averaging pass or an optimization pass. 66 | */ 67 | void setFramebufferMode(FramebufferMode); 68 | 69 | enum class VisualizatonFlag { 70 | Cost = 1, 71 | RotationGradient = 2, 72 | TranslationGradient = 3, 73 | RenderedImage = 4, 74 | }; 75 | 76 | /** 77 | * Utility for rendering some feature of 78 | * a specific key frame into a texture. This 79 | * is mainly useful for debuggin purposes. 80 | * @param image texture into which we want to render. 81 | * This must be allocated already. 82 | * @param idx keyframe index to render 83 | * @param flag to choose between different features 84 | * like gradients, cost or simply a synthetic view 85 | * of the key frame. 86 | */ 87 | void renderIntoTexture(GL::Texture2D& image, size_t idx, VisualizatonFlag flag); 88 | 89 | /** 90 | * @param nx image width 91 | * @param ny image height 92 | * @param fx focal length wrt. pixel width 93 | * @param fy focal length wrt. pixel height 94 | * @param cx x coordinate of central point 95 | * @param cy y coordinate of central point 96 | */ 97 | void setCameraParameters(float nx, float ny, float fx, float fy, float cx, float cy) { 98 | auto fov = Math::atan(nx/(2*fx)); 99 | m_projection = Matrix4::perspectiveProjection(2*fov, nx/ny, 0.01, 10); 100 | 101 | m_fx = fx; 102 | m_fy = fy; 103 | m_cx = cx; 104 | m_cy = cy; 105 | } 106 | 107 | /** 108 | * This reloads and recompiles the shaders. 109 | * This is nice for interactivley debugging/editing 110 | * shaders; 111 | */ 112 | void reloadShader(); 113 | 114 | private: 115 | 116 | GL::Mesh& m_mesh; 117 | Array& m_keyFrames; 118 | 119 | GL::Texture2D* m_texture = nullptr; 120 | 121 | Matrix4 m_projection; 122 | float m_fx, m_fy, m_cx, m_cy; 123 | 124 | GL::Framebuffer m_fb{Mg::NoCreate}; 125 | 126 | UnsignedInt m_depthFilterReductionFactor = 3; 127 | 128 | Shaders::Diff m_diff; 129 | Shaders::TextureCoordinates m_texCoordsShader; 130 | Shaders::Remap m_remap; 131 | Shaders::Combine m_combine; 132 | Shaders::Vis m_vis; 133 | //Shaders::Reduction m_reduction; 134 | 135 | GL::Texture2D m_gradientRotations, m_gradientTranslations, m_costs; 136 | 137 | GL::Texture2D m_red, m_green, m_blue; 138 | GL::Texture2D m_count; 139 | 140 | GL::Texture2D m_depth; 141 | GL::Texture2D m_texCoordsTexture; 142 | 143 | Vector2i m_imageSize; 144 | Vector2i m_textureSize; 145 | 146 | FramebufferMode m_fbMode{0}; 147 | 148 | /* Profiling */ 149 | Mg::DebugTools::GLFrameProfiler m_profilerGenerateTexture{ 150 | Mg::DebugTools::GLFrameProfiler::Value::FrameTime| 151 | Mg::DebugTools::GLFrameProfiler::Value::CpuDuration, 180}; 152 | 153 | Mg::DebugTools::GLFrameProfiler m_profilerComputeGradient{ 154 | Mg::DebugTools::GLFrameProfiler::Value::FrameTime| 155 | Mg::DebugTools::GLFrameProfiler::Value::CpuDuration, 180}; 156 | 157 | GL::Texture2D m_turbo; //colormap 158 | 159 | }; 160 | 161 | } 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Texture Map Optimization 2 | 3 | # Building 4 | To build you will need the following four dependencies : [assimp](https://github.com/assimp/assimp), [ceres](https://github.com/ceres-solver/ceres-solver), [corrade](https://github.com/mosra/corrade), [magnum](https://github.com/mosra/magnum) and [magnum-plugins](https://github.com/mosra/magnum-plugins) 5 | If you are on linux, there will most likely be precompiled packages for assimp and ceres provided by your 6 | distros package manager. For the other three deps, I suggest compiling from source. 7 | 8 | This project uses cmake to generate project files. 9 | To build using e.g. ninja you can use the following commands 10 | ```bash 11 | mkdir build 12 | cmake .. -DCMAKE_BUILD_TYPE=Release -GNinja 13 | ninja 14 | ``` 15 | # Example 16 | The repository contains an application which can load a mesh and calibrated rgb images. 17 | Be aware that the mesh it is *necessary* for the mesh to have texture coordinates. 18 | If your mesh does not have texture coordinates, I suggest to generate them using e.g. 19 | blenders smart uv unwrap tool. 20 | Once everything is loaded you can average all rgb images into the 21 | texture and then optimize the individual poses of the rgb images 22 | to obtain a sharper texture. 23 | The inverse texture mapping and optimization is done using compute shader. 24 | Thus optimizing texture maps, even for large rgb images, should be fast. 25 | 26 | Optimize texture colors on the gpu. Below you can see the result of rendering texture coordinates 27 | and applying the inverse texture map to map image colors onto a the texture. 28 | ![alt text](https://github.com/Janos95/texture_map_optimization/blob/master/render.png) 29 | ![alt text](https://github.com/Janos95/texture_map_optimization/blob/master/texture.png) 30 | -------------------------------------------------------------------------------- /ScopedTimer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(ScopedTimer STATIC ScopedTimer.cpp) 3 | target_include_directories(ScopedTimer PUBLIC 4 | $) 5 | 6 | add_library(Tmo::ScopedTimer ALIAS ScopedTimer) -------------------------------------------------------------------------------- /ScopedTimer/ScopedTimer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 19.10.19. 3 | // 4 | 5 | #include "ScopedTimer.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using my_clock = std::chrono::steady_clock; 14 | using my_duration = std::chrono::duration; 15 | using time_point_t = std::chrono::time_point; 16 | 17 | template 18 | char const* toSI() 19 | { 20 | if constexpr(std::is_same_v) 21 | return "nano seconds"; 22 | if constexpr(std::is_same_v) 23 | return "micro seconds"; 24 | if constexpr(std::is_same_v) 25 | return "milli seconds"; 26 | if constexpr(std::is_same_v, Ratio>) 27 | return "seconds"; 28 | if constexpr(std::is_same_v, Ratio>) 29 | return "minutes"; 30 | if constexpr(std::is_same_v, Ratio>) 31 | return "hours"; 32 | } 33 | 34 | using Ratio = std::ratio<1>; 35 | using user_dur = std::chrono::duration; 36 | 37 | struct TimingInfo 38 | { 39 | my_duration mean{0}; 40 | double M2 = 0; 41 | std::size_t count = 0; 42 | }; 43 | 44 | struct ScopedTimer::Impl{ 45 | std::string name_; 46 | time_point_t start_; 47 | bool verbose_; 48 | }; 49 | 50 | std::unordered_map log_; 51 | std::mutex mutex_; 52 | 53 | ScopedTimer::ScopedTimer(char const* name, bool verbose): 54 | m_impl(new Impl{name, my_clock::now(), verbose}) 55 | { 56 | } 57 | 58 | ScopedTimer::~ScopedTimer() { 59 | const auto end = my_clock::now(); 60 | my_duration time = end - m_impl->start_; 61 | if(m_impl->verbose_) 62 | printf("%s took %f %s\n", m_impl->name_.c_str(), user_dur{time}.count(), toSI()); 63 | 64 | std::lock_guard l(mutex_); 65 | 66 | auto& [mean, M2, count] = log_[m_impl->name_]; 67 | ++count; 68 | auto delta1 = time - mean; 69 | mean += delta1 / count; 70 | auto delta2 = time - mean; 71 | M2 += delta1.count() * delta2.count(); 72 | 73 | delete m_impl; 74 | } 75 | 76 | void ScopedTimer::printStatistics() 77 | { 78 | std::lock_guard l(mutex_); 79 | for(const auto& [name, timingInfo]: log_) 80 | { 81 | const auto& [mean, M2, count] = timingInfo; 82 | user_dur standardDeviation = my_duration{std::sqrt(M2/static_cast(count - 1))}; 83 | user_dur meanUser = mean; 84 | //auto unit = toSI(); 85 | const char* unit = "seconds"; 86 | printf("%s: Mean %f %s, Standard Deviation %f %s\n", name.c_str(), meanUser.count(), unit, standardDeviation.count(), unit); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ScopedTimer/ScopedTimer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Janos Meny on 9/4/19. 3 | // 4 | 5 | #pragma once 6 | 7 | /** 8 | * Timer class. The timing is started when a variable 9 | * the variable is defined and is stopped when the variable 10 | * goes out of scope. The timing is written into a global 11 | * hash map using the provided name as a key. If multiple 12 | * measurements are performed for the same key, an average 13 | * is stored and a rolling standard deviation is computed. 14 | * The content of the hash map can be printed using the 15 | * printStatistics member function. 16 | */ 17 | class ScopedTimer 18 | { 19 | public: 20 | 21 | /** 22 | * @param name of the timer 23 | * @param verbose if yes, then the timing is printed on destruction. 24 | * Turned off by default. 25 | */ 26 | explicit ScopedTimer(char const* name, bool verbose = false); 27 | 28 | ~ScopedTimer(); 29 | 30 | /** 31 | * This goes through the set of stored timings 32 | * and prints them together with its standard 33 | * deviation. 34 | */ 35 | static void printStatistics(); 36 | 37 | private: 38 | struct Impl; 39 | Impl* m_impl; 40 | }; 41 | -------------------------------------------------------------------------------- /Shaders/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | corrade_add_resource(TMO_Rcs resources.conf) 3 | 4 | add_library(Shaders SHARED 5 | Diff.h 6 | Diff.cpp 7 | TextureCoordinates.h 8 | TextureCoordinates.cpp 9 | TextureCoordinates.cpp 10 | TextureCoordinates.h 11 | FullScreenTriangle.cpp 12 | FullScreenTriangle.h 13 | Remap.cpp 14 | Remap.h 15 | Combine.cpp 16 | Combine.h 17 | Reduction.cpp 18 | Reduction.h 19 | Vis.cpp 20 | Vis.h 21 | #DepthFilter.cpp 22 | #DepthFilter.h 23 | ${TMO_Rcs} ) 24 | 25 | 26 | target_include_directories(Shaders PUBLIC ${CMAKE_CURRENT_LIST_DIR}) 27 | target_link_libraries(Shaders 28 | PUBLIC 29 | Magnum::Magnum 30 | Magnum::Shaders 31 | Tmo::Utilities 32 | Tmo::ScopedTimer 33 | ) 34 | 35 | add_library(Tmo::Shaders ALIAS Shaders) 36 | -------------------------------------------------------------------------------- /Shaders/Combine.comp: -------------------------------------------------------------------------------- 1 | layout(local_size_x = 1, local_size_y = 1) in; 2 | 3 | layout(r32f, binding = 0) 4 | uniform readonly image2D texR; 5 | 6 | layout(r32f, binding = 1) 7 | uniform readonly image2D texG; 8 | 9 | layout(r32f, binding = 2) 10 | uniform readonly image2D texB; 11 | 12 | layout(r32f, binding = 3) 13 | uniform readonly image2D texA; 14 | 15 | layout(rgba32f, binding = 4) 16 | uniform writeonly image2D imageRgba; 17 | 18 | void main() 19 | { 20 | ivec2 coords = ivec2(gl_GlobalInvocationID.xy); 21 | vec3 color; 22 | float count = imageLoad(texA, coords).r; 23 | if(count < 1){ 24 | color = vec3(0); 25 | } else { 26 | color = vec3(imageLoad(texR, coords).r, imageLoad(texG, coords).r, imageLoad(texB, coords).r)/count; 27 | } 28 | imageStore(imageRgba, coords, vec4(color,1)); 29 | } 30 | -------------------------------------------------------------------------------- /Shaders/Combine.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/5/20. 3 | // 4 | 5 | #include "Combine.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | using namespace Magnum; 18 | 19 | namespace TextureMapOptimization::Shaders{ 20 | 21 | Combine::Combine() { 22 | MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL460); 23 | 24 | Utility::Resource rs{"tmo-data"}; 25 | 26 | GL::Shader comp{GL::Version::GL460, GL::Shader::Type::Compute}; 27 | 28 | comp.addSource(rs.get("Combine.comp")); 29 | 30 | CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({comp})); 31 | 32 | attachShaders({comp}); 33 | 34 | CORRADE_INTERNAL_ASSERT_OUTPUT(link()); 35 | } 36 | 37 | Combine& Combine::bindTextureR(GL::Texture2D& texture){ 38 | texture.bindImage(m_textureRUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::R32F); 39 | return *this; 40 | } 41 | 42 | Combine& Combine::bindTextureG(GL::Texture2D& texture){ 43 | texture.bindImage(m_textureGUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::R32F); 44 | return *this; 45 | } 46 | 47 | Combine& Combine::bindTextureB(GL::Texture2D& texture){ 48 | texture.bindImage(m_textureBUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::R32F); 49 | return *this; 50 | } 51 | 52 | Combine& Combine::bindTextureA(GL::Texture2D& texture){ 53 | texture.bindImage(m_textureAUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::R32F); 54 | return *this; 55 | } 56 | 57 | Combine& Combine::bindRgbaImage(GL::Texture2D& rgba){ 58 | rgba.bindImage(m_textureRgbaUnit, 0, GL::ImageAccess::WriteOnly, GL::ImageFormat::RGBA32F); 59 | return *this; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /Shaders/Combine.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/5/20. 3 | // 4 | 5 | #ifndef TEXTUREOPTIMIZATION_COMBINE_H 6 | #define TEXTUREOPTIMIZATION_COMBINE_H 7 | 8 | #include 9 | #include 10 | 11 | namespace TextureMapOptimization::Shaders { 12 | 13 | class Combine : public Magnum::GL::AbstractShaderProgram { 14 | public: 15 | 16 | enum class ImageUnit : Magnum::UnsignedInt { 17 | Image = 0, 18 | TextureCoordinate = 1, 19 | Texture = 2 20 | }; 21 | 22 | explicit Combine(); 23 | 24 | explicit Combine(Magnum::NoCreateT) : Magnum::GL::AbstractShaderProgram{Magnum::NoCreate} {}; 25 | 26 | Combine& bindTextureR(Magnum::GL::Texture2D&); 27 | Combine& bindTextureG(Magnum::GL::Texture2D&); 28 | Combine& bindTextureB(Magnum::GL::Texture2D&); 29 | Combine& bindTextureA(Magnum::GL::Texture2D&); 30 | Combine& bindRgbaImage(Magnum::GL::Texture2D&); 31 | 32 | private: 33 | 34 | Magnum::UnsignedInt m_textureRUnit = 0; 35 | Magnum::UnsignedInt m_textureGUnit = 1; 36 | Magnum::UnsignedInt m_textureBUnit = 2; 37 | Magnum::UnsignedInt m_textureAUnit = 3; 38 | Magnum::UnsignedInt m_textureRgbaUnit = 4; 39 | }; 40 | 41 | } 42 | 43 | #endif //TEXTUREOPTIMIZATION_COMBINE_H 44 | -------------------------------------------------------------------------------- /Shaders/DepthFilter.comp: -------------------------------------------------------------------------------- 1 | layout(local_size_x = 1, local_size_y = 1) in; 2 | 3 | layout(r32f, binding = 0) 4 | uniform readonly image2D cost; 5 | 6 | layout(rgb32f, binding = 1) 7 | uniform readonly image2D gradientRotation; 8 | 9 | layout(rgb32f, binding = 2) 10 | uniform readonly image2D gradientTranslation; 11 | 12 | layout(r32f, binding = 3) 13 | uniform writeonly image2D costAccumulated; 14 | 15 | layout(rgb32f, binding = 4) 16 | uniform writeonly image2D gradientRotationAccumulated; 17 | 18 | layout(rgb32f, binding = 5) 19 | uniform writeonly image2D gradientTranslationAccumulated; 20 | 21 | layout(rgb32f, binding = 6) 22 | uniform readonly image2D depth; 23 | 24 | layout(location = 0) 25 | uniform float discontinuityThreshold = 0.005; /* 5mm defaul threshold */ 26 | 27 | void main() 28 | { 29 | ivec2 coordOutput = gl_GlobalInvocationID; 30 | ivec2 coordInput = BLOCK_SIZE * coordOutput; 31 | 32 | vec2 sumCost = vec2(0); 33 | vec4 sumRotation = vec4(0); 34 | vec4 sumTranslation = vec4(0); 35 | 36 | float maximumDepth = -1000; 37 | float minimumDepth = 1000; 38 | for(int i = 0; i < BLOCK_SIZE; ++i){ 39 | for(int j = 0; j < BLOCK_SIZE; ++j){ 40 | ivec2 offset = ivec2(i,j); 41 | sumCost += imageLoad(costInput, coordInput + offset).xy; 42 | sumRotation += imageLoad(rotationInput, coordInput + offset); 43 | sumTranslation += imageLoad(translationInput, coordInput + offset); 44 | float d = imageLoad(depth, coordInput + offset).x; 45 | maximumDepth = max(maximumDepth, d); 46 | minimumDepth = min(minimumDepth, d); 47 | } 48 | } 49 | 50 | float isValid = float(maximumDepth - minimumDepth < discontinuityThreshold); 51 | 52 | imageStore(gradientRotationAccumulated, coords, isValid*gradRotSum); 53 | imageStore(gradientTranslationAccumulated, coords, isValid*gradTransSum); 54 | imageStore(costAccumulated, coords, isValid*vec4(costSum, 0, 0)); 55 | } 56 | -------------------------------------------------------------------------------- /Shaders/DepthFilter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/6/20. 3 | // 4 | 5 | #include "DepthFilter.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace Magnum; 20 | 21 | namespace TextureMapOptimization::Shaders { 22 | 23 | DepthFilter::DepthFilter(UnsignedInt stepSize) { 24 | MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL460); 25 | 26 | Utility::Resource rs{"tmo-data"}; 27 | 28 | GL::Shader comp{GL::Version::GL460, GL::Shader::Type::Compute}; 29 | 30 | comp.addSource(Utility::formatString("#define BLOCK_SIZE {}\n", 1u << stepSize)) 31 | .addSource(rs.get("DepthFilter.comp")); 32 | 33 | CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({comp})); 34 | 35 | attachShaders({comp}); 36 | 37 | CORRADE_INTERNAL_ASSERT_OUTPUT(link()); 38 | } 39 | 40 | DepthFilter& DepthFilter::bindCosts(Magnum::GL::Texture2D& texture){ 41 | texture.bindImage(m_costUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::R32F); 42 | return *this; 43 | } 44 | 45 | DepthFilter& DepthFilter::bindRotationGradients(Magnum::GL::Texture2D& texture){ 46 | texture.bindImage(m_rotationUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::RGBA32F); 47 | return *this; 48 | } 49 | 50 | DepthFilter& DepthFilter::bindTranslationGradients(Magnum::GL::Texture2D& texture){ 51 | texture.bindImage(m_translationUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::RGBA32F); 52 | return *this; 53 | } 54 | 55 | DepthFilter& DepthFilter::bindCostsAccumulated(Magnum::GL::Texture2DArray& texture, UnsignedInt layer){ 56 | texture.bindImage(m_costAccumulatedUnit, 0, layer, GL::ImageAccess::WriteOnly, GL::ImageFormat::R32F); 57 | return *this; 58 | } 59 | 60 | DepthFilter& DepthFilter::bindTranslationGradientsAccumulated(Magnum::GL::Texture2DArray& texture, UnsignedInt layer){ 61 | texture.bindImage(m_translationAccumulatedUnit, 0, layer, GL::ImageAccess::WriteOnly, GL::ImageFormat::RGBA32F); 62 | return *this; 63 | } 64 | 65 | DepthFilter& DepthFilter::bindRotationGradientsAccumulated(Magnum::GL::Texture2DArray& texture, UnsignedInt layer){ 66 | texture.bindImage(m_rotationAccumulatedUnit, 0, layer, GL::ImageAccess::WriteOnly, GL::ImageFormat::RGBA32F); 67 | return *this; 68 | } 69 | 70 | DepthFilter& DepthFilter::bindDepth(Mg::GL::Texture2D& texture) { 71 | texture.bindImage(m_depthUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::R32F); 72 | return *this; 73 | } 74 | 75 | DepthFilter& DepthFilter::setDepthDiscontinuityThreshold(Mg::Float threshold) { 76 | setUniform(m_thresholdUniform, threshold); 77 | return *this; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /Shaders/DepthFilter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/6/20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "Types.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace TextureMapOptimization::Shaders { 13 | 14 | namespace Mg = Magnum; 15 | 16 | class DepthFilter : public Magnum::GL::AbstractShaderProgram { 17 | public: 18 | 19 | explicit DepthFilter(Mg::UnsignedInt); 20 | 21 | explicit DepthFilter(Mg::NoCreateT) : GL::AbstractShaderProgram{Magnum::NoCreate} {}; 22 | 23 | DepthFilter& bindCosts(GL::Texture2D&); 24 | DepthFilter& bindRotationGradients(GL::Texture2D&); 25 | DepthFilter& bindTranslationGradients(GL::Texture2D&); 26 | 27 | DepthFilter& bindCostsAccumulated(GL::Texture2DArray&, UnsignedInt); 28 | DepthFilter& bindTranslationGradientsAccumulated(GL::Texture2DArray&, UnsignedInt); 29 | DepthFilter& bindRotationGradientsAccumulated(GL::Texture2DArray&, UnsignedInt); 30 | 31 | DepthFilter& bindDepth(GL::Texture2D&); 32 | 33 | DepthFilter& setDepthDiscontinuityThreshold(Mg::Float); 34 | 35 | private: 36 | 37 | Mg::UnsignedInt m_costUnit = 0, 38 | m_rotationUnit = 1, 39 | m_translationUnit = 2, 40 | m_costAccumulatedUnit = 3, 41 | m_rotationAccumulatedUnit = 4, 42 | m_translationAccumulatedUnit = 5, 43 | m_depthUnit = 6; 44 | 45 | Mg::UnsignedInt m_thresholdUniform; 46 | }; 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Shaders/Diff.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 05.02.20. 3 | // 4 | 5 | #include "Diff.h" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace Cr = Corrade; 18 | 19 | namespace TextureMapOptimization::Shaders { 20 | 21 | Diff::Diff() { 22 | MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL450); 23 | 24 | Cr::Utility::Resource rs{"tmo-data"}; 25 | 26 | GL::Shader vert{GL::Version::GL450, GL::Shader::Type::Vertex}; 27 | GL::Shader frag{GL::Version::GL450, GL::Shader::Type::Fragment}; 28 | 29 | vert.addSource(rs.get("generic.glsl")) 30 | .addSource(rs.get("Diff.vert")); 31 | 32 | frag.addSource(rs.get("Diff.frag")); 33 | 34 | CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); 35 | 36 | attachShaders({vert, frag}); 37 | 38 | CORRADE_INTERNAL_ASSERT_OUTPUT(link()); 39 | 40 | m_rotationUniform = uniformLocation("rotation"); 41 | m_translationUniform = uniformLocation("translation"); 42 | m_projTfUniform = uniformLocation("projectionTransformationMatrix"); 43 | m_fxUniform = uniformLocation("fx"); 44 | m_fyUniform = uniformLocation("fy"); 45 | m_cxUniform = uniformLocation("cx"); 46 | m_cyUniform = uniformLocation("cy"); 47 | } 48 | 49 | Diff& Diff::setRotation(Vector3 const& rotation) { 50 | setUniform(m_rotationUniform, rotation); 51 | return *this; 52 | } 53 | 54 | Diff& Diff::setTranslation(Vector3 const& translation) { 55 | setUniform(m_translationUniform, translation); 56 | return *this; 57 | } 58 | 59 | Diff& Diff::setCameraParameters(float fx, float fy, float cx, float cy) { 60 | setUniform(m_fxUniform, fx); 61 | setUniform(m_fyUniform, fy); 62 | setUniform(m_cxUniform, cx); 63 | setUniform(m_cyUniform, cy); 64 | return *this; 65 | } 66 | 67 | 68 | Diff& Diff::setProjectionTransformationMatrix(Mg::Matrix4 const& projTf) { 69 | setUniform(m_projTfUniform, projTf); 70 | return *this; 71 | } 72 | 73 | Diff& Diff::bindGroundTruthTexture(GL::Texture2D& texture) { 74 | texture.bind(0); 75 | return *this; 76 | } 77 | 78 | Diff& Diff::bindOptimizationTexture(GL::Texture2D& texture) { 79 | texture.bind(1); 80 | return *this; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /Shaders/Diff.frag: -------------------------------------------------------------------------------- 1 | //not for now 2 | //#extension GL_ARB_fragment_layer_viewport : require 3 | 4 | in vec2 interpolatedTextureCoordinates; 5 | 6 | in vec3 worldPosition; 7 | 8 | uniform float fx; 9 | uniform float fy; 10 | uniform float cx; 11 | uniform float cy; 12 | 13 | layout(binding = 0) 14 | uniform sampler2D groundTruthImage; 15 | 16 | layout(binding = 1) 17 | uniform sampler2D optimizationTexture; 18 | 19 | uniform vec3 rotation; 20 | 21 | uniform vec3 translation; 22 | 23 | layout(location = 0) 24 | out vec2 cost; 25 | 26 | layout(location = 1) 27 | out vec4 gradRotation; 28 | 29 | layout(location = 2) 30 | out vec4 gradTranslation; 31 | 32 | vec3 rotatePoint(in vec3 v, out mat3 jacRot){ 33 | const float x = rotation.x, y = rotation.y, z = rotation.z; 34 | const float x2 = x * x, y2 = y * y, z2 = z*z; 35 | const float theta2 = x2 + y2 + z2; 36 | const float theta = sqrt(theta2); 37 | const vec3 k = rotation / theta; 38 | const float cosTheta = cos(theta); 39 | const float sinTheta = sin(theta); 40 | const float subexpr1 = (1. - cosTheta) / theta2; 41 | const float subexpr2 = sinTheta / theta; 42 | 43 | /* jac is column major */ 44 | jacRot = mat3( 45 | x2 * subexpr1 + cosTheta , x * y * subexpr1 + z * subexpr2, -y * subexpr2 + x * z * subexpr1, 46 | x * y * subexpr1 - z * subexpr2, y2 * subexpr1 + cosTheta , x * subexpr2 + y * z * subexpr1, 47 | x * z * subexpr1 + y * subexpr2, -x * subexpr2 + y * z * subexpr1, z2 * subexpr1 + cosTheta); 48 | 49 | return v * cosTheta + cross(k, v) * sinTheta + k * dot(k, v) * (1. - cosTheta) + translation; 50 | } 51 | 52 | mat2x3 computeSobel(vec2 uv){ 53 | vec2 texelSize = 1.0 / vec2(textureSize(groundTruthImage, 0)); 54 | 55 | vec3 upperLeft = texture(groundTruthImage, uv + vec2(-texelSize.x, texelSize.y)).rgb; 56 | vec3 upperMiddle = texture(groundTruthImage, uv + vec2(0, texelSize.y)).rgb; 57 | vec3 upperRight = texture(groundTruthImage, uv + vec2(texelSize.x, texelSize.y)).rgb; 58 | vec3 left = texture(groundTruthImage, uv + vec2(-texelSize.x, 0)).rgb; 59 | vec3 right = texture(groundTruthImage, uv + vec2(texelSize.x, 0)).rgb; 60 | vec3 lowerLeft = texture(groundTruthImage, uv + vec2(-texelSize.x, -texelSize.y)).rgb; 61 | vec3 lowerMiddle = texture(groundTruthImage, uv + vec2(0, -texelSize.y)).rgb; 62 | vec3 lowerRight = texture(groundTruthImage, uv + vec2(texelSize.x, -texelSize.y)).rgb; 63 | 64 | vec3 derX = upperLeft + 2*left + lowerLeft - upperRight - 2*right - lowerRight; 65 | vec3 derY = upperLeft + 2*upperMiddle + upperRight - lowerRight - 2*lowerMiddle - lowerRight; 66 | 67 | return mat2x3(derX.x, derY.x, derX.y, derY.y, derX.z, derY.z); 68 | } 69 | 70 | void main() { 71 | 72 | vec3 color = texture(optimizationTexture, interpolatedTextureCoordinates).rgb; 73 | 74 | /* if there is no texture value, return early */ 75 | if(color == vec3(0)) { 76 | gradRotation = vec4(0); 77 | gradTranslation = vec4(0); 78 | cost = vec2(0); 79 | return; 80 | } 81 | 82 | vec2 uv = gl_FragCoord.xy/textureSize(groundTruthImage, 0); 83 | vec3 lossGrad = color.rgb - texture(groundTruthImage, uv).rgb; /* corresponds to a simple squared loss */ 84 | 85 | mat3 jacRot; 86 | vec3 p = rotatePoint(worldPosition.xyz, jacRot); 87 | 88 | mat3x2 jacProj = mat3x2( 89 | fx/p.z, 0, 90 | 0, fy/p.z, 91 | -fx*p.x/(p.z*p.z), -fy*p.y/(p.z*p.z) 92 | ); 93 | 94 | mat2x3 CwrtI = computeSobel(uv); 95 | 96 | gradRotation.xyz = lossGrad * CwrtI * jacProj * jacRot; 97 | gradTranslation.xyz = lossGrad * CwrtI * jacProj; /* jacobian wrt. Translation is the identity */ 98 | cost.x = 0.5*dot(lossGrad,lossGrad); 99 | 100 | cost.y = 1.; 101 | gradRotation.w = 1.; 102 | gradTranslation.w = 1.; 103 | } 104 | -------------------------------------------------------------------------------- /Shaders/Diff.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 05.02.20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "Types.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace Mg = Magnum; 15 | 16 | namespace TextureMapOptimization::Shaders { 17 | 18 | class Diff : public GL::AbstractShaderProgram { 19 | public: 20 | 21 | Diff(); 22 | 23 | Diff& setRotation(const Mg::Vector3& rot); 24 | 25 | Diff& setCameraParameters(float fx, float fy, float cx, float cy); 26 | 27 | Diff& setTranslation(Mg::Vector3 const& translation); 28 | 29 | Diff& setProjectionTransformationMatrix(Mg::Matrix4 const& projTf); 30 | 31 | Diff& bindGroundTruthTexture(GL::Texture2D& texture); 32 | 33 | Diff& bindOptimizationTexture(GL::Texture2D& texture); 34 | 35 | private: 36 | Int m_rotationUniform, 37 | m_translationUniform, 38 | m_projTfUniform, 39 | m_fxUniform, 40 | m_fyUniform, 41 | m_cxUniform, 42 | m_cyUniform; 43 | }; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Shaders/Diff.vert: -------------------------------------------------------------------------------- 1 | layout(location = POSITION_ATTRIBUTE_LOCATION) 2 | in highp vec4 position; 3 | 4 | layout(location = TEXTURECOORDINATES_ATTRIBUTE_LOCATION) 5 | in mediump vec2 textureCoordinates; 6 | 7 | uniform mat4 projectionTransformationMatrix; 8 | 9 | out vec2 interpolatedTextureCoordinates; 10 | out vec3 worldPosition; 11 | void main() { 12 | gl_Position = projectionTransformationMatrix*position; 13 | interpolatedTextureCoordinates = textureCoordinates; 14 | worldPosition = position.xyz; 15 | } -------------------------------------------------------------------------------- /Shaders/FullScreenTriangle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/4/20. 3 | // 4 | 5 | #include "FullScreenTriangle.h" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace Magnum; 16 | using namespace Corrade; 17 | 18 | namespace TextureMapOptimization::Shaders { 19 | 20 | FullScreenTriangle::FullScreenTriangle() { 21 | MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL450); 22 | 23 | const Utility::Resource rs{"tmo-data"}; 24 | 25 | GL::Shader vert{GL::Version::GL450, GL::Shader::Type::Vertex}; 26 | GL::Shader frag{GL::Version::GL450, GL::Shader::Type::Fragment}; 27 | 28 | vert.addSource(rs.get("FullScreenTriangle.vert")); 29 | 30 | frag.addSource(rs.get("FullScreenTriangle.frag")); 31 | 32 | CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); 33 | 34 | attachShaders({vert, frag}); 35 | 36 | CORRADE_INTERNAL_ASSERT_OUTPUT(link()); 37 | } 38 | 39 | FullScreenTriangle& FullScreenTriangle::bindTexture(GL::Texture2D& texture) { 40 | texture.bind(0); 41 | return *this; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /Shaders/FullScreenTriangle.frag: -------------------------------------------------------------------------------- 1 | layout(binding = 0) 2 | uniform highp sampler2D image; 3 | 4 | in highp vec2 interpolatedTextureCoordinate; 5 | 6 | layout(location = 0) 7 | out lowp vec4 fragmentColor; 8 | 9 | void main() { 10 | fragmentColor = texture(image, interpolatedTextureCoordinate); 11 | } -------------------------------------------------------------------------------- /Shaders/FullScreenTriangle.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/4/20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace TextureMapOptimization::Shaders { 12 | 13 | class FullScreenTriangle : public Magnum::GL::AbstractShaderProgram { 14 | public: 15 | using Position = Magnum::Shaders::Generic3D::Position; 16 | 17 | explicit FullScreenTriangle(Magnum::NoCreateT) : Magnum::GL::AbstractShaderProgram{Magnum::NoCreate} {}; 18 | 19 | explicit FullScreenTriangle(); 20 | 21 | FullScreenTriangle& bindTexture(Magnum::GL::Texture2D& texture); 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Shaders/FullScreenTriangle.vert: -------------------------------------------------------------------------------- 1 | layout(location = 0) 2 | in highp vec4 position; 3 | 4 | out highp vec2 interpolatedTextureCoordinate; 5 | 6 | void main() 7 | { 8 | gl_Position = vec4((gl_VertexID == 2) ? 3.0 : -1.0, (gl_VertexID == 1) ? -3.0 : 1.0, 0.0, 1.0); 9 | interpolatedTextureCoordinate = gl_Position.xy*0.5 + vec2(0.5); 10 | } -------------------------------------------------------------------------------- /Shaders/Reduction.comp: -------------------------------------------------------------------------------- 1 | layout(local_size_x = 1, local_size_y = 1) in; 2 | 3 | layout(rg32f, binding = 0) 4 | uniform readonly image2D costInput; 5 | 6 | layout(rg32f, binding = 1) 7 | uniform writeonly image2D costOutput; 8 | 9 | layout(rgba32f, binding = 2) 10 | uniform readonly image2D rotationInput; 11 | 12 | layout(rgba32f, binding = 3) 13 | uniform writeonly image2D rotationOutput; 14 | 15 | layout(rgba32f, binding = 4) 16 | uniform readonly image2D translationInput; 17 | 18 | layout(rgba32f, binding = 5) 19 | uniform writeonly image2D translationOutput; 20 | 21 | void main() 22 | { 23 | ivec2 coordOutput = ivec2(gl_GlobalInvocationID.xy); 24 | ivec2 coordInput = BLOCK_SIZE * coordOutput; 25 | 26 | vec2 sumCost = vec2(0); 27 | vec4 sumRotation = vec4(0); 28 | vec4 sumTranslation = vec4(0); 29 | 30 | float minValue, maxValue; 31 | 32 | for(int i = 0; i < BLOCK_SIZE; ++i){ 33 | for(int j = 0; j < BLOCK_SIZE; ++j){ 34 | ivec2 offset = ivec2(i,j); 35 | sumCost += imageLoad(costInput, coordInput + offset).xy; 36 | sumRotation += imageLoad(rotationInput, coordInput + offset); 37 | sumTranslation += imageLoad(translationInput, coordInput + offset); 38 | } 39 | } 40 | 41 | imageStore(costOutput, coordOutput, vec4(sumCost, 0, 0)); 42 | imageStore(rotationOutput, coordOutput, sumRotation); 43 | imageStore(translationOutput, coordOutput, sumTranslation); 44 | } 45 | -------------------------------------------------------------------------------- /Shaders/Reduction.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/21/20. 3 | // 4 | 5 | #include "Reduction.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace TextureMapOptimization::Shaders { 18 | 19 | using namespace Magnum; 20 | using namespace Corrade; 21 | 22 | Reduction::Reduction(UnsignedInt stepSize) { 23 | MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL460); 24 | 25 | Utility::Resource rs{"tmo-data"}; 26 | 27 | GL::Shader comp{GL::Version::GL460, GL::Shader::Type::Compute}; 28 | 29 | //switch(flag) { 30 | // case Flag::MinMaxCost : 31 | // comp.addSource("#define COMPUTE_MIN_MAX_COST\n"); 32 | // break; 33 | // case Flag::MinMaxRotation : 34 | // comp.addSource("#define COMPUTE_MIN_MAX_ROTATION\n"); 35 | // break; 36 | // case Flag::MinMaxTranslation : 37 | // comp.addSource("#define COMPUTE_MIN_MAX_ROTATION\n"); 38 | // break; 39 | // default : break; 40 | //} 41 | 42 | comp.addSource(Utility::formatString("#define BLOCK_SIZE {}\n", 1u << stepSize)) 43 | .addSource(rs.get("Reduction.comp")); 44 | 45 | CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({comp})); 46 | 47 | attachShaders({comp}); 48 | 49 | CORRADE_INTERNAL_ASSERT_OUTPUT(link()); 50 | } 51 | 52 | Reduction& Reduction::reduce(Vector2& cost, Vector4& rot, Vector4& trans) { 53 | 54 | auto& costTex = *m_costTex; 55 | auto& rotTex = *m_rotTex; 56 | auto& transTex = *m_transTex; 57 | 58 | size_t currentMipLevel = 0; 59 | constexpr size_t maxPixelCount = 100; 60 | 61 | while(costTex.imageSize(currentMipLevel).product() > maxPixelCount) { 62 | costTex.bindImage(CostInputUnit, currentMipLevel, GL::ImageAccess::ReadOnly, GL::ImageFormat::RG32F); 63 | costTex.bindImage(CostOutputUnit, currentMipLevel+m_stepSize, GL::ImageAccess::WriteOnly, GL::ImageFormat::RG32F); 64 | 65 | rotTex.bindImage(RotationInputUnit, currentMipLevel, GL::ImageAccess::ReadOnly, GL::ImageFormat::RGBA32F); 66 | rotTex.bindImage(RotationOutputUnit, currentMipLevel+m_stepSize, GL::ImageAccess::WriteOnly, GL::ImageFormat::RGBA32F); 67 | 68 | transTex.bindImage(TranslationInputUnit, currentMipLevel, GL::ImageAccess::ReadOnly, GL::ImageFormat::RGBA32F); 69 | transTex.bindImage(TranslationOutputUnit, currentMipLevel+m_stepSize, GL::ImageAccess::WriteOnly, GL::ImageFormat::RGBA32F); 70 | 71 | Vector2ui size{costTex.imageSize(currentMipLevel)}; 72 | Vector3ui wgCount{size.x(), size.y(), 1}; 73 | dispatchCompute(wgCount); 74 | 75 | currentMipLevel += m_stepSize; 76 | } 77 | 78 | return *this; 79 | } 80 | 81 | 82 | Reduction& Reduction::setTextures(GL::Texture2D& cost, GL::Texture2D& rot, GL::Texture2D& trans) { 83 | m_costTex = &cost; 84 | m_rotTex = &rot; 85 | m_transTex = &trans; 86 | return *this; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /Shaders/Reduction.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/21/20. 3 | // 4 | 5 | #ifndef TEXTUREOPTIMIZATION_REDUCTION_H 6 | #define TEXTUREOPTIMIZATION_REDUCTION_H 7 | 8 | #include "ScopedTimer.h" 9 | #include "Types.h" 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | namespace Mg = Magnum; 18 | namespace Cr = Corrade; 19 | 20 | namespace TextureMapOptimization::Shaders { 21 | 22 | class Reduction : public GL::AbstractShaderProgram { 23 | public: 24 | 25 | enum Flag { 26 | MinMaxCost = 1, 27 | MinMaxRotation = 2, 28 | MinMaxTranslation = 3, 29 | }; 30 | 31 | explicit Reduction(UnsignedInt step = 2); 32 | 33 | explicit Reduction(Mg::NoCreateT) : GL::AbstractShaderProgram{Mg::NoCreate} {}; 34 | 35 | Reduction& setTextures(GL::Texture2D&, GL::Texture2D&, GL::Texture2D&); 36 | 37 | Reduction& reduce(Vector2& cost, Vector4& rot, Vector4& trans); 38 | 39 | private: 40 | 41 | enum { 42 | CostInputUnit = 0, 43 | CostOutputUnit = 1, 44 | RotationInputUnit = 2, 45 | RotationOutputUnit = 3, 46 | TranslationInputUnit = 4, 47 | TranslationOutputUnit = 5, 48 | }; 49 | 50 | 51 | GL::Texture2D* m_costTex, *m_rotTex, *m_transTex; 52 | UnsignedInt m_stepSize = 2; 53 | }; 54 | 55 | } 56 | 57 | #endif //TEXTUREOPTIMIZATION_REDUCTION_H 58 | -------------------------------------------------------------------------------- /Shaders/Remap.comp: -------------------------------------------------------------------------------- 1 | layout(local_size_x = 1, local_size_y = 1) in; 2 | 3 | layout(rgba32f, binding = 0) 4 | uniform readonly image2D image; 5 | 6 | layout(rgba32f, binding = 1) 7 | uniform readonly image2D textureCoordinates; 8 | 9 | layout(r32f, binding = 2) 10 | uniform coherent image2D texR; 11 | 12 | layout(r32f, binding = 3) 13 | uniform coherent image2D texG; 14 | 15 | layout(r32f, binding = 4) 16 | uniform coherent image2D texB; 17 | 18 | layout(r32f, binding = 5) 19 | uniform coherent image2D texA; 20 | 21 | void main() 22 | { 23 | ivec2 coords = ivec2(gl_GlobalInvocationID.xy); 24 | vec4 color = imageLoad(image, coords); 25 | vec2 texCoordsInterpolated = vec2(imageSize(texR)) * imageLoad(textureCoordinates, coords).rg; 26 | ivec2 texCoords = ivec2(round(texCoordsInterpolated.x), round(texCoordsInterpolated.y)); 27 | //imageStore(tex, texCoords, color); 28 | imageAtomicAdd(texR, texCoords, color.r); 29 | imageAtomicAdd(texG, texCoords, color.g); 30 | imageAtomicAdd(texB, texCoords, color.b); 31 | imageAtomicAdd(texA, texCoords, 1.); 32 | } -------------------------------------------------------------------------------- /Shaders/Remap.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/5/20. 3 | // 4 | 5 | #include "Remap.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | using namespace Magnum; 18 | 19 | namespace TextureMapOptimization::Shaders{ 20 | 21 | Remap::Remap() { 22 | MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL460); 23 | 24 | Utility::Resource rs{"tmo-data"}; 25 | 26 | GL::Shader comp{GL::Version::GL460, GL::Shader::Type::Compute}; 27 | 28 | 29 | comp.addSource("#extension GL_NV_shader_atomic_float : require\n") 30 | .addSource(rs.get("Remap.comp")); 31 | 32 | CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({comp})); 33 | 34 | attachShaders({comp}); 35 | 36 | CORRADE_INTERNAL_ASSERT_OUTPUT(link()); 37 | } 38 | 39 | 40 | Remap& Remap::bindImage(GL::Texture2D& image) { 41 | image.bindImage(m_imageUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::RGBA32F); 42 | return *this; 43 | } 44 | 45 | Remap& Remap::bindTextureCoordinates(GL::Texture2D& texCoords){ 46 | texCoords.bindImage(m_texCoordsUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::RGBA32F); 47 | return *this; 48 | } 49 | 50 | Remap& Remap::bindTextureR(GL::Texture2D& texture){ 51 | texture.bindImage(m_textureRUnit, 0, GL::ImageAccess::ReadWrite, GL::ImageFormat::R32F); 52 | return *this; 53 | } 54 | 55 | Remap& Remap::bindTextureG(GL::Texture2D& texture){ 56 | texture.bindImage(m_textureGUnit, 0, GL::ImageAccess::ReadWrite, GL::ImageFormat::R32F); 57 | return *this; 58 | } 59 | 60 | Remap& Remap::bindTextureB(GL::Texture2D& texture){ 61 | texture.bindImage(m_textureBUnit, 0, GL::ImageAccess::ReadWrite, GL::ImageFormat::R32F); 62 | return *this; 63 | } 64 | 65 | Remap& Remap::bindTextureA(GL::Texture2D& texture){ 66 | texture.bindImage(m_textureAUnit, 0, GL::ImageAccess::ReadWrite, GL::ImageFormat::R32F); 67 | return *this; 68 | } 69 | 70 | Remap& Remap::bindTextureRgba(Magnum::GL::Texture2D& rgba){ 71 | rgba.bindImage(6, 0, GL::ImageAccess::ReadWrite, GL::ImageFormat::RGBA32F); 72 | return *this; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /Shaders/Remap.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/5/20. 3 | // 4 | 5 | #ifndef TEXTUREOPTIMIZATION_REMAP_H 6 | #define TEXTUREOPTIMIZATION_REMAP_H 7 | 8 | #include 9 | #include 10 | 11 | namespace TextureMapOptimization::Shaders { 12 | 13 | class Remap : public Magnum::GL::AbstractShaderProgram { 14 | public: 15 | 16 | enum class ImageUnit : Magnum::UnsignedInt { 17 | Image = 0, 18 | TextureCoordinate = 1, 19 | Texture = 2 20 | }; 21 | 22 | explicit Remap(); 23 | 24 | explicit Remap(Magnum::NoCreateT) : Magnum::GL::AbstractShaderProgram{Magnum::NoCreate} {}; 25 | 26 | Remap& bindImage(Magnum::GL::Texture2D&); 27 | 28 | Remap& bindTextureCoordinates(Magnum::GL::Texture2D&); 29 | 30 | Remap& bindTextureR(Magnum::GL::Texture2D&); 31 | Remap& bindTextureG(Magnum::GL::Texture2D&); 32 | Remap& bindTextureB(Magnum::GL::Texture2D&); 33 | Remap& bindTextureA(Magnum::GL::Texture2D&); 34 | 35 | Remap& bindTextureRgba(Magnum::GL::Texture2D& rgba); 36 | 37 | private: 38 | 39 | Magnum::UnsignedInt m_imageUnit = 0; 40 | Magnum::UnsignedInt m_texCoordsUnit = 1; 41 | Magnum::UnsignedInt m_textureRUnit = 2; 42 | Magnum::UnsignedInt m_textureGUnit = 3; 43 | Magnum::UnsignedInt m_textureBUnit = 4; 44 | Magnum::UnsignedInt m_textureAUnit = 5; 45 | }; 46 | 47 | } 48 | 49 | #endif //TEXTUREOPTIMIZATION_REMAP_H 50 | -------------------------------------------------------------------------------- /Shaders/TextureCoordinates.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/2/20. 3 | // 4 | 5 | #include "TextureCoordinates.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | using namespace Magnum; 17 | 18 | namespace TextureMapOptimization::Shaders{ 19 | 20 | TextureCoordinates::TextureCoordinates() { 21 | MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL460); 22 | 23 | Utility::Resource rs{"tmo-data"}; 24 | 25 | GL::Shader vert{GL::Version::GL460, GL::Shader::Type::Vertex}; 26 | GL::Shader frag{GL::Version::GL460, GL::Shader::Type::Fragment}; 27 | 28 | vert.addSource(rs.get("TextureCoordinates.vert")); 29 | frag.addSource(rs.get("TextureCoordinates.frag")); 30 | 31 | CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag})); 32 | 33 | attachShaders({vert, frag}); 34 | 35 | CORRADE_INTERNAL_ASSERT_OUTPUT(link()); 36 | 37 | m_transformationProjectionMatrix = uniformLocation("transformationProjectionMatrix"); 38 | m_numPrimitives = uniformLocation("numPrimitives"); 39 | } 40 | 41 | TextureCoordinates& TextureCoordinates::setTransformationProjectionMatrix(Mg::Matrix4 const& tf){ 42 | setUniform(m_transformationProjectionMatrix, tf); 43 | return *this; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /Shaders/TextureCoordinates.frag: -------------------------------------------------------------------------------- 1 | 2 | in vec2 interpolatedTextureCoordinates; 3 | 4 | layout(location = 0) 5 | out vec4 textureCoordinate; 6 | 7 | void main() 8 | { 9 | textureCoordinate = vec4(interpolatedTextureCoordinates,0,1); 10 | } -------------------------------------------------------------------------------- /Shaders/TextureCoordinates.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/2/20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | namespace Mg = Magnum; 11 | 12 | namespace TextureMapOptimization::Shaders{ 13 | 14 | class TextureCoordinates : public Mg::GL::AbstractShaderProgram { 15 | public: 16 | 17 | enum: Mg::UnsignedInt { 18 | ColorOutput = Mg::Shaders::Generic<3>::ColorOutput, 19 | }; 20 | 21 | explicit TextureCoordinates(); 22 | explicit TextureCoordinates(Mg::NoCreateT) : Mg::GL::AbstractShaderProgram{Mg::NoCreate} {}; 23 | 24 | TextureCoordinates& setTransformationProjectionMatrix(Mg::Matrix4 const&); 25 | 26 | private: 27 | 28 | Mg::Int m_transformationProjectionMatrix; 29 | Mg::Int m_numPrimitives; 30 | }; 31 | 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /Shaders/TextureCoordinates.vert: -------------------------------------------------------------------------------- 1 | layout(location = 0) 2 | in vec4 position; 3 | 4 | layout(location = 1) 5 | in vec2 textureCoordinates; 6 | 7 | out vec2 interpolatedTextureCoordinates; 8 | 9 | layout(location = 0) 10 | uniform mat4 transformationProjectionMatrix; 11 | 12 | void main() 13 | { 14 | interpolatedTextureCoordinates = textureCoordinates; 15 | gl_Position = transformationProjectionMatrix * position; 16 | } -------------------------------------------------------------------------------- /Shaders/Vis.comp: -------------------------------------------------------------------------------- 1 | layout(local_size_x = 1, local_size_y = 1) in; 2 | 3 | uniform float scale; 4 | uniform float offset; 5 | uniform bool useCost; 6 | 7 | layout(binding = 0) 8 | uniform sampler2D colorMap; 9 | 10 | layout(rgba32f, binding = 1) 11 | uniform writeonly image2D image; 12 | 13 | layout(rg32f, binding = 2) 14 | uniform readonly image2D cost; 15 | 16 | layout(rgba32f, binding = 3) 17 | uniform readonly image2D gradient; 18 | 19 | void main() 20 | { 21 | ivec2 coords = ivec2(gl_GlobalInvocationID.xy); 22 | 23 | float value; 24 | if(useCost) 25 | value = imageLoad(cost, coords).x; 26 | else 27 | value = length(imageLoad(gradient, coords).xyz); 28 | 29 | float colorMapCoord = scale*value + offset; 30 | vec4 color = texture(colorMap, vec2(colorMapCoord,0)); 31 | imageStore(image, coords, color); 32 | } 33 | -------------------------------------------------------------------------------- /Shaders/Vis.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 05.02.20. 3 | // 4 | 5 | #include "Vis.h" 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace Cr = Corrade; 17 | 18 | namespace TextureMapOptimization::Shaders { 19 | 20 | Vis::Vis() { 21 | MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL450); 22 | 23 | Cr::Utility::Resource rs{"tmo-data"}; 24 | 25 | GL::Shader comp{GL::Version::GL460, GL::Shader::Type::Compute}; 26 | 27 | comp.addSource(rs.get("Vis.comp")); 28 | 29 | CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({comp})); 30 | 31 | attachShaders({comp}); 32 | 33 | CORRADE_INTERNAL_ASSERT_OUTPUT(link()); 34 | 35 | m_scaleUniform = uniformLocation("scale"); 36 | m_offsetUniform = uniformLocation("offset"); 37 | m_useCostUniform = uniformLocation("useCost"); 38 | } 39 | 40 | Vis& Vis::bindColorMap(GL::Texture2D& texture) { 41 | texture.bind(ColorMapUnit); 42 | return *this; 43 | } 44 | 45 | Vis& Vis::bindOutputImage(GL::Texture2D& texture) { 46 | texture.bindImage(OutputImageUnit, 0, GL::ImageAccess::WriteOnly, GL::ImageFormat::RGBA32F); 47 | return *this; 48 | } 49 | 50 | Vis& Vis::bindCostImage(GL::Texture2D& texture) { 51 | texture.bindImage(CostImageUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::RG32F); 52 | setUniform(m_useCostUniform, true); 53 | return *this; 54 | } 55 | 56 | Vis& Vis::bindGradientImage(GL::Texture2D& texture) { 57 | texture.bindImage(GradientImageUnit, 0, GL::ImageAccess::ReadOnly, GL::ImageFormat::RGBA32F); 58 | setUniform(m_useCostUniform, false); 59 | return *this; 60 | } 61 | 62 | Vis& Vis::setColorMapTransform(float scale, float offset) { 63 | setUniform(m_scaleUniform, scale); 64 | setUniform(m_offsetUniform, offset); 65 | return *this; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Shaders/Vis.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 05.02.20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "Types.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace Mg = Magnum; 13 | 14 | namespace TextureMapOptimization::Shaders { 15 | 16 | class Vis : public GL::AbstractShaderProgram { 17 | public: 18 | 19 | Vis(); 20 | 21 | Vis& bindOutputImage(GL::Texture2D& texture); 22 | 23 | Vis& bindCostImage(GL::Texture2D& texture); 24 | 25 | Vis& bindGradientImage(GL::Texture2D& texture); 26 | 27 | Vis& bindColorMap(GL::Texture2D& texture); 28 | 29 | Vis& setColorMapTransform(float scale, float offset); 30 | 31 | private: 32 | 33 | enum { 34 | ColorMapUnit = 0, 35 | OutputImageUnit = 1, 36 | CostImageUnit = 2, 37 | GradientImageUnit = 3, 38 | }; 39 | 40 | Int m_scaleUniform, 41 | m_offsetUniform, 42 | m_useCostUniform; 43 | }; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Shaders/generic.glsl: -------------------------------------------------------------------------------- 1 | #define POSITION_ATTRIBUTE_LOCATION 0 2 | #define TEXTURECOORDINATES_ATTRIBUTE_LOCATION 1 3 | #define COLOR_ATTRIBUTE_LOCATION 2 4 | #define TANGENT_ATTRIBUTE_LOCATION 3 5 | #define BITANGENT_ATTRIBUTE_LOCATION 4 /* also ObjectId */ 6 | #define OBJECT_ID_ATTRIBUTE_LOCATION 4 /* also Bitangent */ 7 | #define NORMAL_ATTRIBUTE_LOCATION 5 8 | 9 | #define TRANSFORMATION_MATRIX_ATTRIBUTE_LOCATION 8 10 | #define NORMAL_MATRIX_ATTRIBUTE_LOCATION 12 11 | #define TEXTURE_OFFSET_ATTRIBUTE_LOCATION 15 12 | 13 | /* Outputs */ 14 | #define COLOR_OUTPUT_ATTRIBUTE_LOCATION 0 15 | #define OBJECT_ID_OUTPUT_ATTRIBUTE_LOCATION 1 -------------------------------------------------------------------------------- /Shaders/resources.conf: -------------------------------------------------------------------------------- 1 | group = tmo-data 2 | 3 | [file] 4 | filename = Diff.frag 5 | 6 | [file] 7 | filename = Diff.vert 8 | 9 | [file] 10 | filename = TextureCoordinates.frag 11 | 12 | [file] 13 | filename = TextureCoordinates.vert 14 | 15 | [file] 16 | filename = FullScreenTriangle.frag 17 | 18 | [file] 19 | filename = FullScreenTriangle.vert 20 | 21 | [file] 22 | filename = Remap.comp 23 | 24 | [file] 25 | filename = Combine.comp 26 | 27 | [file] 28 | filename = Reduction.comp 29 | 30 | [file] 31 | filename = Vis.comp 32 | 33 | [file] 34 | filename = generic.glsl -------------------------------------------------------------------------------- /Utilities/Allocate.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 10/10/20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace TextureMapOptimization { 10 | 11 | inline void* allocateBuffer(size_t Size, size_t Alignment) { 12 | return ::operator new(Size 13 | #ifdef __cpp_aligned_new 14 | , 15 | std::align_val_t(Alignment) 16 | #endif 17 | ); 18 | } 19 | 20 | 21 | inline void deallocateBuffer(void* Ptr, size_t Size, size_t Alignment) { 22 | ::operator delete(Ptr 23 | #ifdef __cpp_sized_deallocation 24 | , 25 | Size 26 | #endif 27 | #ifdef __cpp_aligned_new 28 | , 29 | std::align_val_t(Alignment) 30 | #endif 31 | ); 32 | } 33 | 34 | 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /Utilities/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(Utilities INTERFACE) 2 | 3 | target_sources(Utilities INTERFACE 4 | UniqueFunction.h 5 | Utilities.h 6 | Types.h 7 | RemoveIf.h 8 | Allocate.h 9 | Utilities.h) 10 | 11 | target_include_directories(Utilities INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 12 | target_link_libraries(Utilities INTERFACE Corrade::Containers) 13 | add_library(Tmo::Utilities ALIAS Utilities) 14 | -------------------------------------------------------------------------------- /Utilities/RemoveIf.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 9/17/20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace TextureMapOptimization { 10 | 11 | template 12 | constexpr InputIt findIf(InputIt first, InputIt last, UnaryPredicate p) { 13 | for(; first != last; ++first) { 14 | if(p(*first)) { 15 | return first; 16 | } 17 | } 18 | return last; 19 | } 20 | 21 | template 22 | ForwardIt removeIf(ForwardIt first, ForwardIt last, UnaryPredicate p) 23 | { 24 | first = findIf(first, last, p); 25 | if (first != last) 26 | for(ForwardIt i = first; ++i != last; ) 27 | if (!p(*i)) 28 | *first++ = std::move(*i); 29 | return first; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Utilities/Types.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 9/14/20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace Corrade::Containers; 13 | 14 | using Magnum::UnsignedInt; 15 | using Magnum::Float; 16 | using Magnum::Double; 17 | using Magnum::Int; 18 | 19 | using Magnum::Vector3; 20 | using Magnum::Vector4; 21 | using Magnum::Vector3i; 22 | using Magnum::Vector3ui; 23 | using Magnum::Vector2; 24 | using Magnum::Vector2i; 25 | using Magnum::Vector2ui; 26 | using Magnum::Vector3ub; 27 | using Magnum::Vector3d; 28 | using Magnum::Matrix3; 29 | using Magnum::Matrix4; 30 | using Magnum::Color3; 31 | using Magnum::Color3ub; 32 | using Magnum::Color4; 33 | using Magnum::Color4ub; 34 | using Magnum::Range2D; 35 | using Magnum::Range2Di; 36 | using Magnum::Quaternion; 37 | using Magnum::DualQuaternion; 38 | 39 | using Magnum::Rad; 40 | using Magnum::Radd; 41 | using Magnum::Deg; 42 | 43 | using Magnum::Debug; 44 | 45 | namespace Math = Magnum::Math; 46 | namespace GL = Magnum::GL; 47 | 48 | namespace tmo { 49 | constexpr size_t Invalid = ~size_t{0}; 50 | } 51 | -------------------------------------------------------------------------------- /Utilities/UniqueFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Allocate.h" 4 | 5 | #include 6 | 7 | namespace TextureMapOptimization { 8 | 9 | template 10 | class UniqueFunction; 11 | 12 | template 13 | class UniqueFunction { 14 | public: 15 | 16 | UniqueFunction() = default; 17 | 18 | UniqueFunction(std::nullptr_t) {} 19 | 20 | template 21 | UniqueFunction(Callable&& f) { 22 | 23 | erased = allocateBuffer(sizeof(Callable), alignof(Callable)); 24 | ::new(erased) Callable((Callable&&) f); 25 | 26 | destroy = +[](void* e) { 27 | static_cast(e)->~Callable(); 28 | deallocateBuffer(e, sizeof(Callable), alignof(Callable)); 29 | }; 30 | 31 | call = +[](void* e, Params... params) -> Ret { 32 | return (*static_cast(e))(params...); 33 | }; 34 | } 35 | 36 | UniqueFunction& operator=(UniqueFunction&& other) noexcept { 37 | other.swap(*this); 38 | return *this; 39 | } 40 | 41 | UniqueFunction(UniqueFunction&& other) noexcept { 42 | other.swap(*this); 43 | } 44 | 45 | void swap(UniqueFunction& other) { 46 | std::swap(erased, other.erased); 47 | std::swap(destroy, other.destroy); 48 | std::swap(call, other.call); 49 | } 50 | 51 | Ret operator()(Params ...params) const { 52 | return call(erased, (Params&&) (params)...); 53 | } 54 | 55 | explicit operator bool() const { return erased; } 56 | 57 | ~UniqueFunction() { 58 | if(destroy) destroy(erased); 59 | } 60 | 61 | private: 62 | 63 | void* erased = nullptr; 64 | void (* destroy)(void*) = nullptr; 65 | Ret (* call)(void*, Params...) = nullptr; 66 | }; 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Utilities/Utilities.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 7/23/20. 3 | // 4 | 5 | #pragma once 6 | 7 | template class UniqueFunction; 8 | 9 | -------------------------------------------------------------------------------- /Viewer/ArcBall.cpp: -------------------------------------------------------------------------------- 1 | #include "ArcBall.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace Magnum; 8 | 9 | namespace { 10 | 11 | /* Project a point in NDC onto the arcball sphere */ 12 | Quaternion ndcToArcBall(const Vector2& p) { 13 | const Float dist = Math::dot(p, p); 14 | 15 | /* Point is on sphere */ 16 | if(dist <= 1.0f) 17 | return {{p.x(), p.y(), Math::sqrt(1.0f - dist)}, 0.0f}; 18 | 19 | /* Point is outside sphere */ 20 | else { 21 | const Vector2 proj = p.normalized(); 22 | return {{proj.x(), proj.y(), 0.0f}, 0.0f}; 23 | } 24 | } 25 | 26 | } 27 | 28 | ArcBall::ArcBall(const Vector3& eye, const Vector3& viewCenter, 29 | const Vector3& upDir, Deg fov, const Vector2i& windowSize): 30 | _fov{fov}, _windowSize{windowSize} 31 | { 32 | setViewParameters(eye, viewCenter, upDir); 33 | } 34 | 35 | void ArcBall::setViewParameters(const Vector3& eye, const Vector3& viewCenter, 36 | const Vector3& upDir) 37 | { 38 | const Vector3 dir = viewCenter - eye; 39 | Vector3 zAxis = dir.normalized(); 40 | Vector3 xAxis = (Math::cross(zAxis, upDir.normalized())).normalized(); 41 | Vector3 yAxis = (Math::cross(xAxis, zAxis)).normalized(); 42 | xAxis = (Math::cross(zAxis, yAxis)).normalized(); 43 | 44 | _targetPosition = -viewCenter; 45 | _targetZooming = -dir.length(); 46 | _targetQRotation = Quaternion::fromMatrix( 47 | Matrix3x3{xAxis, yAxis, -zAxis}.transposed()).normalized(); 48 | 49 | _positionT0 = _currentPosition = _targetPosition; 50 | _zoomingT0 = _currentZooming = _targetZooming; 51 | _qRotationT0 = _currentQRotation = _targetQRotation; 52 | 53 | updateInternalTransformations(); 54 | } 55 | 56 | void ArcBall::reset() { 57 | _targetPosition = _positionT0; 58 | _targetZooming = _zoomingT0; 59 | _targetQRotation = _qRotationT0; 60 | } 61 | 62 | void ArcBall::setLagging(const Float lagging) { 63 | CORRADE_INTERNAL_ASSERT(lagging >= 0.0f && lagging < 1.0f); 64 | _lagging = lagging; 65 | } 66 | 67 | void ArcBall::initTransformation(const Vector2i& mousePos) { 68 | _prevMousePosNDC = screenCoordToNDC(mousePos); 69 | } 70 | 71 | void ArcBall::rotate(const Vector2i& mousePos) { 72 | const Vector2 mousePosNDC = screenCoordToNDC(mousePos); 73 | const Quaternion currentQRotation = ndcToArcBall(mousePosNDC); 74 | const Quaternion prevQRotation = ndcToArcBall(_prevMousePosNDC); 75 | _prevMousePosNDC = mousePosNDC; 76 | _targetQRotation = 77 | (currentQRotation*prevQRotation*_targetQRotation).normalized(); 78 | } 79 | 80 | void ArcBall::translate(const Vector2i& mousePos) { 81 | const Vector2 mousePosNDC = screenCoordToNDC(mousePos); 82 | const Vector2 translationNDC = mousePosNDC - _prevMousePosNDC; 83 | _prevMousePosNDC = mousePosNDC; 84 | translateDelta(translationNDC); 85 | } 86 | 87 | void ArcBall::translateDelta(const Vector2& translationNDC) { 88 | /* Half size of the screen viewport at the view center and perpendicular 89 | with the viewDir */ 90 | const Float hh = Math::abs(_targetZooming)*Math::tan(_fov*0.5f); 91 | const Float hw = hh*Vector2{_windowSize}.aspectRatio(); 92 | 93 | _targetPosition += _inverseView.transformVector( 94 | {translationNDC.x()*hw, translationNDC.y()*hh, 0.0f}); 95 | } 96 | 97 | void ArcBall::zoom(const Float delta) { 98 | _targetZooming += delta; 99 | } 100 | 101 | bool ArcBall::updateTransformation() { 102 | const Vector3 diffViewCenter = _targetPosition - _currentPosition; 103 | const Quaternion diffRotation = _targetQRotation - _currentQRotation; 104 | const Float diffZooming = _targetZooming - _currentZooming; 105 | 106 | const Float dViewCenter = Math::dot(diffViewCenter, diffViewCenter); 107 | const Float dRotation = Math::dot(diffRotation, diffRotation); 108 | const Float dZooming = diffZooming * diffZooming; 109 | 110 | /* Nothing change */ 111 | if(dViewCenter < 1.0e-10f && 112 | dRotation < 1.0e-10f && 113 | dZooming < 1.0e-10f) { 114 | return false; 115 | } 116 | 117 | /* Nearly done: just jump directly to the target */ 118 | if(dViewCenter < 1.0e-6f && 119 | dRotation < 1.0e-6f && 120 | dZooming < 1.0e-6f) { 121 | _currentPosition = _targetPosition; 122 | _currentQRotation = _targetQRotation; 123 | _currentZooming = _targetZooming; 124 | 125 | /* Interpolate between the current transformation and the target 126 | transformation */ 127 | } else { 128 | const Float t = 1 - _lagging; 129 | _currentPosition = Math::lerp(_currentPosition, _targetPosition, t); 130 | _currentZooming = Math::lerp(_currentZooming, _targetZooming, t); 131 | _currentQRotation = Math::slerpShortestPath( 132 | _currentQRotation, _targetQRotation, t); 133 | } 134 | 135 | updateInternalTransformations(); 136 | return true; 137 | } 138 | 139 | void ArcBall::updateInternalTransformations() { 140 | _view = DualQuaternion::translation(Vector3::zAxis(_currentZooming))* 141 | DualQuaternion{_currentQRotation}* 142 | DualQuaternion::translation(_currentPosition); 143 | _inverseView = _view.inverted(); 144 | } 145 | 146 | Vector2 ArcBall::screenCoordToNDC(const Vector2i& mousePos) const { 147 | return {mousePos.x()*2.0f/_windowSize.x() - 1.0f, 148 | 1.0f - 2.0f*mousePos.y()/ _windowSize.y()}; 149 | } 150 | 151 | 152 | -------------------------------------------------------------------------------- /Viewer/ArcBall.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Types.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* Implementation of Ken Shoemake's arcball camera with smooth navigation 12 | feature: https://www.talisman.org/~erlkonig/misc/shoemake92-arcball.pdf */ 13 | class ArcBall { 14 | public: 15 | ArcBall(const Vector3& cameraPosition, const Vector3& viewCenter, 16 | const Vector3& upDir, Deg fov, const Vector2i& windowSize); 17 | 18 | /* Set the camera view parameters: eye position, view center, up 19 | direction */ 20 | void setViewParameters(const Vector3& eye, const Vector3& viewCenter, 21 | const Vector3& upDir); 22 | 23 | /* Reset the camera to its initial position, view center, and up dir */ 24 | void reset(); 25 | 26 | /* Update screen size after the window has been resized */ 27 | void reshape(const Vector2i& windowSize) { _windowSize = windowSize; } 28 | 29 | /* Update any unfinished transformation due to lagging, return true if 30 | the camera matrices have changed */ 31 | bool updateTransformation(); 32 | 33 | /* Get/set the amount of lagging such that the camera will (slowly) 34 | smoothly navigate. Lagging must be in [0, 1) */ 35 | Float lagging() const { return _lagging; } 36 | void setLagging(Float lagging); 37 | 38 | /* Initialize the first (screen) mouse position for camera 39 | transformation. This should be called in mouse pressed event. */ 40 | void initTransformation(const Vector2i& mousePos); 41 | 42 | /* Rotate the camera from the previous (screen) mouse position to the 43 | current (screen) position */ 44 | void rotate(const Vector2i& mousePos); 45 | 46 | /* Translate the camera from the previous (screen) mouse position to 47 | the current (screen) mouse position */ 48 | void translate(const Vector2i& mousePos); 49 | 50 | /* Translate the camera by the delta amount of (NDC) mouse position. 51 | Note that NDC position must be in [-1, -1] to [1, 1]. */ 52 | void translateDelta(const Vector2& translationNDC); 53 | 54 | /* Zoom the camera (positive delta = zoom in, negative = zoom out) */ 55 | void zoom(Float delta); 56 | 57 | /* Get the camera's view transformation as a qual quaternion */ 58 | const DualQuaternion& view() const { return _view; } 59 | 60 | /* Get the camera's view transformation as a matrix */ 61 | Matrix4 viewMatrix() const { return _view.toMatrix(); } 62 | 63 | /* Get the camera's inverse view matrix (which also produces 64 | transformation of the camera) */ 65 | Matrix4 inverseViewMatrix() const { return _inverseView.toMatrix(); } 66 | 67 | /* Get the camera's transformation as a dual quaternion */ 68 | const DualQuaternion& transformation() const { return _inverseView; } 69 | 70 | /* Get the camera's transformation matrix */ 71 | Matrix4 transformationMatrix() const { return _inverseView.toMatrix(); } 72 | 73 | /* Return the distance from the camera position to the center view */ 74 | Float viewDistance() const { return Math::abs(_targetZooming); } 75 | 76 | protected: 77 | /* Update the camera transformations */ 78 | void updateInternalTransformations(); 79 | 80 | /* Transform from screen coordinate to NDC - normalized device 81 | coordinate. The top-left of the screen corresponds to [-1, 1] NDC, 82 | and the bottom right is [1, -1] NDC. */ 83 | Vector2 screenCoordToNDC(const Vector2i& mousePos) const; 84 | 85 | Deg _fov; 86 | Vector2i _windowSize; 87 | 88 | Vector2 _prevMousePosNDC; 89 | Float _lagging{}; 90 | 91 | Vector3 _targetPosition, _currentPosition, _positionT0; 92 | Quaternion _targetQRotation, _currentQRotation, _qRotationT0; 93 | Float _targetZooming, _currentZooming, _zoomingT0; 94 | DualQuaternion _view, _inverseView; 95 | }; 96 | 97 | -------------------------------------------------------------------------------- /Viewer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | corrade_add_resource(Viewer_RESOURCES resources.conf) 3 | add_library(Viewer SHARED 4 | Viewer.cpp 5 | Viewer.h 6 | ArcBall.cpp 7 | ArcBall.h 8 | IO.cpp 9 | IO.h 10 | ${Viewer_RESOURCES} 11 | ) 12 | 13 | target_include_directories(Viewer PUBLIC ${CMAKE_CURRENT_LIST_DIR}) 14 | target_link_libraries(Viewer 15 | PUBLIC 16 | Magnum::GL 17 | Magnum::Magnum 18 | Magnum::MeshTools 19 | Magnum::SceneGraph 20 | Magnum::Application 21 | Magnum::Shaders 22 | Magnum::Primitives 23 | Magnum::DebugTools 24 | MagnumIntegration::ImGui 25 | Tmo::Shaders 26 | Tmo::Optimization 27 | Tmo::ScopedTimer 28 | ) 29 | 30 | add_library(Tmo::Viewer ALIAS Viewer) -------------------------------------------------------------------------------- /Viewer/IO.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 2/8/20. 3 | // 4 | 5 | #include "IO.h" 6 | #include "Types.h" 7 | #include "RemoveIf.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | //#include 25 | 26 | namespace Directory = Corrade::Utility::Directory; 27 | 28 | namespace TextureMapOptimization { 29 | 30 | Optional loadMeshData(const StringView& path) { 31 | Mg::PluginManager::Manager manager; 32 | auto importer = manager.loadAndInstantiate("AssimpImporter"); 33 | if(!importer) std::exit(1); 34 | 35 | Debug{} << "Opening file" << path; 36 | 37 | if(!importer->openFile(path)) 38 | std::exit(4); 39 | 40 | Debug{} << "Imported " << importer->meshCount() << " meshes"; 41 | 42 | return importer->mesh(0); 43 | } 44 | 45 | #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||" 46 | #define PBWIDTH 60 47 | 48 | void printProgress(double percentage) { 49 | int val = (int) (percentage * 100); 50 | int lpad = (int) (percentage * PBWIDTH); 51 | int rpad = PBWIDTH - lpad; 52 | printf("\r%3d%% [%.*s%*s]", val, lpad, PBSTR, rpad, ""); 53 | fflush(stdout); 54 | } 55 | 56 | #pragma clang diagnostic push 57 | #pragma ide diagnostic ignored "openmp-use-default-none" 58 | Array loadImages(const StringView& dir) { 59 | auto files = Directory::list(dir, Directory::Flag::SkipDirectories | 60 | Directory::Flag::SkipSpecial | 61 | Directory::Flag::SortAscending); 62 | 63 | size_t counter = 0; 64 | Array> optionalImages{files.size()}; 65 | 66 | Mg::PluginManager::Manager manager; 67 | 68 | //#pragma omp parallel for 69 | for(size_t i = 0; i < optionalImages.size(); ++i) { 70 | auto path = Directory::join(dir, files[i]); 71 | auto imageImporter = manager.loadAndInstantiate("AnyImageImporter"); 72 | if(!imageImporter->openFile(path) || !imageImporter->image2DCount() || 73 | !imageImporter->image2D(0)) 74 | continue; 75 | 76 | optionalImages[i] = imageImporter->image2D(0); 77 | //#pragma omp critical 78 | double progress = double(counter++)/files.size(); 79 | printProgress(progress); 80 | } 81 | 82 | Array images; 83 | for(auto& optionalImage : optionalImages) { 84 | if(optionalImage) 85 | arrayAppend(images, std::move(*optionalImage)); 86 | } 87 | 88 | Debug{} << "\nImported " << images.size() << " images"; 89 | return images; 90 | } 91 | #pragma clang diagnostic pop 92 | 93 | Array loadPoses(const StringView& path) { 94 | std::ifstream file(path); 95 | Array tfs; 96 | int dummy; 97 | while(file >> dummy >> dummy >> dummy){ 98 | Matrix4 tf; 99 | file >> tf[0][0] >> tf[1][0] >> tf[2][0] >> tf[3][0] >> 100 | tf[0][1] >> tf[1][1] >> tf[2][1] >> tf[3][1] >> 101 | tf[0][2] >> tf[1][2] >> tf[2][2] >> tf[3][2] >> 102 | tf[0][3] >> tf[1][3] >> tf[2][3] >> tf[3][3]; 103 | arrayAppend(tfs, tf); 104 | } 105 | 106 | return tfs; 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /Viewer/IO.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 2/8/20. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "Types.h" 8 | #include 9 | 10 | namespace Mg = Magnum; 11 | 12 | namespace TextureMapOptimization { 13 | 14 | Optional 15 | loadMeshData(const StringView& path); 16 | 17 | Array 18 | loadImages(const StringView& dir); 19 | 20 | Array loadPoses(const StringView& path); 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Viewer/SourceSansPro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/Viewer/SourceSansPro-Regular.ttf -------------------------------------------------------------------------------- /Viewer/Viewer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 08.11.19. 3 | // 4 | 5 | #include "Viewer.h" 6 | #include "IO.h" 7 | #include "Reduction.h" 8 | #include "UniqueFunction.h" 9 | #include "Optimization.h" 10 | #include "ScopedTimer.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "imgui_internal.h" 41 | 42 | namespace TextureMapOptimization { 43 | 44 | template 45 | char (*countof_helper(T (&_Array)[Size]))[Size]; 46 | 47 | #define COUNTOF(array) (sizeof(*countof_helper(array)) + 0) 48 | 49 | using namespace Math::Literals; 50 | using namespace Corrade::Containers::Literals; 51 | 52 | Matrix4 53 | computeProjectionMatrix(float nx, float ny, float fx, float fy, float cx, float cy) { 54 | constexpr float zfar = 10.0f; 55 | constexpr float znear = 0.01; 56 | 57 | Matrix4 P = { 58 | {fx/nx, 0, 0, 0}, 59 | {0, fy/ny, 0, 0}, 60 | {-cx, -cy, (znear + zfar)/(znear - zfar), -1}, 61 | {0, 0, 2*znear*zfar/(znear - zfar), 0} 62 | }; 63 | 64 | auto fov = Math::atan(nx/(2*fx)); 65 | return Matrix4::perspectiveProjection(2*fov, nx/ny, 0.01, 10); 66 | return P; 67 | } 68 | 69 | /** 70 | * If matrix is not rigid, project rotation part onto SO3. 71 | * By default, we assume that the poses transform camera 72 | * coordinates into world coordinates. For optimization 73 | * we need the inverse of that. Furthermore we assume that 74 | * the the transformation are in "computer vision" coordinates 75 | * which is different from the coordinate conventions opengl 76 | * uses, so we fix that as well. 77 | * @param transformations 78 | * @param cv2gl whether to do computer vision to opengl coordinate conversion 79 | * @param invert if true, invert the transformations 80 | */ 81 | void preprocessTransformations(Array& transformations, bool cv2gl = true, bool invert = true) { 82 | for(auto& tf : transformations) { 83 | if(!tf.isRigidTransformation()) { 84 | Matrix3 rot{{tf[0].xyz(), 85 | tf[1].xyz(), 86 | tf[2].xyz()}}; 87 | auto [U, _, V] = Math::Algorithms::svd(rot); 88 | tf = Matrix4::from(U*V.transposed(), tf.translation()); 89 | CORRADE_ASSERT(tf.isRigidTransformation(), "Couldn't salvage not rigid transformation",); 90 | } 91 | if(cv2gl) 92 | tf = tf*Matrix4::scaling({1, -1, 1})*Matrix4::reflection({0, 0, 1}); 93 | if(invert) 94 | tf = tf.invertedRigid(); 95 | } 96 | } 97 | 98 | void setupTexture(GL::Texture2D& texture, Vector2i const& size, GL::TextureFormat format) { 99 | texture = GL::Texture2D{}; 100 | texture.setMagnificationFilter(GL::SamplerFilter::Linear) 101 | .setMinificationFilter(GL::SamplerFilter::Linear) 102 | .setWrapping(GL::SamplerWrapping::ClampToEdge) 103 | .setStorage(1, format, size); 104 | } 105 | 106 | Viewer::Viewer(Arguments const& args) : Mg::Platform::Application{args, Mg::NoCreate} { 107 | 108 | /* Setup window */ 109 | { 110 | const Vector2 dpiScaling = this->dpiScaling({}); 111 | Configuration conf; 112 | conf.setTitle("Viewer") 113 | .setSize(conf.size(), dpiScaling) 114 | .setWindowFlags(Configuration::WindowFlag::Resizable); 115 | GLConfiguration glConf; 116 | glConf.setSampleCount(dpiScaling.max() < 2.0f ? 8 : 2); 117 | if(!tryCreate(conf, glConf)) { 118 | create(conf, glConf.setSampleCount(0)); 119 | } 120 | } 121 | 122 | /* Setup camera */ 123 | { 124 | const Vector3 eye = Vector3::zAxis(5.0f); 125 | const Vector3 viewCenter; 126 | const Vector3 up = Vector3::yAxis(); 127 | const Deg fov = 45.0_degf; 128 | arcball.emplace(eye, viewCenter, up, fov, windowSize()); 129 | arcball->setLagging(0.85f); 130 | 131 | projection = computeProjectionMatrix(640.f, 480.f, 525.f, 525.f, 319.5f, 239.5f); 132 | } 133 | 134 | /* setup texture that will be optimized */ 135 | { 136 | flat = Magnum::Shaders::Flat3D{Magnum::Shaders::Flat3D::Flag::Textured}; 137 | phong = Magnum::Shaders::Phong{Magnum::Shaders::Phong::Flag::DiffuseTexture}; 138 | vertexColored = Magnum::Shaders::VertexColor3D{}; 139 | triangleShader = Shaders::FullScreenTriangle{}; 140 | 141 | Vector2i size = Vector2i{512, 512}; 142 | setupTexture(texture, size, GL::TextureFormat::RGBA32F); 143 | 144 | Array data{NoInit, size.product()*sizeof(Color4)}; 145 | for(Color4& c : arrayCast(data)) { 146 | c = Color4::red(); 147 | } 148 | Mg::Image2D redImage{Mg::PixelFormat::RGBA32F, size, std::move(data)}; 149 | texture.setSubImage(0, {}, redImage); 150 | } 151 | 152 | /* setup scene*/ 153 | if(Cr::Utility::Directory::exists(path)) { 154 | loadScene(path); 155 | } 156 | 157 | /* Setup ImGui, load a better font */ 158 | { 159 | ImGui::CreateContext(); 160 | ImGui::StyleColorsDark(); 161 | 162 | ImGuiIO& io = ImGui::GetIO(); 163 | 164 | io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; 165 | //io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; 166 | 167 | ImFontConfig fontConfig; 168 | fontConfig.FontDataOwnedByAtlas = false; 169 | const Vector2 size = Vector2{windowSize()}/dpiScaling(); 170 | Cr::Utility::Resource rs{"fonts"}; 171 | ArrayView font = rs.getRaw( 172 | "SourceSansPro-Regular.ttf"); 173 | io.Fonts->AddFontFromMemoryTTF( 174 | const_cast(font.data()), Int(font.size()), 175 | 20.0f*framebufferSize().x()/size.x(), &fontConfig); 176 | 177 | imgui = Mg::ImGuiIntegration::Context{*ImGui::GetCurrentContext(), 178 | Vector2{windowSize()}/dpiScaling(), 179 | windowSize(), framebufferSize()}; 180 | 181 | 182 | /* Setup proper blending to be used by ImGui */ 183 | GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add, 184 | GL::Renderer::BlendEquation::Add); 185 | GL::Renderer::setBlendFunction(GL::Renderer::BlendFunction::SourceAlpha, 186 | GL::Renderer::BlendFunction::OneMinusSourceAlpha); 187 | 188 | 189 | } 190 | 191 | GL::Renderer::enable(GL::Renderer::Feature::DepthTest); 192 | GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); 193 | 194 | } 195 | 196 | void Viewer::drawOptions() { 197 | if(ImGui::Begin("Options")) { 198 | if(ImGui::Button("Run Optimization")) { 199 | isOptimizing = true; 200 | } 201 | ImGui::SameLine(); 202 | if(ImGui::Button("Map Texture")) { 203 | renderPass->setTexture(texture); 204 | renderPass->averagingPass(); 205 | } 206 | 207 | ImGui::Checkbox("Draw Poses", &drawPoses); 208 | 209 | if(ImGui::InputInt("Keyframe Idx", ¤tKf)) { 210 | currentKf = Math::clamp(currentKf, 0, keyFrames.size() - 1); 211 | onNewKeyFrame(); 212 | } 213 | 214 | static const char* options[] = { 215 | "Texture", 216 | "Groundtruth Image", 217 | "Rendered Image", 218 | "Cost", 219 | "Rotation Gradient", 220 | "Translation Gradient", 221 | }; 222 | 223 | if(ImGui::BeginCombo("Overlay Options", options[currentOption])) { 224 | for(size_t i = 0; i < COUNTOF(options); ++i) { 225 | bool isSelected = i == currentOption; 226 | if(ImGui::Selectable(options[i], isSelected)) { 227 | currentOption = i; 228 | RenderPass::VisualizatonFlag visFlag{0}; 229 | switch(i) { 230 | case 0: 231 | overlay = &texture; 232 | onNewKeyFrame = []{}; /* remove old callback */ 233 | break; 234 | case 1: 235 | onNewKeyFrame = [this]{ overlay = &keyFrames[currentKf].image; }; 236 | onNewKeyFrame(); 237 | break; 238 | case 2: 239 | visFlag = RenderPass::VisualizatonFlag::RenderedImage; 240 | break; 241 | case 3: 242 | visFlag = RenderPass::VisualizatonFlag::Cost; 243 | break; 244 | case 4: 245 | visFlag = RenderPass::VisualizatonFlag::RotationGradient; 246 | break; 247 | case 5: 248 | visFlag = RenderPass::VisualizatonFlag::TranslationGradient; 249 | break; 250 | 251 | default: CORRADE_ASSERT(false, "Unknown Overlay Option", ); 252 | } 253 | if(bool(visFlag)) { 254 | onNewKeyFrame = [this, visFlag]{ 255 | renderPass->renderIntoTexture(renderedImage, currentKf, visFlag); 256 | GL::DefaultFramebuffer().bind(); 257 | }; 258 | onNewKeyFrame(); 259 | overlay = &renderedImage; 260 | } 261 | } 262 | if(isSelected) 263 | ImGui::SetItemDefaultFocus(); 264 | } 265 | ImGui::EndCombo(); 266 | } 267 | 268 | if(ImGui::Button("Camera To Keyframe")) { 269 | const Matrix4 pose = keyFrames[currentKf].tf.invertedRigid(); 270 | arcball->setViewParameters(pose.translation(), pose.translation()-pose[2].xyz(), pose[1].xyz()); 271 | } 272 | 273 | if(ImGui::Button("Reload Shaders")) { 274 | renderPass->reloadShader(); 275 | } 276 | 277 | ImGui::Text("Import/Export to"); 278 | ImGui::InputText("##Export to", path, sizeof(path)); 279 | 280 | if(ImGui::Button("Load Scene")) { 281 | loadScene(path); 282 | } 283 | 284 | ImGui::End(); 285 | } 286 | } 287 | 288 | void Viewer::loadScene(const char* path) { 289 | 290 | std::string imagesPath = Cr::Utility::Directory::join({path,"image"}); 291 | std::string scenePath = Cr::Utility::Directory::join({path ,"scene"}); 292 | std::string transformationsPath = Cr::Utility::Directory::join(scenePath ,"key.log"); 293 | std::string meshPath = Cr::Utility::Directory::join(scenePath ,"mesh.ply"); 294 | 295 | auto images = loadImages(imagesPath); 296 | auto transformations = loadPoses(transformationsPath); 297 | 298 | preprocessTransformations(transformations); 299 | 300 | imageSize = images.front().size(); 301 | Debug{} << "Image size of imported images" << imageSize; 302 | setupTexture(renderedImage, imageSize, GL::TextureFormat::RGBA32F); 303 | 304 | arrayResize(keyFrames, images.size()); 305 | for(std::size_t i = 0; i < images.size(); ++i) { 306 | //if(i % 10 != 0) continue; 307 | 308 | auto& kf = keyFrames[i]; 309 | 310 | setupTexture(kf.image, imageSize, GL::TextureFormat::RGBA32F); 311 | 312 | kf.image.setSubImage(0, {}, images[i]); 313 | /*computer vision -> opengl */ 314 | kf.tf = transformations[i]; 315 | kf.compressPose(); 316 | } 317 | 318 | meshData = *loadMeshData(meshPath); 319 | 320 | Debug{} << meshData.hasAttribute(Mg::Trade::MeshAttribute::Normal); 321 | Debug{} << meshData.hasAttribute(Mg::Trade::MeshAttribute::TextureCoordinates); 322 | //MeshTools::flipFaceWindingInPlace(meshData.mutableIndices()); 323 | //meshData = MeshTools::duplicate(md); 324 | mesh = Mg::MeshTools::compile(meshData); 325 | axis = Mg::MeshTools::compile(Mg::Primitives::axis3D()); 326 | 327 | renderPass.emplace(mesh, keyFrames); 328 | renderPass->setTexture(texture); 329 | renderPass->setCameraParameters(640.f, 480.f, 525.f, 525.f, 319.5f, 239.5f); 330 | 331 | /* do one averaging pass so we have some color to begin with. 332 | * Also set the camera to the first key frame pose */ 333 | renderPass->averagingPass(); 334 | auto pose = keyFrames[currentKf].tf.invertedRigid(); 335 | arcball->setViewParameters(pose.translation(), pose.translation()-pose[2].xyz(), pose[1].xyz()); 336 | 337 | loaded = true; 338 | } 339 | 340 | void Viewer::viewportEvent(ViewportEvent& event) { 341 | GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()}); 342 | 343 | arcball->reshape(event.windowSize()); 344 | imgui.relayout(Vector2{event.windowSize()}/event.dpiScaling(), 345 | event.windowSize(), event.framebufferSize()); 346 | } 347 | 348 | void Viewer::keyPressEvent(KeyEvent& event) { 349 | if(imgui.handleKeyPressEvent(event)) { 350 | event.setAccepted(); 351 | return; 352 | } 353 | 354 | switch(event.key()) { 355 | case KeyEvent::Key::L: 356 | if(arcball->lagging() > 0.0f) { 357 | Debug{} << "Lagging disabled"; 358 | arcball->setLagging(0.0f); 359 | } else { 360 | Debug{} << "Lagging enabled"; 361 | arcball->setLagging(0.85f); 362 | } 363 | break; 364 | case KeyEvent::Key::R: 365 | showTexture = !showTexture; 366 | arcball->reset(); 367 | break; 368 | default: 369 | return; 370 | } 371 | 372 | event.setAccepted(); 373 | redraw(); /* camera or mesh has changed, redraw! */ 374 | } 375 | 376 | void Viewer::keyReleaseEvent(KeyEvent& event) { 377 | if(imgui.handleKeyReleaseEvent(event)) { 378 | event.setAccepted(); 379 | return; 380 | } 381 | } 382 | 383 | void Viewer::textInputEvent(TextInputEvent& event) { 384 | if(imgui.handleTextInputEvent(event)) { 385 | event.setAccepted(); 386 | return; 387 | } 388 | } 389 | 390 | void Viewer::mousePressEvent(MouseEvent& event) { 391 | if(imgui.handleMousePressEvent(event)) { 392 | event.setAccepted(); 393 | return; 394 | } 395 | 396 | if(event.button() == MouseEvent::Button::Middle) { 397 | trackingMouse = true; 398 | 399 | arcball->initTransformation(event.position()); 400 | 401 | event.setAccepted(); 402 | redraw(); /* camera has changed, redraw! */ 403 | } 404 | } 405 | 406 | void Viewer::mouseReleaseEvent(MouseEvent& event) { 407 | if(imgui.handleMouseReleaseEvent(event)) { 408 | event.setAccepted(); 409 | return; 410 | } 411 | 412 | if(event.button() == MouseEvent::Button::Middle) { 413 | 414 | if(trackingMouse) { 415 | trackingMouse = false; 416 | event.setAccepted(); 417 | } 418 | } 419 | } 420 | 421 | void Viewer::mouseMoveEvent(MouseMoveEvent& event) { 422 | if(imgui.handleMouseMoveEvent(event)) { 423 | event.setAccepted(); 424 | return; 425 | } 426 | 427 | if(trackingMouse) { 428 | if(event.modifiers() & MouseMoveEvent::Modifier::Shift) 429 | arcball->translate(event.position()); 430 | else arcball->rotate(event.position()); 431 | 432 | event.setAccepted(); 433 | redraw(); /* camera has changed, redraw! */ 434 | } 435 | } 436 | 437 | void Viewer::mouseScrollEvent(MouseScrollEvent& event) { 438 | if(imgui.handleMouseScrollEvent(event)) { 439 | /* Prevent scrolling the page */ 440 | event.setAccepted(); 441 | return; 442 | } 443 | 444 | const Float delta = event.offset().y(); 445 | if(Math::abs(delta) < 1.0e-2f) return; 446 | 447 | arcball->zoom(delta); 448 | 449 | event.setAccepted(); 450 | redraw(); /* camera has changed, redraw! */ 451 | } 452 | 453 | void Viewer::drawEvent() { 454 | GL::defaultFramebuffer.clear(GL::FramebufferClear::Color | GL::FramebufferClear::Depth) 455 | .bind(); 456 | 457 | imgui.newFrame(); 458 | /* Enable text input, if needed */ 459 | if(ImGui::GetIO().WantTextInput && !isTextInputActive()) 460 | startTextInput(); 461 | else if(!ImGui::GetIO().WantTextInput && isTextInputActive()) 462 | stopTextInput(); 463 | 464 | if(loaded) { 465 | 466 | arcball->updateTransformation(); 467 | Matrix4 viewTf = arcball->viewMatrix(); 468 | 469 | if(drawPoses) { 470 | for(auto const& kf : keyFrames) { 471 | Matrix4 tf = viewTf*kf.tf.invertedRigid()*Matrix4::scaling({0.1, 0.1, 0.1}); 472 | vertexColored.setTransformationProjectionMatrix(projection*tf) 473 | .draw(axis); 474 | } 475 | //GL::Texture2D testTexture; 476 | //testTexture.setMagnificationFilter(GL::SamplerFilter::Linear) 477 | // .setMinificationFilter(GL::SamplerFilter::Linear) 478 | // .setWrapping(GL::SamplerWrapping::ClampToEdge) 479 | // .setStorage(1, GL::TextureFormat::R32F, {4096, 4096}); 480 | //glClearTexImage(testTexture.id(), 0, GL_RED, GL_FLOAT, Mg::Color4{1}.data()); 481 | //auto sum = reduce(testTexture); 482 | } 483 | 484 | /* first render the mesh using the texture */ 485 | phong 486 | .bindDiffuseTexture(texture) 487 | .setTransformationMatrix(viewTf) 488 | .setNormalMatrix(viewTf.normalMatrix()) 489 | .setProjectionMatrix(projection) 490 | .setLightPositions({{-3.0f, 10.0f, 10.0f, 0}}) 491 | //.setLightPosition({-3, 10, 10}) 492 | //.setDiffuseColor(0x2f83cc_rgbf) 493 | .setSpecularColor(Color4{0.3}) 494 | .setShininess(20) 495 | .draw(mesh); 496 | 497 | /* render the texture into the upper right corner ontop */ 498 | auto vp = GL::defaultFramebuffer.viewport(); 499 | GL::Renderer::disable(GL::Renderer::Feature::DepthTest); 500 | 501 | GL::defaultFramebuffer.setViewport({vp.max()*2./3., vp.max()}); 502 | 503 | triangleShader.bindTexture(*overlay) 504 | .draw(GL::Mesh{}.setCount(3)); 505 | GL::Renderer::enable(GL::Renderer::Feature::DepthTest); 506 | GL::defaultFramebuffer.setViewport(vp); 507 | } 508 | 509 | //ImGui::Begin("Viewer"); 510 | //auto dockspaceId = ImGui::GetID("Viewer"); 511 | //if (ImGui::DockBuilderGetNode(dockspaceId) == nullptr) 512 | // presetLayout(); 513 | drawOptions(); 514 | //ImGui::End(); 515 | 516 | imgui.updateApplicationCursor(*this); 517 | 518 | /* Render ImGui window */ 519 | { 520 | GL::Renderer::enable(GL::Renderer::Feature::Blending); 521 | GL::Renderer::disable(GL::Renderer::Feature::FaceCulling); 522 | GL::Renderer::disable(GL::Renderer::Feature::DepthTest); 523 | GL::Renderer::enable(GL::Renderer::Feature::ScissorTest); 524 | 525 | imgui.drawFrame(); 526 | 527 | GL::Renderer::disable(GL::Renderer::Feature::ScissorTest); 528 | GL::Renderer::enable(GL::Renderer::Feature::DepthTest); 529 | GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); 530 | GL::Renderer::disable(GL::Renderer::Feature::Blending); 531 | } 532 | 533 | swapBuffers(); 534 | 535 | redraw(); 536 | } 537 | 538 | void Viewer::startOptimization() { 539 | [[maybe_unused]] bool userFailure = runOptimization(keyFrames, 540 | texture, 541 | *renderPass, 542 | [this]{ return mainLoopIteration() && isOptimizing; } 543 | ); 544 | isOptimizing = false; 545 | } 546 | 547 | void Viewer::presetLayout() { 548 | auto dockspaceId = ImGui::GetID("Viewer"); 549 | ImGui::DockBuilderRemoveNode(dockspaceId); // Clear out existing layout 550 | ImGui::DockBuilderAddNode(dockspaceId); // Add empty node 551 | ImGui::DockBuilderSetNodeSize(dockspaceId, ImGui::GetIO().DisplaySize); 552 | 553 | ImGuiID dock_main_id = dockspaceId; // This variable will track the document node, however we are not using it here as we aren't docking anything into it. 554 | ImGuiID dock_id_prop = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Left, 0.20f, NULL, &dock_main_id); 555 | 556 | ImGui::DockBuilderDockWindow("Options", dock_id_prop); 557 | ImGui::DockBuilderFinish(dockspaceId); 558 | } 559 | 560 | 561 | } -------------------------------------------------------------------------------- /Viewer/Viewer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by janos on 08.11.19. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "ArcBall.h" 8 | #include "KeyFrame.h" 9 | #include "FullScreenTriangle.h" 10 | #include "Types.h" 11 | #include "Utilities.h" 12 | #include "RenderPass.h" 13 | #include "UniqueFunction.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "imgui.h" 32 | 33 | namespace TextureMapOptimization { 34 | 35 | namespace Mg = Magnum; 36 | namespace Cr = Corrade; 37 | 38 | struct Viewer : public Mg::Platform::Application { 39 | 40 | explicit Viewer(Arguments const&); 41 | 42 | void drawEvent() override; 43 | 44 | void viewportEvent(ViewportEvent& event) override; 45 | 46 | void keyPressEvent(KeyEvent& event) override; 47 | 48 | void mousePressEvent(MouseEvent& event) override; 49 | 50 | void mouseReleaseEvent(MouseEvent& event) override; 51 | 52 | void mouseMoveEvent(MouseMoveEvent& event) override; 53 | 54 | void mouseScrollEvent(MouseScrollEvent& event) override; 55 | 56 | void keyReleaseEvent(KeyEvent& event) override; 57 | 58 | void textInputEvent(TextInputEvent& event) override; 59 | 60 | void drawOptions(); 61 | 62 | void presetLayout(); 63 | 64 | /* 65 | * this member function should not be called 66 | * from withing this class. Rather it is used 67 | * to start the optimization from the thread driving 68 | * the application. The optimization framework used (ceres) 69 | * does not allow to do a single interation, thus 70 | * we give it a callback which runs the main loop 71 | * iteration after each optimization pass to not block 72 | * the GUI. 73 | */ 74 | void startOptimization(); 75 | 76 | void loadScene(const char* path); 77 | 78 | bool isOptimizing = false; 79 | 80 | Optional arcball; 81 | 82 | GL::Texture2D texture{Mg::NoCreate}; 83 | 84 | GL::Mesh mesh{Mg::NoCreate}; 85 | Mg::Trade::MeshData meshData{Mg::MeshPrimitive::Points, 0}; 86 | Array keyFrames; 87 | Matrix4 projection; 88 | 89 | Shaders::FullScreenTriangle triangleShader{Mg::NoCreate}; 90 | Mg::Shaders::Flat3D flat{Mg::NoCreate}; 91 | Mg::Shaders::Phong phong{Mg::NoCreate}; 92 | Mg::Shaders::VertexColor3D vertexColored{Mg::NoCreate}; 93 | 94 | bool trackingMouse = false; 95 | 96 | Mg::ImGuiIntegration::Context imgui{Mg::NoCreate}; 97 | 98 | bool showTexture = true; 99 | bool drawPoses = false; 100 | 101 | Vector2i textureSize{1024, 1024}; 102 | Vector2i imageSize; 103 | 104 | GL::Mesh axis{Mg::NoCreate}; 105 | int currentKf = 0; 106 | int currentOption = 0; 107 | 108 | GL::Texture2D renderedImage{Mg::NoCreate}; 109 | 110 | Optional renderPass; 111 | 112 | GL::Texture2D* overlay = &texture; 113 | UniqueFunction onNewKeyFrame = []{}; 114 | 115 | char path[256] = "/home/janos/TextureMapOptimization/assets/fountain_small/"; 116 | bool loaded = false; 117 | }; 118 | 119 | } -------------------------------------------------------------------------------- /Viewer/resources.conf: -------------------------------------------------------------------------------- 1 | group=fonts 2 | 3 | [file] 4 | filename=SourceSansPro-Regular.ttf -------------------------------------------------------------------------------- /assets/fountain_small/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/.DS_Store -------------------------------------------------------------------------------- /assets/fountain_small/image/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/.DS_Store -------------------------------------------------------------------------------- /assets/fountain_small/image/0000010-000001228920.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000010-000001228920.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000031-000004096400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000031-000004096400.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000044-000005871507.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000044-000005871507.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000064-000008602440.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000064-000008602440.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000110-000014883587.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000110-000014883587.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000156-000021164733.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000156-000021164733.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000200-000027172787.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000200-000027172787.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000215-000029220987.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000215-000029220987.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000255-000034682853.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000255-000034682853.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000299-000040690907.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000299-000040690907.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000331-000045060400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000331-000045060400.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000368-000050112627.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000368-000050112627.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000412-000056120680.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000412-000056120680.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000429-000058441973.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000429-000058441973.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000474-000064586573.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000474-000064586573.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000487-000066361680.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000487-000066361680.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000526-000071687000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000526-000071687000.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000549-000074827573.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000549-000074827573.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000582-000079333613.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000582-000079333613.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000630-000085887853.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000630-000085887853.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000655-000089301520.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000655-000089301520.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000703-000095855760.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000703-000095855760.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000722-000098450147.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000722-000098450147.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000771-000105140933.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000771-000105140933.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000792-000108008413.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000792-000108008413.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000818-000111558627.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000818-000111558627.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000849-000115791573.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000849-000115791573.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000883-000120434160.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000883-000120434160.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000896-000122209267.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000896-000122209267.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000935-000127534587.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000935-000127534587.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0000985-000134361920.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0000985-000134361920.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0001028-000140233427.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0001028-000140233427.jpg -------------------------------------------------------------------------------- /assets/fountain_small/image/0001061-000144739467.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/image/0001061-000144739467.jpg -------------------------------------------------------------------------------- /assets/fountain_small/scene/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/assets/fountain_small/scene/.DS_Store -------------------------------------------------------------------------------- /assets/fountain_small/scene/key.log: -------------------------------------------------------------------------------- 1 | 0 0 1 2 | 0.999927 0.0120774 0.00108134 0.737753 3 | -0.0120802 0.999924 0.00258248 0.741936 4 | -0.00105007 -0.00259535 0.999997 -0.323651 5 | 0 -0 -0 1 6 | 1 1 2 7 | 0.984925 0.0275681 0.17078 0.496713 8 | -0.029509 0.999526 0.00883665 0.686971 9 | -0.170455 -0.013743 0.98527 -0.378047 10 | 0 -0 -0 1 11 | 2 2 3 12 | 0.982682 -0.0153239 0.184669 0.445162 13 | 0.0217631 0.999223 -0.0328926 0.625207 14 | -0.184021 0.0363419 0.982252 -0.359023 15 | -0 -0 -0 1 16 | 3 3 4 17 | 0.911536 -0.13528 0.388336 0.231427 18 | 0.142383 0.989757 0.010574 0.5565 19 | -0.385788 0.0456539 0.921459 -0.243189 20 | -0 -0 -0 1 21 | 4 4 5 22 | 0.765484 -0.208538 0.608732 -0.0197712 23 | 0.248561 0.968429 0.0191963 0.487958 24 | -0.593514 0.136612 0.793148 -0.100109 25 | -0 -0 -0 1 26 | 5 5 6 27 | 0.77001 -0.0792711 0.633095 -0.0581291 28 | 0.157963 0.985049 -0.0687828 0.411917 29 | -0.618175 0.152968 0.771015 -0.0449623 30 | -0 -0 -0 1 31 | 6 6 7 32 | 0.834712 -0.206312 0.510591 0.0881921 33 | 0.16669 0.978335 0.122808 0.446087 34 | -0.524864 -0.0173988 0.851013 -0.0099763 35 | 0 -0 -0 1 36 | 7 7 8 37 | 0.797047 -0.23306 0.557145 0.20988 38 | 0.160604 0.971118 0.176472 0.423691 39 | -0.58218 -0.0511758 0.811453 0.0721401 40 | 0 -0 -0 1 41 | 8 8 9 42 | 0.775189 -0.438645 0.454625 0.114385 43 | 0.257199 0.876438 0.40708 0.64143 44 | -0.577012 -0.198633 0.792219 -0.0386433 45 | 0 -0 -0 1 46 | 9 9 10 47 | 0.902413 -0.344455 0.258874 0.228924 48 | 0.206537 0.87306 0.44172 0.837317 49 | -0.378163 -0.345143 0.858998 -0.172894 50 | 0 -0 -0 1 51 | 10 10 11 52 | 0.942231 -0.240705 0.232975 0.369618 53 | 0.145661 0.920681 0.362131 0.725144 54 | -0.301659 -0.307272 0.902548 -0.288314 55 | 0 -0 -0 1 56 | 11 11 12 57 | 0.996514 -0.0731539 -0.0402986 0.797674 58 | 0.0824014 0.939826 0.331586 0.697214 59 | 0.0136199 -0.333747 0.942569 -0.298208 60 | -0 -0 -0 1 61 | 12 12 13 62 | 0.987536 0.0286346 -0.154822 0.988772 63 | -0.0274008 0.999578 0.0101093 0.534129 64 | 0.155049 -0.00574002 0.987897 -0.326515 65 | -0 -0 -0 1 66 | 13 13 14 67 | 0.99272 -0.0158023 -0.119486 1.04394 68 | 0.0160971 0.999875 0.00151528 0.528668 69 | 0.119449 -0.00342659 0.992841 -0.339829 70 | -0 -0 -0 1 71 | 14 14 15 72 | 0.918134 0.0467414 -0.393524 1.3354 73 | -0.0655555 0.997259 -0.0344919 0.457914 74 | 0.390834 0.0574657 0.918675 -0.235918 75 | -0 0 -0 1 76 | 15 15 16 77 | 0.944676 0.00608795 -0.327978 1.334 78 | -0.0047265 0.999982 0.00495338 0.514232 79 | 0.328005 -0.00312852 0.944681 -0.317113 80 | -0 -0 -0 1 81 | 16 16 17 82 | 0.866727 0.0991218 -0.488853 1.47461 83 | 0.103799 0.922767 0.371138 0.686659 84 | 0.487885 -0.372414 0.789491 -0.142403 85 | -0 -0 -0 1 86 | 17 17 18 87 | 0.852923 0.146774 -0.500995 1.34131 88 | 0.0227848 0.948293 0.316607 0.581823 89 | 0.521559 -0.281453 0.805469 -0.138865 90 | -0 -0 -0 1 91 | 18 18 19 92 | 0.737347 0.391586 -0.550448 1.25748 93 | -0.12705 0.880702 0.456336 0.439831 94 | 0.663475 -0.266541 0.699126 0.0280481 95 | -0 -0 -0 1 96 | 19 19 20 97 | 0.7587 0.406414 -0.509135 1.3263 98 | -0.0898154 0.839341 0.536154 0.34106 99 | 0.645236 -0.361047 0.673302 0.175424 100 | -0 -0 -0 1 101 | 20 20 21 102 | 0.673491 0.463372 -0.575944 1.41366 103 | -0.0962677 0.827496 0.553178 0.325066 104 | 0.732916 -0.317112 0.601912 0.272313 105 | -0 -0 -0 1 106 | 21 21 22 107 | 0.570682 0.515535 -0.639185 1.49805 108 | -0.111991 0.819978 0.561355 0.290943 109 | 0.813512 -0.248768 0.525678 0.407649 110 | -0 -0 -0 1 111 | 22 22 23 112 | 0.487882 0.579338 -0.652955 1.48096 113 | -0.123084 0.786213 0.605596 0.279782 114 | 0.864201 -0.215087 0.454884 0.444719 115 | -0 -0 -0 1 116 | 23 23 24 117 | 0.742268 0.226459 -0.630688 1.55947 118 | 0.124602 0.878127 0.46195 0.672411 119 | 0.658437 -0.42147 0.623581 0.199459 120 | -0 -0 -0 1 121 | 24 24 25 122 | 0.837646 0.180718 -0.515465 1.4024 123 | 0.136778 0.844242 0.518245 0.797722 124 | 0.528836 -0.504603 0.682448 0.0228552 125 | -0 -0 -0 1 126 | 25 25 26 127 | 0.769134 0.332648 -0.545704 1.44601 128 | -0.00566735 0.857397 0.514651 0.864204 129 | 0.639086 -0.392737 0.661329 0.0418165 130 | -0 -0 -0 1 131 | 26 26 27 132 | 0.831474 0.344438 -0.435929 1.4332 133 | -0.273909 0.936799 0.217737 1.07873 134 | 0.483378 -0.0616339 0.873255 0.121835 135 | -0 -0 -0 1 136 | 27 27 28 137 | 0.7779 0.593221 -0.207336 1.37725 138 | -0.619423 0.77944 -0.0938983 1.15268 139 | 0.105911 0.201474 0.973762 0.103121 140 | -0 0 -0 1 141 | 28 28 29 142 | 0.719334 0.69211 -0.059767 1.2473 143 | -0.689169 0.700151 -0.186721 1.22028 144 | -0.0873758 0.175505 0.980602 0.0412374 145 | -0 -0 -0 1 146 | 29 29 30 147 | 0.563716 0.824342 -0.0521353 0.94959 148 | -0.816834 0.546981 -0.183382 1.20334 149 | -0.122642 0.145962 0.981668 -0.0570833 150 | -0 -0 -0 1 151 | 30 30 31 152 | 0.390329 0.866371 0.311582 0.552761 153 | -0.834885 0.475731 -0.276914 1.21973 154 | -0.388128 -0.152045 0.908985 -0.0422156 155 | 0 -0 -0 1 156 | 31 31 32 157 | 0.178116 0.815677 0.550437 0.288006 158 | -0.795609 0.448548 -0.407244 1.24656 159 | -0.579067 -0.365391 0.728828 0.159298 160 | 0 -0 -0 1 161 | 32 32 33 162 | 0.148292 0.694635 0.703934 0.36476 163 | -0.839471 0.464708 -0.281728 1.28108 164 | -0.522814 -0.549148 0.652016 0.0852921 165 | 0 -0 -0 1 166 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "Viewer.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | 14 | using namespace Corrade; 15 | using namespace Magnum; 16 | 17 | using namespace Magnum::Math::Literals; 18 | 19 | Matrix3 primeSenseCameraMatrix() 20 | { 21 | Matrix3 cameraMatrix(Math::IdentityInit); 22 | cameraMatrix[0][0] = 525.0; 23 | cameraMatrix[1][1] = 525.0; 24 | cameraMatrix[2][0] = 319.5; 25 | cameraMatrix[2][1] = 239.5; 26 | return cameraMatrix; 27 | } 28 | 29 | void rodriguezRot(Vector3d const& rod, Vector3d const& v, Vector3d& result, Matrix3d* jac){ 30 | const auto x = rod.x(), y = rod.y(), z = rod.z(); 31 | const auto x2 = x * x, y2 = y * y, z2 = z*z; 32 | const auto theta2 = x2 + y2 + z2; 33 | const auto theta = sqrt(theta2); 34 | const auto k = rod / theta; 35 | const auto cosTheta = cos(theta); 36 | const auto sinTheta = sin(theta); 37 | const auto subexpr1 = (1. - cosTheta) / theta2; 38 | const auto subexpr2 = sinTheta / theta; 39 | 40 | result = v * cosTheta + Math::cross(k, v) * sinTheta + k * Math::dot(k, v) * (1 - cosTheta); 41 | /* jac is column major */ 42 | if(!jac) return; 43 | *jac = {{x2 * subexpr1 + cosTheta , x * y * subexpr1 + z * subexpr2 , -y * subexpr2 + x * z * subexpr1}, 44 | {x * y * subexpr1 - z * subexpr2, y2 * subexpr1 + cosTheta , x * subexpr2 + y * z * subexpr1}, 45 | {x * z * subexpr1 + y * subexpr2, -x * subexpr2 + y * z * subexpr1, z2 * subexpr1 + cosTheta}}; 46 | } 47 | 48 | 49 | int main(int argc, char** argv){ 50 | TextureMapOptimization::Viewer viewer{{argc, argv}}; 51 | 52 | while(viewer.mainLoopIteration()){ 53 | if(viewer.isOptimizing){ 54 | viewer.startOptimization(); 55 | viewer.isOptimizing = false; 56 | } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /modules/FindAssimp.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # Find Assimp 3 | # ------------- 4 | # 5 | # Finds the Assimp library. This module defines: 6 | # 7 | # Assimp_FOUND - True if Assimp library is found 8 | # Assimp::Assimp - Assimp imported target 9 | # 10 | # Additionally these variables are defined for internal usage: 11 | # 12 | # ASSIMP_LIBRARY - Assimp library 13 | # ASSIMP_INCLUDE_DIR - Include dir 14 | # 15 | 16 | # 17 | # This file is part of Magnum. 18 | # 19 | # Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 20 | # Vladimír Vondruš 21 | # Copyright © 2017 Jonathan Hale 22 | # 23 | # Permission is hereby granted, free of charge, to any person obtaining a 24 | # copy of this software and associated documentation files (the "Software"), 25 | # to deal in the Software without restriction, including without limitation 26 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 27 | # and/or sell copies of the Software, and to permit persons to whom the 28 | # Software is furnished to do so, subject to the following conditions: 29 | # 30 | # The above copyright notice and this permission notice shall be included 31 | # in all copies or substantial portions of the Software. 32 | # 33 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 36 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 37 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 38 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 39 | # DEALINGS IN THE SOFTWARE. 40 | # 41 | 42 | find_path(ASSIMP_INCLUDE_DIR NAMES assimp/anim.h HINTS include) 43 | 44 | if(WIN32 AND MSVC) 45 | # Adapted from https://github.com/assimp/assimp/blob/799fd74714f9ffac29004c6b5a674b3402524094/CMakeLists.txt#L645-L655 46 | # with versions below MSVC 2015 (14.0 / 1900) removed, and the discouraged 47 | # use of MSVCxy replaced with MSVC_VERSION. See also 48 | # https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering 49 | if(MSVC_TOOLSET_VERSION) # available only since CMake 3.12 50 | set(ASSIMP_MSVC_VERSION vc${MSVC_TOOLSET_VERSION}) 51 | elseif(MSVC_VERSION VERSION_LESS 1910) 52 | set(ASSIMP_MSVC_VERSION vc140) 53 | elseif(MSVC_VERSION VERSION_LESS 1920) 54 | set(ASSIMP_MSVC_VERSION vc141) 55 | elseif(MSVC_VERSION VERSION_LESS 1930) 56 | set(ASSIMP_MSVC_VERSION vc142) 57 | else() 58 | message(FATAL_ERROR "Unsupported MSVC version") 59 | endif() 60 | 61 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 62 | set(ASSIMP_LIBRARY_DIR "lib64") 63 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) 64 | set(ASSIMP_LIBRARY_DIR "lib32") 65 | endif() 66 | 67 | find_library(ASSIMP_LIBRARY_RELEASE assimp-${ASSIMP_MSVC_VERSION}-mt.lib PATHS ${ASSIMP_LIBRARY_DIR}) 68 | find_library(ASSIMP_LIBRARY_DEBUG assimp-${ASSIMP_MSVC_VERSION}-mtd.lib PATHS ${ASSIMP_LIBRARY_DIR}) 69 | else() 70 | find_library(ASSIMP_LIBRARY_RELEASE assimp) 71 | find_library(ASSIMP_LIBRARY_DEBUG assimpd) 72 | endif() 73 | 74 | # Static build of Assimp (built with Vcpkg, any system) depends on IrrXML, find 75 | # that one as well. If not found, simply don't link to it --- it might be a 76 | # dynamic build (on Windows it's a *.lib either way), or a static build using 77 | # system IrrXML. Related issue: https://github.com/Microsoft/vcpkg/issues/5012 78 | if(ASSIMP_LIBRARY_DEBUG MATCHES "${CMAKE_STATIC_LIBRARY_SUFFIX}$" OR ASSIMP_LIBRARY_RELEASE MATCHES "${CMAKE_STATIC_LIBRARY_SUFFIX}$") 79 | find_library(ASSIMP_IRRXML_LIBRARY_RELEASE IrrXML) 80 | find_library(ASSIMP_IRRXML_LIBRARY_DEBUG IrrXMLd) 81 | endif() 82 | 83 | include(SelectLibraryConfigurations) 84 | select_library_configurations(ASSIMP) 85 | 86 | include(FindPackageHandleStandardArgs) 87 | find_package_handle_standard_args(Assimp DEFAULT_MSG 88 | ASSIMP_LIBRARY 89 | ASSIMP_INCLUDE_DIR) 90 | 91 | if(NOT TARGET Assimp::Assimp) 92 | add_library(Assimp::Assimp UNKNOWN IMPORTED) 93 | 94 | if(ASSIMP_LIBRARY_DEBUG AND ASSIMP_LIBRARY_RELEASE) 95 | set_target_properties(Assimp::Assimp PROPERTIES 96 | IMPORTED_LOCATION_DEBUG ${ASSIMP_LIBRARY_DEBUG} 97 | IMPORTED_LOCATION_RELEASE ${ASSIMP_LIBRARY_RELEASE}) 98 | else() 99 | set_target_properties(Assimp::Assimp PROPERTIES 100 | IMPORTED_LOCATION ${ASSIMP_LIBRARY}) 101 | endif() 102 | 103 | # Link to IrrXML as well, if found. See the comment above for details. 104 | if(ASSIMP_IRRXML_LIBRARY_RELEASE) 105 | set_property(TARGET Assimp::Assimp APPEND PROPERTY 106 | INTERFACE_LINK_LIBRARIES $<$>:${ASSIMP_IRRXML_LIBRARY_RELEASE}>) 107 | endif() 108 | if(ASSIMP_IRRXML_LIBRARY_DEBUG) 109 | set_property(TARGET Assimp::Assimp APPEND PROPERTY 110 | INTERFACE_LINK_LIBRARIES $<$:${ASSIMP_IRRXML_LIBRARY_DEBUG}>) 111 | endif() 112 | 113 | set_target_properties(Assimp::Assimp PROPERTIES 114 | INTERFACE_INCLUDE_DIRECTORIES ${ASSIMP_INCLUDE_DIR}) 115 | endif() -------------------------------------------------------------------------------- /modules/FindGLFW.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # Find GLFW 3 | # --------- 4 | # 5 | # Finds the GLFW library using its cmake config if that exists, otherwise 6 | # falls back to finding it manually. This module defines: 7 | # 8 | # GLFW_FOUND - True if GLFW library is found 9 | # GLFW::GLFW - GLFW imported target 10 | # 11 | # Additionally, in case the config was not found, these variables are defined 12 | # for internal usage: 13 | # 14 | # GLFW_LIBRARY - GLFW library 15 | # GLFW_DLL_DEBUG - GLFW debug DLL on Windows, if found 16 | # GLFW_DLL_RELEASE - GLFW release DLL on Windows, if found 17 | # GLFW_INCLUDE_DIR - Root include dir 18 | # 19 | 20 | # 21 | # This file is part of Magnum. 22 | # 23 | # Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 24 | # 2020 Vladimír Vondruš 25 | # Copyright © 2016 Jonathan Hale 26 | # 27 | # Permission is hereby granted, free of charge, to any person obtaining a 28 | # copy of this software and associated documentation files (the "Software"), 29 | # to deal in the Software without restriction, including without limitation 30 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 31 | # and/or sell copies of the Software, and to permit persons to whom the 32 | # Software is furnished to do so, subject to the following conditions: 33 | # 34 | # The above copyright notice and this permission notice shall be included 35 | # in all copies or substantial portions of the Software. 36 | # 37 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 38 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 39 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 40 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 41 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 42 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 43 | # DEALINGS IN THE SOFTWARE. 44 | # 45 | 46 | # GLFW installs cmake package config files which handles dependencies in case 47 | # GLFW is built statically. Try to find first, quietly, so it doesn't print 48 | # loud messages when it's not found, since that's okay. If the glfw target 49 | # already exists, it means we're using it through a CMake subproject -- don't 50 | # attempt to find the package in that case. 51 | if(NOT TARGET glfw) 52 | find_package(glfw3 CONFIG QUIET) 53 | endif() 54 | 55 | # If either a glfw config file was found or we have a subproject, point 56 | # GLFW::GLFW to that and exit -- nothing else to do here. 57 | if(TARGET glfw) 58 | if(NOT TARGET GLFW::GLFW) 59 | # Aliases of (global) targets are only supported in CMake 3.11, so we 60 | # work around it by this. This is easier than fetching all possible 61 | # properties (which are impossible to track of) and then attempting to 62 | # rebuild them into a new target. 63 | add_library(GLFW::GLFW INTERFACE IMPORTED) 64 | set_target_properties(GLFW::GLFW PROPERTIES INTERFACE_LINK_LIBRARIES glfw) 65 | endif() 66 | 67 | # Just to make FPHSA print some meaningful location, nothing else 68 | get_target_property(_GLFW_INTERFACE_INCLUDE_DIRECTORIES glfw INTERFACE_INCLUDE_DIRECTORIES) 69 | include(FindPackageHandleStandardArgs) 70 | find_package_handle_standard_args("GLFW" DEFAULT_MSG 71 | _GLFW_INTERFACE_INCLUDE_DIRECTORIES) 72 | 73 | if(CORRADE_TARGET_WINDOWS) 74 | # .dll is in LOCATION, .lib is in IMPLIB. Yay, useful! 75 | get_target_property(GLFW_DLL_DEBUG glfw IMPORTED_LOCATION_DEBUG) 76 | get_target_property(GLFW_DLL_RELEASE glfw IMPORTED_LOCATION_RELEASE) 77 | endif() 78 | 79 | return() 80 | endif() 81 | 82 | if(CORRADE_TARGET_WINDOWS) 83 | if(MSVC) 84 | if(MSVC_VERSION VERSION_LESS 1910) 85 | set(_GLFW_LIBRARY_PATH_SUFFIX lib-vc2015) 86 | elseif(MSVC_VERSION VERSION_LESS 1920) 87 | set(_GLFW_LIBRARY_PATH_SUFFIX lib-vc2017) 88 | elseif(MSVC_VERSION VERSION_LESS 1930) 89 | set(_GLFW_LIBRARY_PATH_SUFFIX lib-vc2019) 90 | else() 91 | message(FATAL_ERROR "Unsupported MSVC version") 92 | endif() 93 | elseif(MINGW) 94 | set(_GLFW_LIBRARY_PATH_SUFFIX lib-mingw-w64) 95 | else() 96 | message(FATAL_ERROR "Unsupported compiler") 97 | endif() 98 | endif() 99 | 100 | # In case no config file was found, try manually finding the library. Prefer 101 | # the glfw3dll as it's a dynamic library. 102 | find_library(GLFW_LIBRARY 103 | NAMES glfw glfw3dll glfw3 104 | PATH_SUFFIXES ${_GLFW_LIBRARY_PATH_SUFFIX}) 105 | 106 | if(CORRADE_TARGET_WINDOWS AND GLFW_LIBRARY MATCHES "glfw3dll.(lib|a)$") 107 | # TODO: debug? 108 | find_file(GLFW_DLL_RELEASE 109 | NAMES glfw3.dll 110 | PATH_SUFFIXES ${_GLFW_LIBRARY_PATH_SUFFIX}) 111 | endif() 112 | 113 | # Include dir 114 | find_path(GLFW_INCLUDE_DIR 115 | NAMES GLFW/glfw3.h) 116 | 117 | include(FindPackageHandleStandardArgs) 118 | find_package_handle_standard_args("GLFW" DEFAULT_MSG 119 | GLFW_LIBRARY 120 | GLFW_INCLUDE_DIR) 121 | 122 | if(NOT TARGET GLFW::GLFW) 123 | add_library(GLFW::GLFW UNKNOWN IMPORTED) 124 | 125 | # Work around BUGGY framework support on macOS 126 | # https://cmake.org/Bug/view.php?id=14105 127 | if(CORRADE_TARGET_APPLE AND GLFW_LIBRARY MATCHES "\\.framework$") 128 | set_property(TARGET GLFW::GLFW PROPERTY IMPORTED_LOCATION ${GLFW_LIBRARY}/GLFW) 129 | else() 130 | set_property(TARGET GLFW::GLFW PROPERTY IMPORTED_LOCATION ${GLFW_LIBRARY}) 131 | endif() 132 | 133 | set_property(TARGET GLFW::GLFW PROPERTY 134 | INTERFACE_INCLUDE_DIRECTORIES ${GLFW_INCLUDE_DIR}) 135 | endif() 136 | 137 | mark_as_advanced(GLFW_LIBRARY GLFW_INCLUDE_DIR) 138 | -------------------------------------------------------------------------------- /render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/render.png -------------------------------------------------------------------------------- /texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Janos95/texture_map_optimization/66f2067765db27647428811b306e259bd31ef75e/texture.png --------------------------------------------------------------------------------