├── .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 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
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 | 
29 | 
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