├── .clang-format ├── .github └── workflows │ └── cmake.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── app ├── image3d.cc ├── point2mesh.cc ├── posmap_gen.cc ├── posmap_recon.cc ├── textrans.cc └── vc2tex.cc ├── app_gui ├── mesh_viewer │ └── main.cc └── mesh_viewer_min │ └── main.cc ├── data ├── blendshape │ ├── building.mtl │ ├── building.obj │ ├── color_grid.png │ ├── cube.mtl │ ├── cube.obj │ ├── sphere.mtl │ └── sphere.obj ├── color_transfer │ ├── reference_00.jpg │ └── target_00.jpg ├── cylinder │ ├── boundary.txt │ ├── cylinder.mtl │ └── cylinder.obj ├── face │ ├── boundary.txt │ ├── ict-facekit_lmk.json │ ├── ict-facekit_movable_faces.txt │ ├── ict-facekit_tri.mtl │ ├── ict-facekit_tri.obj │ ├── lpshead │ │ ├── Infinite-Scan_License.txt │ │ ├── README.txt │ │ ├── head_triangulated.obj │ │ ├── head_triangulated.obj.mtl │ │ ├── head_triangulated_landmarks.json │ │ ├── head_triangulated_landmarks_8.txt │ │ └── lambertian_1k.jpg │ ├── max-planck.obj │ ├── max-planck_lmk.json │ ├── mediapipe_face.obj │ ├── mediapipe_face_landmarks.json │ └── mediapipe_face_landmarks_8.txt ├── gif │ ├── README.md │ └── dancing.gif ├── inpaint │ ├── fruits.jpg │ └── fruits_scrabble.png ├── make_gif.py ├── plane │ ├── plane.mtl │ ├── plane.obj │ └── plane.png ├── poisson_blending │ ├── mask.png │ ├── source.png │ └── target.png ├── sfs │ ├── GT.ply │ ├── mask_00000.png │ ├── mask_00001.png │ ├── mask_00002.png │ ├── mask_00003.png │ ├── mask_00004.png │ ├── mask_00005.png │ └── tumpose.txt ├── sphere │ ├── icosphere3_smart_uv.mtl │ ├── icosphere3_smart_uv.obj │ ├── icosphere5_smart_uv.mtl │ └── icosphere5_smart_uv.obj ├── spot │ ├── README.txt │ ├── spot.mtl │ ├── spot_control_mesh.obj │ ├── spot_quadrangulated.obj │ ├── spot_remesh.mtl │ ├── spot_remesh.obj │ ├── spot_texture.png │ ├── spot_texture.svg │ └── spot_triangulated.obj └── synthesis │ ├── 217_s.png │ └── README.md ├── examples ├── ex01_mesh.cc ├── ex02_renderer.cc ├── ex03_sfs.cc ├── ex04_adjacency.cc ├── ex05_geodesic.cc ├── ex06_image.cc ├── ex07_inflation.cc ├── ex08_inpaint.cc ├── ex09_renderer_realtime.cc ├── ex10_stereo.cc ├── ex11_synthesis.cc ├── ex12_texturing.cc ├── ex13_clustering.cc ├── ex14_thread.cc ├── ex15_optimizer.cc ├── ex16_textrans.cc ├── ex17_kdtree.cc ├── ex18_bvh.cc ├── ex19_parameterize.cc ├── ex20_manifold.cc ├── ex21_fusion.cc ├── ex22_line.cc ├── ex23_rigid.cc ├── ex24_nonrigid.cc ├── ex25_superpixel.cc ├── ex26_poisson_recon.cc ├── ex27_math.cc ├── ex28_curvature.cc └── ex29_editing.cc ├── imgui.ini ├── include └── ugu │ ├── accel │ ├── bvh.h │ ├── bvh_base.h │ ├── bvh_naive.h │ ├── bvh_nanort.h │ ├── kdtree.h │ ├── kdtree_base.h │ ├── kdtree_naive.h │ └── kdtree_nanoflann.h │ ├── camera.h │ ├── clustering │ └── clustering.h │ ├── common.h │ ├── correspondence │ └── correspondence_finder.h │ ├── cuda │ ├── image.h │ ├── knn.h │ └── voxel.h │ ├── curvature │ └── curvature.h │ ├── decimation │ └── decimation.h │ ├── discrete │ └── bin_packer_2d.h │ ├── editing │ └── poisson_mesh_editing.h │ ├── eigen_util.h │ ├── external │ └── external.h │ ├── face_adjacency.h │ ├── geodesic │ └── geodesic.h │ ├── image.h │ ├── image_io.h │ ├── image_proc.h │ ├── inflation │ └── inflation.h │ ├── inpaint │ └── inpaint.h │ ├── line.h │ ├── log.h │ ├── mesh.h │ ├── optimizer │ └── optimizer.h │ ├── parameterize │ └── parameterize.h │ ├── plane.h │ ├── point.h │ ├── rect.h │ ├── registration │ ├── nonrigid.h │ ├── registration.h │ └── rigid.h │ ├── renderable_mesh.h │ ├── renderer │ ├── base.h │ ├── cpu │ │ ├── pixel_shader.h │ │ ├── rasterizer.h │ │ ├── raytracer.h │ │ ├── renderer.h │ │ └── util_private.h │ └── gl │ │ └── renderer.h │ ├── sfs │ └── voxel_carver.h │ ├── shader │ └── shader.h │ ├── stereo │ └── base.h │ ├── superpixel │ └── superpixel.h │ ├── synthesis │ └── bdsim.h │ ├── textrans │ └── texture_transfer.h │ ├── texturing │ ├── texture_mapper.h │ ├── vertex_colorizer.h │ └── visibility_tester.h │ ├── timer.h │ ├── util │ ├── camera_util.h │ ├── geom_util.h │ ├── image_util.h │ ├── io_util.h │ ├── math_util.h │ ├── path_util.h │ ├── raster_util.h │ ├── rgbd_util.h │ ├── string_util.h │ └── thread_util.h │ └── voxel │ ├── extract_voxel.h │ ├── marching_cubes.h │ ├── marching_cubes_lut.h │ └── voxel.h ├── python ├── obj_io.py ├── test.py └── ugu_py.cc ├── rebuild.bat ├── reconfigure.bat ├── script └── glsl2header.py ├── src ├── camera.cc ├── clustering │ └── clustering.cc ├── common.cc ├── correspondence │ └── correspondence_finder.cc ├── cuda │ ├── helper_cuda.h │ ├── helper_string.h │ ├── image.cc │ ├── image.cu │ ├── image.cuh │ ├── knn.cc │ ├── knn.cu │ ├── knn.cuh │ ├── voxel.cc │ ├── voxel.cu │ └── voxel.cuh ├── curvature │ └── curvature.cc ├── decimation │ └── decimation.cc ├── discrete │ └── bin_packer_2d.cc ├── editing │ └── poisson_mesh_editing.cc ├── external │ ├── fast_quadric_mesh_simplification.cc │ ├── libigl.cc │ ├── mvs_texturing.cc │ └── poisson_reconstruction.cc ├── geodesic │ └── geodesic.cc ├── gltf.h ├── image.cc ├── image_io.cc ├── image_proc.cc ├── inflation │ └── inflation.cc ├── inpaint │ └── inpaint.cc ├── line.cc ├── log.cc ├── mesh.cc ├── optimizer │ └── optimizer.cc ├── parameterize │ └── parameterize.cc ├── plane.cc ├── point.cc ├── registration │ ├── nonrigid.cc │ ├── registration.cc │ └── rigid.cc ├── renderable_mesh.cc ├── renderer │ ├── cpu │ │ ├── rasterizer.cc │ │ ├── raytracer.cc │ │ └── util_private.cc │ └── gl │ │ ├── font │ │ └── Open_Sans │ │ │ ├── OFL.txt │ │ │ ├── README.txt │ │ │ ├── static │ │ │ └── OpenSans │ │ │ │ └── OpenSans-Regular.ttf │ │ │ └── static_OpenSans_OpenSans_Regular_ttf.h │ │ └── renderer.cc ├── sfs │ └── voxel_carver.cc ├── shader │ ├── frag.h │ ├── geom.h │ ├── glsl │ │ ├── frag │ │ │ ├── deferred.frag │ │ │ ├── gbuf.frag │ │ │ └── text.frag │ │ ├── geom │ │ │ └── dummy.geom │ │ └── vert │ │ │ ├── deferred.vert │ │ │ ├── gbuf.vert │ │ │ └── text.vert │ ├── shader.cc │ └── vert.h ├── stb.cc ├── stereo │ ├── base.cc │ └── patchmatch_stereo_impl.h ├── superpixel │ └── superpixel.cc ├── synthesis │ └── bdsim.cc ├── textrans │ └── texture_transfer.cc ├── texturing │ ├── texture_mapper.cc │ ├── vertex_colorizer.cc │ └── visibility_tester.cc ├── ugu_stb.h ├── util │ ├── camera_util.cc │ ├── geom_util.cc │ ├── image_util.cc │ ├── io_util.cc │ ├── math_util.cc │ ├── path_util.cc │ ├── raster_util.cc │ ├── rgbd_util.cc │ ├── string_util.cc │ └── thread_util.cc └── voxel │ ├── extract_voxel.cc │ ├── marching_cubes.cc │ ├── marching_cubes_lut.cc │ └── voxel.cc └── third_party └── glad ├── include ├── KHR │ └── khrplatform.h └── glad │ ├── gl.h │ └── gles2.h └── src ├── gl.c └── gles2.c /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: 4 | push: 5 | branches: [develop] 6 | pull_request: 7 | branches: [develop] 8 | 9 | env: 10 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 11 | BUILD_TYPE: Debug 12 | 13 | jobs: 14 | build_clang: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - name: Submodule Update 21 | run: git submodule update --init --recursive 22 | 23 | - name: Setup GLFW 24 | run: sudo apt install libgl-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev 25 | 26 | - name: Install Clang 27 | uses: egor-tensin/setup-clang@v1 28 | 29 | - name: Install OpenMP for Clang 30 | run: sudo apt-get install libomp-dev 31 | 32 | - name: Configure CMake Clang 33 | env: 34 | CC: clang 35 | CXX: clang++ 36 | run: cmake -B ${{github.workspace}}/build_clang -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 37 | 38 | - name: Build Clang 39 | env: 40 | CC: clang 41 | CXX: clang++ 42 | run: cmake --build ${{github.workspace}}/build_clang --config ${{env.BUILD_TYPE}} -j 2 43 | 44 | - name: Test Clang 45 | working-directory: ${{github.workspace}}/build_clang 46 | run: ctest -C ${{env.BUILD_TYPE}} 47 | 48 | build_gcc: 49 | runs-on: ubuntu-latest 50 | 51 | steps: 52 | - uses: actions/checkout@v2 53 | 54 | - name: Submodule Update 55 | run: git submodule update --init --recursive 56 | 57 | - name: Setup GLFW 58 | run: sudo apt install libgl-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev 59 | 60 | - name: Configure CMake GCC 61 | env: 62 | CC: gcc 63 | CXX: g++ 64 | run: cmake -B ${{github.workspace}}/build_gcc -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 65 | 66 | - name: Build GCC 67 | env: 68 | CC: gcc 69 | CXX: g++ 70 | # Build your program with the given configuration 71 | run: cmake --build ${{github.workspace}}/build_gcc --config ${{env.BUILD_TYPE}} -j 2 72 | 73 | - name: Test GCC 74 | working-directory: ${{github.workspace}}/build_gcc 75 | run: ctest -C ${{env.BUILD_TYPE}} 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | /win_build/ 3 | /build/ 4 | /bin/ 5 | /lib/ 6 | /data/ 7 | 8 | # Prerequisites 9 | *.d 10 | 11 | # Compiled Object files 12 | *.slo 13 | *.lo 14 | *.o 15 | # *.obj 16 | 17 | # Precompiled Headers 18 | *.gch 19 | *.pch 20 | 21 | # Compiled Dynamic libraries 22 | *.so 23 | *.dylib 24 | *.dll 25 | 26 | # Fortran module files 27 | *.mod 28 | *.smod 29 | 30 | # Compiled Static libraries 31 | *.lai 32 | *.la 33 | *.a 34 | *.lib 35 | 36 | # Executables 37 | *.exe 38 | *.out 39 | *.app 40 | 41 | # Imgui 42 | imgui 43 | 44 | # Output of examples 45 | out 46 | /checks.json 47 | /.vscode/c_cpp_properties.json 48 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third_party/tinyobjloader"] 2 | path = third_party/tinyobjloader 3 | url = https://github.com/syoyo/tinyobjloader.git 4 | [submodule "third_party/stb"] 5 | path = third_party/stb 6 | url = https://github.com/nothings/stb.git 7 | [submodule "third_party/lodepng"] 8 | path = third_party/lodepng 9 | url = https://github.com/lvandeve/lodepng 10 | [submodule "third_party/tinycolormap"] 11 | path = third_party/tinycolormap 12 | url = https://github.com/yuki-koyama/tinycolormap.git 13 | [submodule "third_party/nanort"] 14 | path = third_party/nanort 15 | url = https://github.com/lighttransport/nanort.git 16 | [submodule "third_party/eigen"] 17 | path = third_party/eigen 18 | url = https://gitlab.com/libeigen/eigen.git 19 | [submodule "third_party/json"] 20 | path = third_party/json 21 | url = https://github.com/nlohmann/json.git 22 | [submodule "third_party/nanopm"] 23 | path = third_party/nanopm 24 | url = https://github.com/unclearness/nanopm.git 25 | [submodule "third_party/nanoflann"] 26 | path = third_party/nanoflann 27 | url = https://github.com/jlblancoc/nanoflann.git 28 | [submodule "third_party/Fast-Quadric-Mesh-Simplification"] 29 | path = third_party/Fast-Quadric-Mesh-Simplification 30 | url = https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification.git 31 | [submodule "third_party/mvs-texturing"] 32 | path = third_party/mvs-texturing 33 | url = https://github.com/unclearness/mvs-texturing.git 34 | [submodule "third_party/cxxopts"] 35 | path = third_party/cxxopts 36 | url = https://github.com/jarro2783/cxxopts.git 37 | [submodule "third_party/libigl"] 38 | path = third_party/libigl 39 | url = https://github.com/libigl/libigl.git 40 | [submodule "third_party/imgui"] 41 | path = third_party/imgui 42 | url = https://github.com/ocornut/imgui.git 43 | [submodule "third_party/glfw"] 44 | path = third_party/glfw 45 | url = https://github.com/glfw/glfw.git 46 | [submodule "third_party/PoissonRecon"] 47 | path = third_party/PoissonRecon 48 | url = https://github.com/mkazhdan/PoissonRecon.git 49 | [submodule "third_party/freetype"] 50 | path = third_party/freetype 51 | url = https://github.com/freetype/freetype.git 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 unclearness 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **UGU**: **U**nclearness **G**eometry **U**tility 2 | 3 | **UGU** handles the intersection of computer vision and graphics from the point of view of geometries and images. 4 | 5 | # Design concept 6 | 7 | ## Minimal dependency yet scalable functionality 8 | 9 | Mandatory dependency is only [Eigen](https://gitlab.com/libeigen/eigen). 10 | 11 | All other dependencies in `third_party/` are optional. The use of the dependencies can be handled with CMake configuration. 12 | 13 | ## Easy build on any platform 14 | 15 | Most dependencies are kept as `git submodule`. 16 | 17 | Build with CMake should pass on Linux (clang/gcc) and Windows (MSVC). 18 | 19 | ## Compatibility to cv::Mat 20 | 21 | For easy integration into OpenCV-based assets, ugu::ImageBase can be replaced with cv::Mat. 22 | 23 | # Build 24 | 25 | - `git submodule update --init --recursive` 26 | - To pull dependencies registered as git submodule. 27 | - Use CMake with `CMakeLists.txt`. 28 | - `reconfigure.bat` and `rebuild.bat` are command line CMake utilities for Windows 10/11 and Visual Studio 2017-2022. 29 | -------------------------------------------------------------------------------- /app/posmap_gen.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | 8 | #include "ugu/image_io.h" 9 | #include "ugu/inpaint/inpaint.h" 10 | #include "ugu/mesh.h" 11 | #include "ugu/timer.h" 12 | #include "ugu/util/raster_util.h" 13 | #include "ugu/util/string_util.h" 14 | 15 | #ifdef _WIN32 16 | #pragma warning(push, 0) 17 | #endif 18 | #include "cxxopts.hpp" 19 | #ifdef _WIN32 20 | #pragma warning(pop) 21 | #endif 22 | 23 | int main(int argc, char* argv[]) { 24 | cxxopts::Options options("textrans", 25 | "Texture transfer for almost aligned meshes"); 26 | options.positional_help("[optional args]").show_positional_help(); 27 | 28 | options.add_options()("s,src", "Src mesh (.obj)", 29 | cxxopts::value())( 30 | "o,out", "Output posmap (.exr or .bin)", cxxopts::value())( 31 | "width", "Output texture width", 32 | cxxopts::value()->default_value("1024"))( 33 | "height", "Output texture height", 34 | cxxopts::value()->default_value("1024"))( 35 | "i,inpaint", "Enable inpaint", 36 | cxxopts::value()->default_value("false"))("h,help", "Print usage"); 37 | 38 | options.parse_positional({"src", "out"}); 39 | 40 | auto result = options.parse(argc, argv); 41 | 42 | if (result.count("help") > 0 || result.count("src") < 1 || 43 | result.count("out") < 1) { 44 | std::cout << options.help() << std::endl; 45 | exit(0); 46 | } 47 | 48 | const std::string& src_obj_path = result["src"].as(); 49 | const std::string& out_path = result["out"].as(); 50 | int width = result["width"].as(); 51 | int height = result["height"].as(); 52 | bool to_inpaint = result["inpaint"].as(); 53 | 54 | std::string ext = ugu::ExtractExt(out_path); 55 | #ifdef UGU_USE_OPENCV 56 | if (ext != "exr") { 57 | std::cout << "only .exr is supported" << std::endl; 58 | return 1; 59 | } 60 | #else 61 | if (ext != "bin") { 62 | std::cout << "only .bin is supported" << std::endl; 63 | return 1; 64 | } 65 | #endif 66 | 67 | ugu::Timer<> timer; 68 | ugu::Mesh src_mesh; 69 | 70 | src_mesh.LoadObj(src_obj_path); 71 | 72 | ugu::Image3f posmap; 73 | ugu::Image1b mask = ugu::Image1b::zeros(width, height); 74 | ugu::RasterizeVertexAttributeToTexture( 75 | src_mesh.vertices(), src_mesh.vertex_indices(), src_mesh.uv(), 76 | src_mesh.uv_indices(), posmap, width, height, &mask); 77 | 78 | if (to_inpaint) { 79 | ugu::Image1b inv_mask; 80 | ugu::Not(mask, &inv_mask); 81 | ugu::Inpaint(inv_mask, posmap, 3.f, ugu::InpaintMethod::NAIVE); 82 | } 83 | 84 | ugu::imwrite(out_path, posmap); 85 | 86 | return 0; 87 | } -------------------------------------------------------------------------------- /app/posmap_recon.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | 8 | #include "ugu/image_io.h" 9 | #include "ugu/mesh.h" 10 | #include "ugu/timer.h" 11 | #include "ugu/util/raster_util.h" 12 | #include "ugu/util/string_util.h" 13 | 14 | #ifdef _WIN32 15 | #pragma warning(push, 0) 16 | #endif 17 | #include "cxxopts.hpp" 18 | #ifdef _WIN32 19 | #pragma warning(pop) 20 | #endif 21 | 22 | int main(int argc, char* argv[]) { 23 | cxxopts::Options options("textrans", 24 | "Texture transfer for almost aligned meshes"); 25 | options.positional_help("[optional args]").show_positional_help(); 26 | 27 | options.add_options()("s,src", "Src posmap (.exr or .bin)", 28 | cxxopts::value())( 29 | "m,mesh", "Src mesh that has indices(.obj)", 30 | cxxopts::value())("o,out", "Output mesh (.obj)", 31 | cxxopts::value())( 32 | "h,help", "Print usage"); 33 | 34 | options.parse_positional({"src", "mesh", "out"}); 35 | 36 | auto result = options.parse(argc, argv); 37 | 38 | if (result.count("help") > 0 || result.count("src") < 1 || 39 | result.count("mesh") < 1 || result.count("out") < 1) { 40 | std::cout << options.help() << std::endl; 41 | exit(0); 42 | } 43 | 44 | const std::string& src_posmap_path = result["src"].as(); 45 | const std::string& src_mesh_path = result["mesh"].as(); 46 | const std::string& out_path = result["out"].as(); 47 | 48 | std::string ext = ugu::ExtractExt(src_posmap_path); 49 | #ifdef UGU_USE_OPENCV 50 | if (ext != "exr") { 51 | std::cout << "only .exr is supported" << std::endl; 52 | return 1; 53 | } 54 | #else 55 | { 56 | std::cout << "Not supported" << std::endl; 57 | return 1; 58 | // if (ext != "bin") { 59 | // std::cout << "only .bin is supported" << std::endl; 60 | // return 1; 61 | // } 62 | } 63 | #endif 64 | 65 | ugu::Image3f posmap = ugu::imread(src_posmap_path, -1); 66 | 67 | ugu::Timer<> timer; 68 | ugu::Mesh src_mesh; 69 | 70 | src_mesh.LoadObj(src_mesh_path); 71 | 72 | std::vector vertices(src_mesh.vertices().size()); 73 | 74 | for (size_t fid = 0; fid < src_mesh.vertex_indices().size(); fid++) { 75 | for (int j = 0; j < 3; j++) { 76 | auto vid = src_mesh.vertex_indices()[fid][j]; 77 | auto uvid = src_mesh.uv_indices()[fid][j]; 78 | auto x = ugu::U2X(src_mesh.uv()[uvid].x(), posmap.cols); 79 | auto y = ugu::V2Y(src_mesh.uv()[uvid].y(), posmap.rows); 80 | 81 | auto val = ugu::BilinearInterpolation(x, y, posmap); 82 | 83 | vertices[vid][0] = val[0]; 84 | vertices[vid][1] = val[1]; 85 | vertices[vid][2] = val[2]; 86 | } 87 | } 88 | 89 | src_mesh.set_vertices(vertices); 90 | 91 | src_mesh.WriteObj(out_path); 92 | 93 | return 0; 94 | } -------------------------------------------------------------------------------- /data/blendshape/building.mtl: -------------------------------------------------------------------------------- 1 | # 2 | # Wavefront material file 3 | # Converted by Meshlab Group 4 | # 5 | 6 | newmtl material_0 7 | Ka 0.200000 0.200000 0.200000 8 | Kd 0.800000 0.800000 0.800000 9 | Ks 1.000000 1.000000 1.000000 10 | Tr 1.000000 11 | illum 2 12 | Ns 0.000000 13 | map_Kd color_grid.png 14 | 15 | -------------------------------------------------------------------------------- /data/blendshape/color_grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/blendshape/color_grid.png -------------------------------------------------------------------------------- /data/blendshape/cube.mtl: -------------------------------------------------------------------------------- 1 | # 2 | # Wavefront material file 3 | # Converted by Meshlab Group 4 | # 5 | 6 | newmtl material_0 7 | Ka 0.200000 0.200000 0.200000 8 | Kd 0.800000 0.800000 0.800000 9 | Ks 1.000000 1.000000 1.000000 10 | Tr 1.000000 11 | illum 2 12 | Ns 0.000000 13 | map_Kd color_grid.png 14 | 15 | -------------------------------------------------------------------------------- /data/blendshape/sphere.mtl: -------------------------------------------------------------------------------- 1 | # 2 | # Wavefront material file 3 | # Converted by Meshlab Group 4 | # 5 | 6 | newmtl material_0 7 | Ka 0.200000 0.200000 0.200000 8 | Kd 0.800000 0.800000 0.800000 9 | Ks 1.000000 1.000000 1.000000 10 | Tr 1.000000 11 | illum 2 12 | Ns 0.000000 13 | map_Kd color_grid.png 14 | 15 | -------------------------------------------------------------------------------- /data/color_transfer/reference_00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/color_transfer/reference_00.jpg -------------------------------------------------------------------------------- /data/color_transfer/target_00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/color_transfer/target_00.jpg -------------------------------------------------------------------------------- /data/cylinder/boundary.txt: -------------------------------------------------------------------------------- 1 | 71 2 | 69 3 | 67 4 | 65 5 | 63 6 | 61 7 | 59 8 | 57 9 | 55 10 | 53 11 | 51 12 | 49 13 | 47 14 | 45 15 | 43 16 | 41 17 | 39 18 | 37 19 | 35 20 | 33 21 | 31 22 | 29 23 | 27 24 | 25 25 | 23 26 | 21 27 | 19 28 | 17 29 | 15 30 | 13 31 | 11 32 | 9 33 | 7 34 | 5 35 | 3 36 | 1 37 | -------------------------------------------------------------------------------- /data/cylinder/cylinder.mtl: -------------------------------------------------------------------------------- 1 | # Blender 3.3.7 MTL File: 'None' 2 | # www.blender.org 3 | -------------------------------------------------------------------------------- /data/face/boundary.txt: -------------------------------------------------------------------------------- 1 | 10 2 | 109 3 | 67 4 | 103 5 | 54 6 | 21 7 | 162 8 | 127 9 | 234 10 | 93 11 | 132 12 | 58 13 | 172 14 | 136 15 | 150 16 | 149 17 | 176 18 | 148 19 | 152 20 | 377 21 | 400 22 | 378 23 | 379 24 | 365 25 | 397 26 | 288 27 | 361 28 | 323 29 | 454 30 | 356 31 | 389 32 | 251 33 | 284 34 | 332 35 | 297 36 | 338 -------------------------------------------------------------------------------- /data/face/ict-facekit_lmk.json: -------------------------------------------------------------------------------- 1 | [[14878,0.9058523178100586,0.07349729537963867],[1808,0.007423492148518562,0.7876565456390381],[2095,0.04167643189430237,0.5800861120223999],[14766,0.7468355298042297,0.10722687095403671],[16943,0.2619077265262604,0.15411342680454254],[3926,0.5591217279434204,0.07752206176519394],[16999,0.2939227521419525,0.30290287733078003],[16881,0.6828303337097168,0.10709937661886215],[4332,0.36122849583625793,0.12600350379943848],[5109,0.7214459180831909,0.2520028352737427],[5799,0.7275643944740295,0.25801169872283936],[5531,0.3596378564834595,0.463667094707489],[5903,0.055671993643045425,0.40739238262176514],[5654,0.7389029860496521,0.2550804913043976],[7382,0.21769945323467255,0.35299012064933777],[7647,0.03713187202811241,0.2084357589483261],[6715,0.4971673786640167,0.2532358765602112],[20626,0.46943333745002747,0.36143845319747925]] -------------------------------------------------------------------------------- /data/face/ict-facekit_tri.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 9 3 | 4 | newmtl M_BackHead 5 | Ns 18.000004 6 | Ka 1.000000 1.000000 1.000000 7 | Kd 0.116547 0.600000 0.085082 8 | Ks 0.050000 0.050000 0.050000 9 | Ke 0.000000 0.000000 0.000000 10 | Ni 1.000000 11 | d 1.000000 12 | illum 2 13 | 14 | newmtl M_EarBack 15 | Ns 250.000000 16 | Ka 1.000000 1.000000 1.000000 17 | Kd 0.800000 0.628060 0.029617 18 | Ks 0.500000 0.500000 0.500000 19 | Ke 0.000000 0.000000 0.000000 20 | Ni 1.450000 21 | d 1.000000 22 | illum 2 23 | 24 | newmtl M_EarHole 25 | Ns 250.000000 26 | Ka 1.000000 1.000000 1.000000 27 | Kd 0.800000 0.800000 0.800000 28 | Ks 0.500000 0.500000 0.500000 29 | Ke 0.000000 0.000000 0.000000 30 | Ni 1.450000 31 | d 1.000000 32 | illum 2 33 | 34 | newmtl M_Face 35 | Ns 18.000004 36 | Ka 1.000000 1.000000 1.000000 37 | Kd 0.003159 0.079121 0.600000 38 | Ks 0.050000 0.050000 0.050000 39 | Ke 0.000000 0.000000 0.000000 40 | Ni 1.000000 41 | d 1.000000 42 | illum 2 43 | 44 | newmtl M_LeftEyeCapsule 45 | Ns 250.000000 46 | Ka 1.000000 1.000000 1.000000 47 | Kd 0.800000 0.800000 0.800000 48 | Ks 0.500000 0.500000 0.500000 49 | Ke 0.000000 0.000000 0.000000 50 | Ni 1.450000 51 | d 1.000000 52 | illum 2 53 | 54 | newmtl M_MouthInside 55 | Ns 250.000000 56 | Ka 1.000000 1.000000 1.000000 57 | Kd 0.800000 0.800000 0.800000 58 | Ks 0.500000 0.500000 0.500000 59 | Ke 0.000000 0.000000 0.000000 60 | Ni 1.450000 61 | d 1.000000 62 | illum 2 63 | 64 | newmtl M_Neck 65 | Ns 250.000000 66 | Ka 1.000000 1.000000 1.000000 67 | Kd 0.800000 0.004087 0.241236 68 | Ks 0.500000 0.500000 0.500000 69 | Ke 0.000000 0.000000 0.000000 70 | Ni 1.450000 71 | d 1.000000 72 | illum 2 73 | 74 | newmtl M_NoseHole 75 | Ns 250.000000 76 | Ka 1.000000 1.000000 1.000000 77 | Kd 0.800000 0.800000 0.800000 78 | Ks 0.500000 0.500000 0.500000 79 | Ke 0.000000 0.000000 0.000000 80 | Ni 1.450000 81 | d 1.000000 82 | illum 2 83 | 84 | newmtl M_RightEyeCapsule 85 | Ns 250.000000 86 | Ka 1.000000 1.000000 1.000000 87 | Kd 0.800000 0.800000 0.800000 88 | Ks 0.500000 0.500000 0.500000 89 | Ke 0.000000 0.000000 0.000000 90 | Ni 1.450000 91 | d 1.000000 92 | illum 2 93 | -------------------------------------------------------------------------------- /data/face/lpshead/Infinite-Scan_License.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Licence 2 | Infinite, 3D Head Scan by Lee Perry-Smith is licensed under a Creative Commons Attribution 3.0 Unported License. 3 | Based on a work at www.triplegangers.com. 4 | Permissions beyond the scope of this license may be available at http://www.ir-ltd.net/ 5 | Please remember: Do what you want with the files, but always mention where you got them from... 6 | ---------------------- 7 | This distribution was created by Morgan McGuire and Guedis Cardenas 8 | http://graphics.cs.williams.edu/data/ 9 | 10 | 11 | Downloaded from: 12 | http://www.ir-ltd.net/infinite-3d-head-scan-released 13 | Then decompressed the Object and displacement maps .rar files. We renamed Map-COL.jpg to lambertian.jpg 14 | We converted the displacement file from .tif to 16-bit .png. and saved it as bump.png 15 | Then made a lowRes version of the bump map by rescaling it with sharpening in Photoshop using 16 | Autolevels to fill the dynamic range, converting 8-bit, and filling the seams with content aware fill. 17 | We saved this as bump-lowRes.png. 18 | 19 | Edited mtl file: 20 | Set up texture maps and adjusted the default glossy highlight. 21 | We added: 22 | map_bump -bm 0.001 bump-lowRes.png 23 | 24 | map_bump -bm 0.02 bump.png (high res) 25 | ks .0001 .0001 .0001 26 | Ns 5 27 | 28 | -------------------------------------------------------------------------------- /data/face/lpshead/README.txt: -------------------------------------------------------------------------------- 1 | Original data were downloaded from https://casual-effects.com/data/ 2 | Direct link: https://casual-effects.com/g3d/data10/research/model/lpshead/lpshead.zip 3 | 4 | head_triangulated.obj* were made from the original data by the following processes: 5 | 1) Convert mesh from quad to triangle by MeshLab. 6 | 2) Annotate 8 landmark vertex ids manually. 7 | 3) Resize diffuse texture from 4K to 1K 8 | 9 | -------------------------------------------------------------------------------- /data/face/lpshead/head_triangulated.obj.mtl: -------------------------------------------------------------------------------- 1 | # 2 | # Wavefront material file 3 | # Converted by Meshlab Group 4 | # 5 | 6 | newmtl material_0 7 | Ka 0.200000 0.200000 0.200000 8 | Kd 1.000000 1.000000 1.000000 9 | Ks 1.000000 1.000000 1.000000 10 | Tr 1.000000 11 | illum 2 12 | Ns 0.000000 13 | map_Kd lambertian_1k.jpg 14 | 15 | -------------------------------------------------------------------------------- /data/face/lpshead/head_triangulated_landmarks.json: -------------------------------------------------------------------------------- 1 | {"00":[10387,0.5939168334007263,0.1954422891139984],"01":[10232,0.35002511739730835,0.20097282528877258],"02":[1482,0.29210740327835083,0.6811007857322693],"03":[797,0.3416244685649872,0.5562918186187744],"04":[13915,0.5469151139259338,0.24772381782531738],"05":[13352,0.9008604884147644,0.042212165892124176],"06":[4860,0.06502342969179153,0.3088628649711609]} -------------------------------------------------------------------------------- /data/face/lpshead/head_triangulated_landmarks_8.txt: -------------------------------------------------------------------------------- 1 | 1772 2 | 1696 3 | 904 4 | 917 5 | 1983 6 | 2143 7 | 1897 8 | 694 -------------------------------------------------------------------------------- /data/face/lpshead/lambertian_1k.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/face/lpshead/lambertian_1k.jpg -------------------------------------------------------------------------------- /data/face/max-planck_lmk.json: -------------------------------------------------------------------------------- 1 | [[52681,0.15883700549602509,0.40535297989845276],[10692,0.482810914516449,0.2789025604724884],[76633,0.2585858404636383,0.3915485441684723],[10739,0.8046832084655762,0.14566634595394135],[21539,0.10416414588689804,0.37503582239151],[21001,0.7022184133529663,0.19467799365520477],[20300,0.23827260732650757,0.5234237909317017],[64093,0.3541841506958008,0.07437394559383392],[78476,0.3328317105770111,0.1973133683204651],[64909,0.2597714364528656,0.058168258517980576],[59769,0.8571684956550598,0.1140313446521759],[60296,0.22954894602298737,0.08492521941661835],[64259,0.40793171525001526,0.5500279664993286],[63559,0.44070377945899963,0.4678257703781128],[83554,0.5771920084953308,0.11570337414741516],[58202,0.22656354308128357,0.08311660587787628],[45,0.3633840084075928,0.33787310123443604],[29961,0.19918425381183624,0.1244717389345169]] -------------------------------------------------------------------------------- /data/face/mediapipe_face_landmarks.json: -------------------------------------------------------------------------------- 1 | {"00":[567,0.5991419553756714,0.3155214786529541],"01":[665,0.596817135810852,0.2551451027393341],"02":[786,0.30712655186653137,0.6009528636932373],"03":[242,0.4358175992965698,0.11133315414190292],"04":[730,0.0683203935623169,0.02500099502503872],"05":[709,0.5060034394264221,0.05243024230003357],"06":[702,0.5007988214492798,0.4228275418281555]} -------------------------------------------------------------------------------- /data/face/mediapipe_face_landmarks_8.txt: -------------------------------------------------------------------------------- 1 | 33 2 | 133 3 | 362 4 | 263 5 | 168 6 | 4 7 | 61 8 | 291 -------------------------------------------------------------------------------- /data/gif/README.md: -------------------------------------------------------------------------------- 1 | https://giphy.com/stickers/transparency-overlay-ffmpeg-MxYQrB9jeGzza 2 | 3 | https://stackoverflow.com/questions/10438713/overlay-animated-images-with-transparency-over-a-static-background-image-using-f 4 | 5 | https://i.stack.imgur.com/e8nZC.gif 6 | -------------------------------------------------------------------------------- /data/gif/dancing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/gif/dancing.gif -------------------------------------------------------------------------------- /data/inpaint/fruits.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/inpaint/fruits.jpg -------------------------------------------------------------------------------- /data/inpaint/fruits_scrabble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/inpaint/fruits_scrabble.png -------------------------------------------------------------------------------- /data/make_gif.py: -------------------------------------------------------------------------------- 1 | from PIL import Image, ImageDraw 2 | import os 3 | import cv2 4 | 5 | 6 | def make_images(data_dir, is_right, write=False): 7 | label = 'r' if is_right else 'l' 8 | images = [] 9 | prefix = 'right: ' if is_right else 'left: ' 10 | color = (191, 132, 71) if is_right else (71, 71, 191) 11 | 12 | im = cv2.imread(os.path.join(data_dir, 'disp_' + label +'_init.png')) 13 | cv2.putText(im, prefix + "random initialization", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2) 14 | images += [im]*10 15 | 16 | for i in range(3): 17 | for j in range(5): 18 | name = 'disp_' + label + '_' + str(i) + '_' + str(j) + '.png' 19 | path = os.path.join(data_dir, name) 20 | im = cv2.imread(path) 21 | cv2.putText(im, prefix + "iter " + str(i), (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2) 22 | images.append(im) 23 | 24 | im = cv2.imread(os.path.join(data_dir, 'disp_' + label +'_iterend.png')) 25 | cv2.putText(im, prefix + "finish main process", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2) 26 | images += [im]*10 27 | 28 | im = cv2.imread(os.path.join(data_dir, 'disp_' + label +'_lrconsistency.png')) 29 | cv2.putText(im, prefix + "left right consistency", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2) 30 | images += [im]*10 31 | 32 | im = cv2.imread(os.path.join(data_dir, 'disp_'+ label +'_fillholenn.png')) 33 | cv2.putText(im, prefix + "hole filling", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2) 34 | images += [im]*10 35 | 36 | im = cv2.imread(os.path.join(data_dir, 'disp_'+ label +'_filled.png')) 37 | cv2.putText(im, prefix + "weighted median filter", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2) 38 | images += [im]*10 39 | 40 | im = cv2.imread(os.path.join(data_dir, 'disp_'+ label +'_filled.png')) 41 | cv2.putText(im, prefix + "final output", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.9, color, 2) 42 | images += [im]*10 43 | 44 | if write: 45 | for i, im in enumerate(images): 46 | name = 'gif_' + label + '_' + str(i).zfill(2) + '.png' 47 | path = os.path.join(data_dir, name) 48 | cv2.imwrite(path, im) 49 | return images 50 | 51 | def make_gif(root_dir, prefix, ext): 52 | images = [] 53 | 54 | im_files = sorted([x for x in os.listdir(root_dir) if x.startswith(prefix) and x.endswith(ext)]) 55 | 56 | for im_file in im_files: 57 | path = os.path.join(root_dir, im_file) 58 | im = Image.open(path) 59 | images.append(im) 60 | 61 | images[0].save(prefix + '.gif', 62 | save_all=True, append_images=images[1:], optimize=False, duration=200, loop=0) 63 | 64 | if __name__ == "__main__": 65 | data_dir = '../win_build/' 66 | left_images = make_images(data_dir, False) 67 | right_images = make_images(data_dir, True) 68 | for i, (l, r) in enumerate(zip(left_images, right_images)): 69 | combined = cv2.hconcat([l, r]) 70 | name = 'gif_' + str(i).zfill(2) + '.png' 71 | path = os.path.join(data_dir, name) 72 | cv2.imwrite(path, combined) 73 | make_gif(data_dir, 'gif', 'png') 74 | #make_gif(data_dir, 'gif_r', 'png') -------------------------------------------------------------------------------- /data/plane/plane.mtl: -------------------------------------------------------------------------------- 1 | newmtl mat0001 2 | Ka 0.117647 0.117647 0.117647 3 | Kd 0.752941 0.752941 0.752941 4 | Ks 0.752941 0.752941 0.752941 5 | Tr 0 6 | illum 1 7 | Ns 8 8 | map_Kd plane.png 9 | -------------------------------------------------------------------------------- /data/plane/plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/plane/plane.png -------------------------------------------------------------------------------- /data/poisson_blending/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/poisson_blending/mask.png -------------------------------------------------------------------------------- /data/poisson_blending/source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/poisson_blending/source.png -------------------------------------------------------------------------------- /data/poisson_blending/target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/poisson_blending/target.png -------------------------------------------------------------------------------- /data/sfs/mask_00000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/sfs/mask_00000.png -------------------------------------------------------------------------------- /data/sfs/mask_00001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/sfs/mask_00001.png -------------------------------------------------------------------------------- /data/sfs/mask_00002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/sfs/mask_00002.png -------------------------------------------------------------------------------- /data/sfs/mask_00003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/sfs/mask_00003.png -------------------------------------------------------------------------------- /data/sfs/mask_00004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/sfs/mask_00004.png -------------------------------------------------------------------------------- /data/sfs/mask_00005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/sfs/mask_00005.png -------------------------------------------------------------------------------- /data/sfs/tumpose.txt: -------------------------------------------------------------------------------- 1 | 00000 -39.163902 -48.510956 -718.163391 0.000000 0.000000 0.000000 1.000000 2 | 00001 -39.163902 -48.510956 781.836609 0.000000 1.000000 0.000000 0.000000 3 | 00002 710.836121 -48.510956 31.836634 0.000000 -0.707107 0.000000 0.707107 4 | 00003 -789.163879 -48.510956 31.836634 0.000000 0.707107 0.000000 0.707107 5 | 00004 -39.163902 -798.510986 31.836634 -0.707107 0.000000 0.000000 0.707107 6 | 00005 -39.163902 701.489014 31.836634 0.707107 0.000000 0.000000 0.707107 7 | -------------------------------------------------------------------------------- /data/sphere/icosphere3_smart_uv.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl None 5 | Ns 500 6 | Ka 0.8 0.8 0.8 7 | Kd 0.8 0.8 0.8 8 | Ks 0.8 0.8 0.8 9 | d 1 10 | illum 2 11 | -------------------------------------------------------------------------------- /data/sphere/icosphere5_smart_uv.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl None 5 | Ns 500 6 | Ka 0.8 0.8 0.8 7 | Kd 0.8 0.8 0.8 8 | Ks 0.8 0.8 0.8 9 | d 1 10 | illum 2 11 | -------------------------------------------------------------------------------- /data/spot/README.txt: -------------------------------------------------------------------------------- 1 | Spot 2 | ==== 3 | contact: Keenan Crane (keenan@cs.caltech.edu) 4 | 5 | Files 6 | -------------------------------------------- 7 | This archive contains a description of the surface "Spot," including: 8 | 9 | 1. the original Catmull-Clark control mesh [spot_control_mesh.obj] 10 | 2. the original texture map as a vector image [spot_texture.svg] 11 | 3. triangular and quadrilateral tessellations [spot_triangulated.obj, spot_quadrangulated.obj] 12 | 4. the texture map as a raster image [spot_texture.png] 13 | 14 | Note that (3) and (4) can be generated from (1) and (2), and are provided only 15 | for convenience. Meshes are stored in the Wavefront OBJ format. All meshes 16 | are manifold, genus-0 embeddings. The texture map should be interpreted as a 17 | unit square in the positive quadrant [0,1]x[0,1]. 18 | 19 | License 20 | -------------------------------------------- 21 | 22 | As the sole author of this data, I hereby release it into the public domain. 23 | 24 | -------------------------------------------------------------------------------- /data/spot/spot.mtl: -------------------------------------------------------------------------------- 1 | newmtl material000 2 | Ka 0.0 0.0 0.0 3 | Kd 1.0 1.0 1.0 4 | Ks 0.0 0.0 0.0 5 | illum 1 6 | Ns 8 7 | map_Kd spot_texture.png 8 | -------------------------------------------------------------------------------- /data/spot/spot_remesh.mtl: -------------------------------------------------------------------------------- 1 | newmtl material000 2 | Ns 7.999999 3 | Ka 1.000000 1.000000 1.000000 4 | Kd 1.000000 1.000000 1.000000 5 | Ks 0.000000 0.000000 0.000000 6 | Ke 0.000000 0.000000 0.000000 7 | Ni 1.450000 8 | d 1.000000 9 | illum 1 10 | map_Kd spot_remesh_texture.png 11 | -------------------------------------------------------------------------------- /data/spot/spot_texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/spot/spot_texture.png -------------------------------------------------------------------------------- /data/synthesis/217_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/data/synthesis/217_s.png -------------------------------------------------------------------------------- /data/synthesis/README.md: -------------------------------------------------------------------------------- 1 | Images in this directory were gotten from 2 | 3 | http://www.wisdom.weizmann.ac.il/~vision/ingan/resources/comparison.html 4 | 5 | Shocher, Assaf, et al. "Ingan: Capturing and retargeting the" dna" of a natural image." Proceedings of the IEEE/CVF International Conference on Computer Vision. 2019. -------------------------------------------------------------------------------- /examples/ex03_sfs.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include "ugu/camera.h" 11 | #include "ugu/image_io.h" 12 | #include "ugu/sfs/voxel_carver.h" 13 | #include "ugu/util/image_util.h" 14 | #include "ugu/util/string_util.h" 15 | 16 | // test by bunny data with 6 views 17 | int main(int argc, char* argv[]) { 18 | (void)argc; 19 | (void)argv; 20 | 21 | std::string data_dir{"../data/sfs/"}; 22 | std::vector poses; 23 | ugu::LoadTumFormat(data_dir + "tumpose.txt", &poses); 24 | 25 | ugu::VoxelCarver carver; 26 | ugu::VoxelCarverOption option; 27 | 28 | // exact mesh bounding box computed in advacne 29 | option.bb_min = Eigen::Vector3f(-250.000000f, -344.586151f, -129.982697f); 30 | option.bb_max = Eigen::Vector3f(250.000000f, 150.542343f, 257.329224f); 31 | 32 | // add offset to the bounding box to keep boundary clean 33 | float bb_offset = 20.0f; 34 | option.bb_min[0] -= bb_offset; 35 | option.bb_min[1] -= bb_offset; 36 | option.bb_min[2] -= bb_offset; 37 | 38 | option.bb_max[0] += bb_offset; 39 | option.bb_max[1] += bb_offset; 40 | option.bb_max[2] += bb_offset; 41 | 42 | // voxel resolution is 10mm 43 | option.resolution.setConstant(10.0f); 44 | carver.set_option(option); 45 | 46 | carver.Init(); 47 | 48 | // image size and intrinsic parameters 49 | int width = 320; 50 | int height = 240; 51 | Eigen::Vector2f principal_point(159.3f, 127.65f); 52 | Eigen::Vector2f focal_length(258.65f, 258.25f); 53 | std::shared_ptr camera = std::make_shared( 54 | width, height, Eigen::Affine3d::Identity(), principal_point, 55 | focal_length); 56 | 57 | for (size_t i = 0; i < 6; i++) { 58 | camera->set_c2w(poses[i]); 59 | 60 | std::string num = ugu::zfill(i); 61 | 62 | ugu::Image1b silhouette = 63 | ugu::Imread(data_dir + "/mask_" + num + ".png", 0); 64 | 65 | ugu::Image1f sdf; 66 | // Carve() is the main process to update voxels. Corresponds to the fusion 67 | // step in KinectFusion 68 | carver.Carve(*camera, silhouette, &sdf); 69 | 70 | // save SDF visualization 71 | ugu::Image3b vis_sdf; 72 | ugu::SignedDistance2Color(sdf, &vis_sdf, -1.0f, 1.0f); 73 | ugu::imwrite(data_dir + "/sdf_" + num + ".png", vis_sdf); 74 | 75 | ugu::Mesh mesh; 76 | // voxel extraction 77 | // slow for algorithm itself and saving to disk 78 | carver.ExtractVoxel(&mesh); 79 | // mesh.WritePly(data_dir + "/voxel_" + num + ".ply"); 80 | 81 | // marching cubes 82 | // smoother and faster 83 | carver.ExtractIsoSurface(&mesh, 0.0); 84 | mesh.WritePly(data_dir + "/surface_" + num + ".ply"); 85 | } 86 | 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /examples/ex04_adjacency.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | 8 | #include "ugu/face_adjacency.h" 9 | #include "ugu/mesh.h" 10 | #include "ugu/util/geom_util.h" 11 | #include "ugu/util/image_util.h" 12 | 13 | // test by bunny data with 6 views 14 | int main(int argc, char* argv[]) { 15 | (void)argc; 16 | (void)argv; 17 | 18 | std::string data_dir = "../data/bunny/"; 19 | std::string obj_path = data_dir + "bunny.obj"; 20 | 21 | { 22 | std::ifstream ifs(obj_path); 23 | if (!ifs.is_open()) { 24 | printf("Please put %s\n", obj_path.c_str()); 25 | return -1; 26 | } 27 | } 28 | 29 | // load mesh 30 | ugu::MeshPtr mesh = ugu::Mesh::Create(); 31 | mesh->LoadObj(obj_path, data_dir); 32 | 33 | auto [clusters, non_orphans, orphans, clusters_f] = 34 | ugu::ClusterByConnectivity(mesh->uv_indices(), 35 | static_cast(mesh->uv().size())); 36 | ugu::LOGI("#Clusters %d\n", clusters.size()); 37 | 38 | ugu::Mesh cluster_colored = *mesh; 39 | auto random_colors = 40 | ugu::GenRandomColors(static_cast(clusters.size())); 41 | auto [vid2uvid, uvid2vid] = 42 | ugu::GenerateVertex2UvMap(mesh->vertex_indices(), mesh->vertices().size(), 43 | mesh->uv_indices(), mesh->uv().size()); 44 | std::vector colors(mesh->vertices().size()); 45 | for (size_t i = 0; i < clusters.size(); i++) { 46 | const auto& cluster = clusters[i]; 47 | for (const auto& uvid : cluster) { 48 | auto vid = uvid2vid[uvid]; 49 | colors[vid] = random_colors[i]; 50 | } 51 | } 52 | 53 | cluster_colored.set_vertex_colors(colors); 54 | cluster_colored.WritePly(data_dir + "bunny_uv_cluster.ply"); 55 | auto [boundary_edges_list, boundary_vertex_ids_list] = ugu::FindBoundaryLoops( 56 | mesh->vertex_indices(), static_cast(mesh->vertices().size())); 57 | 58 | for (size_t i = 0; i < boundary_edges_list.size(); i++) { 59 | ugu::LOGI("%d th boundary\n", i); 60 | std::vector boundary_vertices; 61 | for (size_t j = 0; j < boundary_edges_list[i].size(); j++) { 62 | ugu::LOGI("%d th vertex id %d\n", j, boundary_vertex_ids_list[i][j]); 63 | boundary_vertices.push_back( 64 | mesh->vertices()[boundary_vertex_ids_list[i][j]]); 65 | } 66 | ugu::Mesh tmp; 67 | tmp.set_vertices(boundary_vertices); 68 | tmp.WritePly(data_dir + "bunny_boundary_" + std::to_string(i) + ".ply"); 69 | } 70 | 71 | ugu::FaceAdjacency face_adjacency; 72 | face_adjacency.Init(static_cast(mesh->vertices().size()), 73 | mesh->vertex_indices()); 74 | 75 | auto [boundary_edges, boundary_vertex_ids] = 76 | face_adjacency.GetBoundaryEdges(); 77 | 78 | ugu::LOGI("boundary_edges\n"); 79 | for (const auto& p : boundary_edges) { 80 | ugu::LOGI("%d -> %d\n", p.first, p.second); 81 | } 82 | 83 | ugu::LOGI("\nboundary_vertex_ids\n"); 84 | for (const auto& vid : boundary_vertex_ids) { 85 | ugu::LOGI("%d\n", vid); 86 | } 87 | 88 | std::vector valid_vertex_table(mesh->vertices().size(), true); 89 | for (const auto& vid : boundary_vertex_ids) { 90 | valid_vertex_table[vid] = false; 91 | } 92 | 93 | mesh->RemoveVertices(valid_vertex_table); 94 | mesh->WritePly(data_dir + "bunny_boundary_removed.ply"); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /examples/ex07_inflation.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | 8 | #include "ugu/image_io.h" 9 | #include "ugu/image_proc.h" 10 | #include "ugu/inflation/inflation.h" 11 | #include "ugu/mesh.h" 12 | #include "ugu/util/image_util.h" 13 | #include "ugu/util/path_util.h" 14 | 15 | // test by bunny data with 6 views 16 | int main(int argc, char* argv[]) { 17 | (void)argc; 18 | (void)argv; 19 | 20 | // https://www.bandainamco-mirai.com/images/miraikomachi/miraikomachi_pose_neon03.png 21 | std::string data_dir = "../data/character/"; 22 | std::string img_path = data_dir + "miraikomachi_pose_neon03.png"; 23 | ugu::EnsureDirExists(data_dir); 24 | if (!ugu::FileExists(img_path)) { 25 | ugu::LOGE( 26 | "Please download " 27 | "https://www.bandainamco-mirai.com/images/miraikomachi/" 28 | "miraikomachi_pose_neon03.png and put it as %s\nSee Mirai Komachi " 29 | "informaiton https://www.miraikomachi.com/download/\n", 30 | img_path.c_str()); 31 | return 1; 32 | } 33 | 34 | ugu::Image4b rgba_org = ugu::imread(img_path, -1); 35 | 36 | ugu::Image4b rgba; 37 | ugu::resize(rgba_org, rgba, 38 | {480, static_cast(480 * static_cast(rgba_org.rows) / 39 | static_cast(rgba_org.cols))}, 40 | 0.0, 0.0); 41 | 42 | std::vector planes; 43 | ugu::Split(rgba, planes); 44 | 45 | ugu::Image1b mask = planes[3]; 46 | ugu::Erode(mask.clone(), &mask, 3); 47 | ugu::Erode(mask.clone(), &mask, 3); 48 | ugu::resize(mask.clone(), mask, ugu::Size(-1, -1), 0.5f, 0.5f); 49 | 50 | // Inflation 51 | ugu::Image1f height; 52 | ugu::Mesh mesh; 53 | ugu::Inflation(mask, height, mesh); 54 | ugu::Image1b vis_height; 55 | ugu::Depth2Gray(height, &vis_height, 0.f, 300.f); 56 | ugu::imwrite(data_dir + "00000_height.png", vis_height); 57 | 58 | mesh.WritePly(data_dir + "00000_height.ply"); 59 | 60 | ugu::Image3b color = ugu::Merge(planes[0], planes[1], planes[2]); 61 | ugu::InflationParams params; 62 | params.texture = &color; 63 | ugu::Inflation(mask, height, mesh, params); 64 | mesh.WriteObj(data_dir, "00000_height_single"); 65 | 66 | params.generate_back = true; 67 | params.back_texture_type = ugu::InflationBackTextureType::INPAINT; 68 | ugu::Inflation(mask, height, mesh, params); 69 | mesh.WriteObj(data_dir, "00000_height_double"); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /examples/ex08_inpaint.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include "ugu/inpaint/inpaint.h" 11 | #include "ugu/util/image_util.h" 12 | #include "ugu/image_io.h" 13 | #include "ugu/image_proc.h" 14 | 15 | // test by bunny data with 6 views 16 | int main(int argc, char* argv[]) { 17 | (void)argc; 18 | (void)argv; 19 | 20 | std::string data_dir = "../data/inpaint/"; 21 | std::string color_path = data_dir + "fruits.jpg"; 22 | std::string mask_path = data_dir + "fruits_scrabble.png"; 23 | 24 | ugu::Image1b mask = ugu::Imread(mask_path, 0); 25 | ugu::Image3b color = ugu::Imread(color_path); 26 | ugu::Image3b color_gt = color; 27 | ugu::Image3b color_scrabbled = color.clone(); 28 | 29 | // FMM 30 | ugu::Image1f fmm_dist; 31 | ugu::FastMarchingMethod(mask, fmm_dist); 32 | ugu::Image1b vis_fmm_dist; 33 | ugu::Depth2Gray(fmm_dist, &vis_fmm_dist, 0.f, 10.f); 34 | ugu::imwrite(data_dir + "00000_fmm_dist.png", vis_fmm_dist); 35 | 36 | for (int j = 0; j < color.rows; j++) { 37 | for (int i = 0; i < color.cols; i++) { 38 | if (mask.at(j, i) == 255) { 39 | auto& c = color_scrabbled.at(j, i); 40 | c[0] = 0; 41 | c[1] = 0; 42 | c[2] = 0; 43 | } 44 | } 45 | } 46 | 47 | ugu::imwrite(data_dir + "fruits_scrabbled.png", color_scrabbled); 48 | ugu::Image3b tmp = color_scrabbled.clone(); 49 | ugu::Inpaint(mask, tmp, 5.f, ugu::InpaintMethod::TELEA); 50 | ugu::imwrite(data_dir + "fruits_inpainted_telea.png", tmp); 51 | 52 | tmp = color_scrabbled.clone(); 53 | ugu::Inpaint(mask, color, 5.f, ugu::InpaintMethod::NAIVE); 54 | ugu::imwrite(data_dir + "fruits_inpainted_naive.png", color); 55 | 56 | // Inpaint float 57 | ugu::Image3f color_scrabbled_f; 58 | ugu::ConvertTo(color_scrabbled, &color_scrabbled_f, 1.f / 255.f); 59 | ugu::Image3f tmp_f = color_scrabbled_f.clone(); 60 | ugu::Image3b color_scrabbled_f_vis; 61 | 62 | ugu::Inpaint(mask, tmp_f, 5.f, ugu::InpaintMethod::NAIVE); 63 | ugu::ConvertTo(tmp_f, &color_scrabbled_f_vis, 255.f); 64 | ugu::imwrite(data_dir + "fruits_inpainted_naive_f.png", 65 | color_scrabbled_f_vis); 66 | 67 | tmp_f = color_scrabbled_f.clone(); 68 | ugu::Inpaint(mask, tmp_f, 5.f, ugu::InpaintMethod::TELEA); 69 | ugu::ConvertTo(tmp_f, &color_scrabbled_f_vis, 255.f); 70 | ugu::imwrite(data_dir + "fruits_inpainted_telea_f.png", 71 | color_scrabbled_f_vis); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /examples/ex11_synthesis.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #if __has_include("../third_party/nanopm/nanopm.h") 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "ugu/image.h" 13 | #include "ugu/image_io.h" 14 | #include "ugu/synthesis/bdsim.h" 15 | 16 | int main(int argc, char* argv[]) { 17 | (void)argc; 18 | (void)argv; 19 | 20 | std::string data_dir = "../data/synthesis/"; 21 | std::string data_name = "217_s.png"; 22 | ugu::Image3b src = ugu::Imread(data_dir + data_name); 23 | ugu::Image3b dst; 24 | 25 | ugu::BdsimParams params; 26 | params.patch_size = 11; 27 | params.verbose = true; 28 | params.debug_dir = "./"; 29 | params.target_size.height = static_cast(src.rows * 0.4); 30 | params.target_size.width = static_cast(src.cols * 0.4); 31 | 32 | ugu::Synthesize(src, dst, params); 33 | 34 | ugu::imwrite("out.png", dst); 35 | 36 | return 0; 37 | } 38 | #else 39 | int main(int argc, char* argv[]) { 40 | (void)argc; 41 | (void)argv; 42 | return 0; 43 | } 44 | #endif -------------------------------------------------------------------------------- /examples/ex14_thread.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/image.h" 7 | #include "ugu/image_io.h" 8 | #include "ugu/timer.h" 9 | #include "ugu/util/thread_util.h" 10 | 11 | namespace { 12 | 13 | void ForSpeedTest() { 14 | const ugu::Image3b color_org = 15 | ugu::Imread("../data/inpaint/fruits.jpg"); 16 | ugu::Image3b color; 17 | const int ksize = 31; 18 | const int hksize = ksize / 2; 19 | ugu::Timer<> timer; 20 | 21 | // Simple box blur 22 | auto loop_body = [&](int j) { 23 | for (int i = 0; i < color.cols; i++) { 24 | double ave[3] = {0, 0, 0}; 25 | int count = 0; 26 | for (int jj = -hksize; jj <= hksize; jj++) { 27 | for (int ii = -hksize; ii <= hksize; ii++) { 28 | if (j + jj < 0 || color.rows - 1 < j + jj || i + ii < 0 || 29 | color.cols - 1 < i + ii) { 30 | continue; 31 | } 32 | const auto& pix_org = color_org.at(j + jj, i + ii); 33 | ave[0] += pix_org[0]; 34 | ave[1] += pix_org[1]; 35 | ave[2] += pix_org[2]; 36 | count++; 37 | } 38 | } 39 | ave[0] /= count; 40 | ave[1] /= count; 41 | ave[2] /= count; 42 | 43 | ave[0] = std::max(std::min(255.0, ave[0]), 0.0); 44 | ave[1] = std::max(std::min(255.0, ave[1]), 0.0); 45 | ave[2] = std::max(std::min(255.0, ave[2]), 0.0); 46 | 47 | auto& pix = color.at(j, i); 48 | pix[0] = static_cast(ave[0]); 49 | pix[1] = static_cast(ave[1]); 50 | pix[2] = static_cast(ave[2]); 51 | } 52 | }; 53 | 54 | // Naive 55 | color = color_org.clone(); 56 | timer.Start(); 57 | for (int j = 0; j < color.rows; j++) { 58 | loop_body(j); 59 | } 60 | timer.End(); 61 | ugu::LOGI("Naive: %f ms\n", timer.elapsed_msec()); 62 | ugu::imwrite("fruits_blur_naive.jpg", color); 63 | 64 | // OpenMP 65 | color = color_org.clone(); 66 | timer.Start(); 67 | #pragma omp parallel for 68 | for (int j = 0; j < color.rows; j++) { 69 | loop_body(j); 70 | } 71 | timer.End(); 72 | ugu::LOGI("OpenMP: %f ms\n", timer.elapsed_msec()); 73 | ugu::imwrite("fruits_blur_omp.jpg", color); 74 | 75 | // ugu::parallel_for 76 | color = color_org.clone(); 77 | timer.Start(); 78 | ugu::parallel_for(0, color.rows, loop_body); 79 | timer.End(); 80 | ugu::LOGI("ugu::parallel_for: %f ms\n", timer.elapsed_msec()); 81 | ugu::imwrite("fruits_blur_ugu.jpg", color); 82 | } 83 | 84 | } // namespace 85 | 86 | int main(int argc, char* argv[]) { 87 | (void)argc; 88 | (void)argv; 89 | 90 | ForSpeedTest(); 91 | 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /examples/ex16_textrans.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | 8 | #include "ugu/image_io.h" 9 | #include "ugu/image_proc.h" 10 | #include "ugu/inpaint/inpaint.h" 11 | #include "ugu/textrans/texture_transfer.h" 12 | #include "ugu/timer.h" 13 | #include "ugu/util/image_util.h" 14 | #include "ugu/util/io_util.h" 15 | 16 | int main(int argc, char* argv[]) { 17 | (void)argc; 18 | (void)argv; 19 | 20 | std::string data_dir = "../data/spot/"; 21 | std::string src_obj_path = data_dir + "spot_triangulated.obj"; 22 | std::string dst_obj_path = data_dir + "spot_remesh.obj"; 23 | ugu::Timer<> timer; 24 | ugu::Mesh src_mesh, dst_mesh; 25 | src_mesh.LoadObj(src_obj_path, data_dir); 26 | dst_mesh.LoadObj(dst_obj_path, data_dir); 27 | 28 | ugu::Image3f src_tex; 29 | ugu::ConvertTo(src_mesh.materials()[0].diffuse_tex, &src_tex); 30 | 31 | ugu::TexTransNoCorrespOutput output; 32 | 33 | timer.Start(); 34 | ugu::TexTransNoCorresp(src_tex, src_mesh, dst_mesh, 1024, 1024, output); 35 | timer.End(); 36 | ugu::LOGI("TexTransNoCorresp: %f ms", timer.elapsed_msec()); 37 | 38 | std::string out_basename = data_dir + "spot_remesh_texture"; 39 | ugu::Image3b dst_tex_vis; 40 | ugu::ConvertTo(output.dst_tex, &dst_tex_vis); 41 | ugu::imwrite(out_basename + "_org.png", dst_tex_vis); 42 | ugu::imwrite(out_basename + "_mask.png", output.dst_mask); 43 | 44 | ugu::Image3b srcpos_tex_vis = 45 | ugu::ColorizeImagePosMap(output.srcpos_tex, src_tex.cols, src_tex.rows); 46 | ugu::imwrite(out_basename + "_srcpos.png", srcpos_tex_vis); 47 | 48 | ugu::Image3f remaped; 49 | ugu::Remap(src_tex, output.srcpos_tex, output.dst_mask, remaped); 50 | ugu::Image3b remaped_vis; 51 | ugu::ConvertTo(remaped, &remaped_vis); 52 | ugu::imwrite(out_basename + "_remap.png", remaped_vis); 53 | 54 | ugu::Image1b inpaint_mask; 55 | ugu::Not(output.dst_mask, &inpaint_mask); 56 | // ugu::Dilate(inpaint_mask.clone(), &inpaint_mask, 3); 57 | ugu::Image3b dst_tex_vis_inpainted = dst_tex_vis.clone(); 58 | ugu::Inpaint(inpaint_mask, dst_tex_vis_inpainted, 3.f); 59 | ugu::imwrite(out_basename + ".png", dst_tex_vis_inpainted); 60 | 61 | ugu::Image3b nn_fid_tex_vis; 62 | ugu::FaceId2Color(output.nn_fid_tex, &nn_fid_tex_vis); 63 | ugu::imwrite(out_basename + "_fid.png", nn_fid_tex_vis); 64 | ugu::WriteFaceIdAsText(output.nn_fid_tex, out_basename + "_fid.txt"); 65 | 66 | ugu::Image3b nn_pos_tex_vis = ugu::ColorizePosMap(output.nn_pos_tex); 67 | ugu::imwrite(out_basename + "_pos.png", nn_pos_tex_vis); 68 | 69 | ugu::Image3b nn_bary_tex_vis = ugu::ColorizeBarycentric(output.nn_bary_tex); 70 | ugu::imwrite(out_basename + "_bary.png", nn_bary_tex_vis); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /examples/ex20_manifold.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/face_adjacency.h" 7 | #include "ugu/util/geom_util.h" 8 | 9 | int main(int argc, char* argv[]) { 10 | (void)argc; 11 | (void)argv; 12 | 13 | std::string data_dir = "../data/"; 14 | 15 | auto nonmanifold_mesh = ugu::MakePlane(1.f); 16 | std::vector vertices = nonmanifold_mesh->vertices(); 17 | std::vector faces = nonmanifold_mesh->vertex_indices(); 18 | // std::vector vertices = nonmanifold_mesh->vertices(); 19 | 20 | vertices.push_back({1.f, 1.f, 1.f}); 21 | vertices.push_back({1.f, 0.f, 1.f}); 22 | vertices.push_back({1.f, -1.f, 2.f}); 23 | vertices.push_back({-1.f, -1.f, 1.f}); 24 | faces.push_back({0, 1, 4}); 25 | faces.push_back({0, 1, 5}); 26 | faces.push_back({0, 2, 6}); 27 | faces.push_back({2, 3, 7}); 28 | 29 | nonmanifold_mesh->set_vertices(vertices); 30 | nonmanifold_mesh->set_vertex_indices(faces); 31 | nonmanifold_mesh->set_uv({}); 32 | nonmanifold_mesh->set_uv_indices({}); 33 | nonmanifold_mesh->set_default_material(); 34 | 35 | nonmanifold_mesh->CalcNormal(); 36 | 37 | nonmanifold_mesh->CalcStats(); 38 | 39 | nonmanifold_mesh->WriteObj(data_dir, "nonmanifold"); 40 | 41 | ugu::FaceAdjacency fa; 42 | fa.Init(static_cast(nonmanifold_mesh->vertices().size()), 43 | nonmanifold_mesh->vertex_indices()); 44 | auto nonmanifold_vtx = fa.GetNonManifoldVertices(); 45 | for (const auto& v : nonmanifold_vtx) { 46 | ugu::LOGI("nonmanifold vid %d\n", v); 47 | } 48 | 49 | std::vector clean_vertices; 50 | std::vector clean_faces; 51 | ugu::CleanGeom(nonmanifold_mesh->vertices(), 52 | nonmanifold_mesh->vertex_indices(), clean_vertices, 53 | clean_faces); 54 | 55 | auto clean_mesh = ugu::Mesh::Create(); 56 | clean_mesh->set_vertices(clean_vertices); 57 | clean_mesh->set_vertex_indices(clean_faces); 58 | clean_mesh->set_default_material(); 59 | 60 | clean_mesh->CalcNormal(); 61 | 62 | clean_mesh->CalcStats(); 63 | 64 | fa.Init(static_cast(clean_mesh->vertices().size()), 65 | clean_mesh->vertex_indices()); 66 | nonmanifold_vtx = fa.GetNonManifoldVertices(); 67 | for (const auto& v : nonmanifold_vtx) { 68 | ugu::LOGI("nonmanifold vid %d\n", v); 69 | } 70 | 71 | clean_mesh->WriteObj(data_dir, "nonmanifold_cleaned"); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /examples/ex22_line.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | 8 | #include "ugu/line.h" 9 | #include "ugu/mesh.h" 10 | #include "ugu/timer.h" 11 | 12 | namespace { 13 | 14 | const uint32_t seed = 0; 15 | static std::default_random_engine engine(seed); 16 | 17 | void SavePoints(const std::vector& lines, 18 | const std::string& path) { 19 | ugu::MeshPtr mesh = ugu::Mesh::Create(); 20 | 21 | std::vector vertices; 22 | std::vector normals; 23 | std::vector colors; 24 | 25 | for (const auto& l : lines) { 26 | vertices.push_back(l.a.cast()); 27 | normals.push_back(l.d.cast()); 28 | colors.push_back( 29 | (Eigen::Vector3f(l.d.cast()) + Eigen::Vector3f::Constant(1.f)) * 30 | 0.5f * 255.f); 31 | } 32 | 33 | mesh->set_vertices(vertices); 34 | mesh->set_normals(normals); 35 | mesh->set_vertex_colors(colors); 36 | 37 | mesh->WritePly(path); 38 | } 39 | 40 | } // namespace 41 | 42 | int main(int argc, char* argv[]) { 43 | (void)argc; 44 | (void)argv; 45 | 46 | int num = 1000; 47 | 48 | double p_mu = 0.0; 49 | double p_sigma = 0.02; 50 | double d_mu = 0.0; 51 | double d_sigma = ugu::pi / 6.0; 52 | std::normal_distribution p_dist(p_mu, p_sigma); 53 | std::normal_distribution d_dist(d_mu, d_sigma); 54 | std::uniform_real_distribution a_dist; 55 | 56 | auto spiral = [&](double a, double b, double t) { 57 | double x = a * std::exp(b * t) * std::cos(t); 58 | double y = a * std::exp(b * t) * std::sin(t); 59 | double z = t; 60 | double dxdt = x * b - y; 61 | double dydt = y * b + x; 62 | double dzdt = 1; 63 | return std::tuple(Eigen::Vector3d(x, y, z), 64 | Eigen::Vector3d(dxdt, dydt, dzdt)); 65 | }; 66 | 67 | std::vector clean; 68 | 69 | #if 0 70 | // mm scale 71 | Eigen::Vector3d d(1.0, 0.0, 0.0); 72 | Eigen::Vector3d offset(0.0, 0.33 / 2, 0.33 / 2); 73 | double step = 0.05; 74 | for (int i = 0; i < num; i++) { 75 | ugu::Line3d l; 76 | l.a = d * step * i; 77 | l.d = d; 78 | clean.push_back(l); 79 | 80 | ugu::Line3d l2; 81 | l2.a = d * step * i + offset; 82 | l2.d = d; 83 | clean.push_back(l2); 84 | } 85 | #endif 86 | for (int i = 0; i < num; i++) { 87 | double a = 1.27; 88 | double b = 0.35; 89 | double t = double(i) / num * ugu::pi * 2; 90 | ugu::Line3d l; 91 | std::tie(l.a, l.d) = spiral(a, b, t); 92 | l.d.normalize(); 93 | clean.push_back(l); 94 | } 95 | 96 | SavePoints(clean, "clean.ply"); 97 | 98 | std::vector unclean; 99 | for (size_t i = 0; i < clean.size(); i++) { 100 | for (int j = 0; j < 20; j++) { 101 | ugu::Line3d l; 102 | l.a = clean[i].a + 103 | Eigen::Vector3d(p_dist(engine), p_dist(engine), p_dist(engine)); 104 | Eigen::Vector3d axis(a_dist(engine), a_dist(engine), a_dist(engine)); 105 | axis.normalize(); 106 | Eigen::Matrix3d R = Eigen::AngleAxisd(d_dist(engine), axis).matrix(); 107 | l.d = R * clean[i].d; 108 | unclean.push_back(l); 109 | } 110 | } 111 | SavePoints(unclean, "unclean.ply"); 112 | 113 | ugu::Timer<> timer; 114 | std::vector fused; 115 | double tau_s = 0.002; 116 | double r_nei = 0.2; // 1/10 from the paper. Possibly the paper is wrong 117 | // because 2mm radius is too big for hair strands. 118 | double sigma_p = 0.1; 119 | double sigma_d = ugu::pi / 6.0; 120 | timer.Start(); 121 | ugu::LineClustering(unclean, fused, tau_s, r_nei, sigma_p, sigma_d); 122 | timer.End(); 123 | ugu::LOGI("LineClustering: %f ms\n", timer.elapsed_msec()); 124 | SavePoints(fused, "fused.ply"); 125 | 126 | double s = 0.1; 127 | double tau_r = 0.1; 128 | double tau_a = ugu::pi / 6.0; // 30 deg 129 | 130 | std::vector> strands; 131 | timer.Start(); 132 | ugu::GenerateStrands(fused, strands, s, tau_r, tau_a); 133 | timer.End(); 134 | ugu::LOGI("GenerateStrands: %f ms\n", timer.elapsed_msec()); 135 | std::vector> colors; 136 | for (const auto& line : strands) { 137 | std::vector single; 138 | for (const auto& l : line) { 139 | single.push_back((l.d + Eigen::Vector3d::Constant(1.f)) * 0.5 * 255); 140 | } 141 | colors.push_back(single); 142 | } 143 | ugu::WriteObjLine(strands, "fused.obj", colors); 144 | 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /examples/ex25_superpixel.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #if defined(UGU_USE_OPENCV) && __has_include("opencv2/ximgproc.hpp") 7 | #include "ugu/image_io.h" 8 | #include "ugu/superpixel/superpixel.h" 9 | #include "ugu/util/image_util.h" 10 | #include "ugu/util/path_util.h" 11 | 12 | using namespace ugu; 13 | 14 | namespace { 15 | void MeanColorPerLabel(const Image3b& img, const Image1i& labels, int label_num, 16 | Image3b& mean_color) { 17 | mean_color = Image3b::zeros(img.rows, img.cols); 18 | 19 | for (int i = 0; i < label_num; i++) { 20 | Vec3d mean, stddev; 21 | Image1b mask = labels == i; 22 | meanStdDev(img, mean, stddev, mask); 23 | 24 | Vec3b mean3b(static_cast(mean[0]), static_cast(mean[1]), 25 | static_cast(mean[2])); 26 | mean_color.setTo(mean3b, mask); 27 | } 28 | } 29 | 30 | } // namespace 31 | 32 | int main() { 33 | std::string out_dir = "../out/ex25/"; 34 | EnsureDirExists(out_dir); 35 | 36 | ImageBase img, bgr; 37 | Image1i labels; 38 | Image1b contour_mask; 39 | Image3b img_vis; 40 | Image3b contour_mask3b; 41 | Image3b mean_color; 42 | int sp_num; 43 | 44 | std::string data_path = "../data/inpaint/fruits.jpg"; 45 | // data_path = "../data/spot/spot_texture.png"; 46 | img = imread(data_path); 47 | bgr = img.clone(); 48 | 49 | int region_size = 20; 50 | float ruler = 30.f; 51 | int min_element_size_percent = 10; 52 | int num_iterations = 10; 53 | size_t min_clusters = 2; 54 | double max_color_diff = 40.0; 55 | double max_boundary_strengh_for_merge = 80.0; 56 | double max_boundary_strengh_for_terminate = 120.0; 57 | SimilarColorClusteringMode mode = SimilarColorClusteringMode::MEAN; 58 | 59 | auto slic_proc = [&](const ImageBase& img) { 60 | Slic(img, labels, contour_mask, sp_num, region_size, ruler, 61 | min_element_size_percent, num_iterations); 62 | FaceId2RandomColor(labels, &img_vis); 63 | contour_mask3b = Merge(contour_mask, contour_mask, contour_mask); 64 | contour_mask3b.copyTo(img_vis, contour_mask3b); 65 | addWeighted(img_vis.clone(), 0.3, bgr, 0.7, 0, img_vis); 66 | MeanColorPerLabel(bgr, labels, sp_num, mean_color); 67 | }; 68 | 69 | slic_proc(img); 70 | imwrite(out_dir + "rgb_slic.png", img_vis); 71 | imwrite(out_dir + "rgb_slic_mean.png", mean_color); 72 | std::cout << "#Cluster: " << sp_num << std::endl; 73 | 74 | cvtColor(img.clone(), img, cv::COLOR_BGR2HSV); 75 | slic_proc(img); 76 | imwrite(out_dir + "hsv_slic.png", img_vis); 77 | imwrite(out_dir + "hsv_slic_mean.png", mean_color); 78 | std::cout << "#Cluster: " << sp_num << std::endl; 79 | 80 | SimilarColorClustering(bgr, labels, sp_num, region_size, ruler, 81 | min_element_size_percent, num_iterations, min_clusters, 82 | max_color_diff, max_boundary_strengh_for_merge, 83 | max_boundary_strengh_for_terminate, 84 | SimilarColorClusteringMode::MEAN); 85 | FaceId2RandomColor(labels, &img_vis); 86 | addWeighted(img_vis.clone(), 0.3, bgr, 0.7, 0, img_vis); 87 | MeanColorPerLabel(bgr, labels, sp_num, mean_color); 88 | imwrite(out_dir + "rgb_cluster_mean.png", img_vis); 89 | imwrite(out_dir + "rgb_cluster_mean_mean.png", mean_color); 90 | std::cout << "#Cluster: " << sp_num << std::endl; 91 | 92 | SimilarColorClustering(bgr, labels, sp_num, region_size, ruler, 93 | min_element_size_percent, num_iterations, min_clusters, 94 | max_color_diff, max_boundary_strengh_for_merge, 95 | max_boundary_strengh_for_terminate, 96 | SimilarColorClusteringMode::MEDIAN); 97 | FaceId2RandomColor(labels, &img_vis); 98 | addWeighted(img_vis.clone(), 0.3, bgr, 0.7, 0, img_vis); 99 | MeanColorPerLabel(bgr, labels, sp_num, mean_color); 100 | imwrite(out_dir + "rgb_cluster_median.png", img_vis); 101 | imwrite(out_dir + "rgb_cluster_median_mean.png", mean_color); 102 | std::cout << "#Cluster: " << sp_num << std::endl; 103 | 104 | return 0; 105 | } 106 | #else 107 | int main() { return 0; } 108 | #endif -------------------------------------------------------------------------------- /examples/ex26_poisson_recon.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/external/external.h" 7 | #include "ugu/inpaint/inpaint.h" 8 | #include "ugu/parameterize/parameterize.h" 9 | #include "ugu/textrans/texture_transfer.h" 10 | #include "ugu/timer.h" 11 | #include "ugu/util/geom_util.h" 12 | #include "ugu/util/raster_util.h" 13 | #include "ugu/voxel/marching_cubes.h" 14 | #include "ugu/voxel/voxel.h" 15 | using namespace ugu; 16 | 17 | void Textrans(MeshPtr src, MeshPtr recon) { 18 | Timer<> timer; 19 | timer.Start(); 20 | recon->CalcFaceNormal(); 21 | timer.End(); 22 | ugu::LOGI("CalcFaceNormal %f ms\n", timer.elapsed_msec()); 23 | 24 | timer.Start(); 25 | Parameterize(*recon.get(), 512, 512, ugu::ParameterizeUvType::kSmartUv); 26 | timer.End(); 27 | ugu::LOGI("Parameterize %f ms\n", timer.elapsed_msec()); 28 | 29 | timer.Start(); 30 | Image3f trans_tex; 31 | Image1b trans_mask; 32 | TexTransFromColoredPoints(*src.get(), *recon.get(), 512, 512, trans_tex, 33 | trans_mask); 34 | timer.End(); 35 | ugu::LOGI("TexTransFromColoredPoints %f ms\n", timer.elapsed_msec()); 36 | 37 | recon->set_default_material(); 38 | auto mats = recon->materials(); 39 | trans_tex.convertTo(mats[0].diffuse_tex, CV_8UC3); 40 | 41 | Not(trans_mask.clone(), &trans_mask); 42 | timer.Start(); 43 | Inpaint(trans_mask, mats[0].diffuse_tex); 44 | timer.End(); 45 | ugu::LOGI("Inpaint %f ms\n", timer.elapsed_msec()); 46 | 47 | recon->set_materials(mats); 48 | } 49 | 50 | int main() { 51 | Timer<> timer; 52 | 53 | MeshPtr src = Mesh::Create(); 54 | src->LoadObj("../data/bunny/bunny.obj"); 55 | 56 | std::vector colors; 57 | src->SplitMultipleUvVertices(); 58 | FetchVertexAttributeFromTexture(src->materials()[0].diffuse_tex, src->uv(), 59 | colors); 60 | src->set_vertex_colors(colors); 61 | 62 | timer.Start(); 63 | MeshPtr recon = PoissonRecon(src, 7); 64 | timer.End(); 65 | ugu::LOGI("PoissonRecon %f ms\n", timer.elapsed_msec()); 66 | 67 | Textrans(src, recon); 68 | 69 | if (recon != nullptr) { 70 | recon->WriteObj("../data/bunny/", "bunny_spr"); 71 | } 72 | 73 | { 74 | timer.Start(); 75 | ugu::VoxelGrid voxel_grid; 76 | float resolution = 77 | (src->stats().bb_max - src->stats().bb_min).maxCoeff() / 32; 78 | Eigen::Vector3f offset = Eigen::Vector3f::Ones() * resolution * 2; 79 | voxel_grid.Init(src->stats().bb_max + offset, src->stats().bb_min - offset, 80 | resolution); 81 | ugu::VoxelUpdateOption option = ugu::GenFuseDepthDefaultOption(resolution); 82 | timer.End(); 83 | ugu::LOGI("Init %f ms\n", timer.elapsed_msec()); 84 | // src->set_normals({}); 85 | timer.Start(); 86 | EstimateNormalsFromPoints(src.get()); 87 | timer.End(); 88 | ugu::LOGI("Normal estimation %f ms\n", timer.elapsed_msec()); 89 | // src->WriteObj("../data/bunny/bunny_tmp.obj"); 90 | 91 | timer.Start(); 92 | ugu::FusePoints(src->vertices(), src->normals(), option, voxel_grid, 93 | src->vertex_colors()); 94 | timer.End(); 95 | ugu::LOGI("PointCloud -> SDF %f ms\n", timer.elapsed_msec()); 96 | 97 | auto pc_fused = ugu::Mesh::Create(); 98 | timer.Start(); 99 | ugu::MarchingCubes(voxel_grid, pc_fused.get(), 0.0, true); 100 | timer.End(); 101 | ugu::LOGI("Marching Cubes %f ms\n", timer.elapsed_msec()); 102 | 103 | Textrans(src, pc_fused); 104 | 105 | pc_fused->WriteObj("../data/bunny/bunny_mc.obj"); 106 | } 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /examples/ex27_math.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/timer.h" 7 | #include "ugu/util/math_util.h" 8 | 9 | using namespace ugu; 10 | 11 | int main() { 12 | Timer<> timer; 13 | 14 | Pca pca; 15 | 16 | Eigen::MatrixXd data; 17 | data.resize(3, 100); 18 | data.setRandom(); 19 | 20 | // eigen values must match 21 | // eigen vectors must match except sign 22 | 23 | std::cout << "data_num (" << data.cols() << ") > data_dim (" << data.rows() 24 | << ")" << std::endl; 25 | // this case eigendecomposition is faster 26 | timer.Start(); 27 | pca.Compute(data); 28 | timer.End(); 29 | std::cout << "SVD: " << timer.elapsed_msec() << " ms" << std::endl; 30 | std::cout << pca.coeffs << std::endl; 31 | std::cout << pca.vecs << std::endl; 32 | 33 | timer.Start(); 34 | pca.Compute(data, true, true, false); 35 | timer.End(); 36 | std::cout << "Eigendecomposition: " << timer.elapsed_msec() << " ms" 37 | << std::endl; 38 | std::cout << pca.coeffs << std::endl; 39 | std::cout << pca.vecs << std::endl; 40 | 41 | std::cout << std::endl; 42 | 43 | data.transposeInPlace(); 44 | 45 | std::cout << "data_num (" << data.cols() << ") < data_dim (" << data.rows() 46 | << ")" << std::endl; 47 | // this case svd is faster 48 | timer.Start(); 49 | pca.Compute(data); 50 | timer.End(); 51 | std::cout << "SVD: " << timer.elapsed_msec() << " ms" << std::endl; 52 | std::cout << pca.coeffs << std::endl; 53 | // std::cout << pca.vecs << std::endl; 54 | 55 | timer.Start(); 56 | pca.Compute(data, true, true, false); 57 | timer.End(); 58 | std::cout << "Eigendecomposition: " << timer.elapsed_msec() << " ms" 59 | << std::endl; 60 | std::cout << pca.coeffs << std::endl; 61 | // std::cout << pca.vecs << std::endl; 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /examples/ex28_curvature.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/curvature/curvature.h" 7 | #include "ugu/mesh.h" 8 | #include "ugu/timer.h" 9 | #include "ugu/util/image_util.h" 10 | 11 | using namespace ugu; 12 | 13 | int main() { 14 | Timer<> timer; 15 | 16 | MeshPtr mesh = Mesh::Create(); 17 | mesh->LoadObj("../data/bunny/bunny.obj"); 18 | 19 | std::vector curvature; 20 | std::vector internal_angles; 21 | CurvatureGaussian(mesh->vertices(), mesh->vertex_indices(), curvature, 22 | internal_angles); 23 | std::vector area = 24 | BarycentricCellArea(mesh->vertices(), mesh->vertex_indices()); 25 | std::vector normalized_curvature(curvature.size()); 26 | float max_c = std::numeric_limits::lowest(); 27 | float min_c = std::numeric_limits::max(); 28 | for (size_t i = 0; i < curvature.size(); i++) { 29 | normalized_curvature[i] = curvature[i] / (std::max(area[i], 1e-10f)); 30 | if (normalized_curvature[i] < min_c) { 31 | min_c = normalized_curvature[i]; 32 | } 33 | if (max_c < normalized_curvature[i]) { 34 | max_c = normalized_curvature[i]; 35 | } 36 | } 37 | std::cout << "max/min: " << max_c << "/" << min_c << std::endl; 38 | std::vector sorted_normalized_curvature = normalized_curvature; 39 | float r = 0.1f; 40 | std::sort(sorted_normalized_curvature.begin(), 41 | sorted_normalized_curvature.end()); 42 | max_c = sorted_normalized_curvature[static_cast( 43 | (1.f - r) * sorted_normalized_curvature.size())]; 44 | min_c = sorted_normalized_curvature[static_cast( 45 | r * sorted_normalized_curvature.size())]; 46 | std::cout << "90%/10%: " << max_c << " " << min_c << std::endl; 47 | for (auto& c : normalized_curvature) { 48 | c = std::clamp((c - min_c) / (max_c - min_c), 0.f, 1.f); 49 | } 50 | 51 | std::vector colors = Colorize(normalized_curvature); 52 | 53 | mesh->set_vertex_colors(colors); 54 | 55 | mesh->WriteObj("../data_out/ex28.obj"); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /examples/ex29_editing.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/editing/poisson_mesh_editing.h" 7 | #include "ugu/mesh.h" 8 | #include "ugu/timer.h" 9 | #include "ugu/util/io_util.h" 10 | 11 | using namespace ugu; 12 | 13 | int main() { 14 | Timer<> timer; 15 | 16 | MeshPtr pinned = Mesh::Create(); 17 | pinned->LoadObj("../data/cylinder/cylinder.obj"); 18 | 19 | std::vector pinned_boundary_vids = 20 | LoadTxtAsVector("../data/cylinder/boundary.txt"); 21 | 22 | MeshPtr floating = Mesh::Create(); 23 | floating->LoadObj("../data/face/mediapipe_face.obj"); 24 | 25 | std::vector floating_boundary_vids = 26 | LoadTxtAsVector("../data/face/boundary.txt"); 27 | 28 | timer.Start(); 29 | MeshPtr merged = PoissonMeshMerging(pinned, pinned_boundary_vids, floating, 30 | floating_boundary_vids); 31 | timer.End(); 32 | std::cout << "PoissonMeshMerging: " << timer.elapsed_msec() << " ms." 33 | << std::endl; 34 | merged->WriteObj("../data_out/ex29.obj"); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][Debug##Default] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | [Window][View 0] 7 | Pos=60,60 8 | Size=208,628 9 | Collapsed=0 10 | 11 | [Window][View 1] 12 | Pos=60,60 13 | Size=208,628 14 | Collapsed=0 15 | 16 | [Window][General] 17 | Pos=60,60 18 | Size=103,77 19 | Collapsed=0 20 | 21 | -------------------------------------------------------------------------------- /include/ugu/accel/bvh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "ugu/accel/bvh_base.h" 10 | #include "ugu/accel/bvh_naive.h" 11 | #include "ugu/accel/bvh_nanort.h" 12 | 13 | namespace ugu { 14 | 15 | template 16 | BvhPtr GetDefaultBvh() { 17 | BvhPtr bvh; 18 | #ifdef UGU_USE_NANORT 19 | bvh = std::make_shared>(); 20 | #else 21 | bvh = std::make_shared>(); 22 | #endif 23 | return bvh; 24 | } 25 | 26 | } // namespace ugu 27 | -------------------------------------------------------------------------------- /include/ugu/accel/kdtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "ugu/accel/kdtree_base.h" 10 | #include "ugu/accel/kdtree_naive.h" 11 | #include "ugu/accel/kdtree_nanoflann.h" 12 | 13 | namespace ugu { 14 | 15 | template 16 | KdTreePtr GetDefaultKdTreeDynamic() { 17 | KdTreePtr kdtree; 18 | #ifdef UGU_USE_NANOFLANN 19 | kdtree = std::make_shared>(); 20 | #else 21 | kdtree = std::make_shared>(); 22 | #endif 23 | return kdtree; 24 | } 25 | 26 | template 27 | KdTreePtr GetDefaultKdTree() { 28 | KdTreePtr kdtree; 29 | #ifdef UGU_USE_NANOFLANN 30 | kdtree = std::make_shared>(); 31 | #else 32 | kdtree = std::make_shared>(); 33 | #endif 34 | return kdtree; 35 | } 36 | 37 | template 38 | KdTreeUniquePtr GetDefaultUniqueKdTreeDynamic() { 39 | KdTreeUniquePtr kdtree; 40 | #ifdef UGU_USE_NANOFLANN 41 | kdtree = std::make_unique>(); 42 | #else 43 | kdtree = std::make_unique>(); 44 | #endif 45 | return kdtree; 46 | } 47 | 48 | template 49 | KdTreeUniquePtr GetDefaultUniqueKdTree() { 50 | KdTreeUniquePtr kdtree; 51 | #ifdef UGU_USE_NANOFLANN 52 | kdtree = std::make_unique>(); 53 | #else 54 | kdtree = std::make_unique>(); 55 | #endif 56 | return kdtree; 57 | } 58 | } // namespace ugu 59 | -------------------------------------------------------------------------------- /include/ugu/accel/kdtree_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "ugu/common.h" 16 | 17 | namespace ugu { 18 | 19 | struct KdTreeSearchResult { 20 | size_t index; 21 | double dist; 22 | }; 23 | 24 | using KdTreeSearchResults = std::vector; 25 | 26 | template 27 | class KdTree { 28 | public: 29 | using KdPoint = Eigen::Matrix; 30 | virtual ~KdTree() {} 31 | virtual bool Build() = 0; 32 | virtual void Clear() = 0; 33 | virtual bool IsInitialized() const = 0; 34 | virtual void SetData(const std::vector& data) = 0; 35 | virtual void SetMaxLeafDataNum(int max_leaf_data_num) = 0; 36 | 37 | virtual KdTreeSearchResults SearchNn(const KdPoint& query) const = 0; 38 | virtual KdTreeSearchResults SearchKnn(const KdPoint& query, 39 | const size_t& k) const = 0; 40 | virtual KdTreeSearchResults SearchRadius(const KdPoint& query, 41 | const double& r) const = 0; 42 | }; 43 | 44 | template 45 | using KdTreePtr = std::shared_ptr>; 46 | 47 | template 48 | using KdTreeUniquePtr = std::unique_ptr>; 49 | 50 | } // namespace ugu 51 | -------------------------------------------------------------------------------- /include/ugu/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define UGU_EIGEN_WARNING_LEVEL 0 17 | #define UGU_OPENCV_WARNING_LEVEL 0 18 | 19 | #ifdef _WIN32 20 | #pragma warning(push, UGU_EIGEN_WARNING_LEVEL) 21 | #endif 22 | #include "Eigen/Geometry" 23 | #include "ugu/eigen_util.h" 24 | #ifdef _WIN32 25 | #pragma warning(pop) 26 | #endif 27 | 28 | #include "ugu/log.h" 29 | 30 | #ifdef UGU_USE_OPENCV 31 | #ifdef _WIN32 32 | #pragma warning(push, UGU_OPENCV_WARNING_LEVEL) 33 | #endif 34 | #include "opencv2/core.hpp" 35 | #ifdef _WIN32 36 | #pragma warning(pop) 37 | #endif 38 | #endif 39 | 40 | #define UGU_FLOATING_POINT_ONLY_TEMPLATE \ 41 | template ::value, \ 43 | std::nullptr_t>::type = nullptr> 44 | 45 | namespace ugu { 46 | 47 | static inline const double pi = 3.14159265358979323846; 48 | 49 | // Interpolation method in texture uv space 50 | enum class ColorInterpolation { 51 | kNn = 0, // Nearest Neigbor 52 | kBilinear = 1 // Bilinear interpolation 53 | }; 54 | 55 | enum class CoordinateType { OpenCV, OpenGL }; 56 | 57 | float radians(const float& degrees); 58 | double radians(const double& degrees); 59 | 60 | float degrees(const float& radians); 61 | double degrees(const double& radians); 62 | 63 | float Fov2FocalPix(float fov, float pix, bool is_deg = false); 64 | float FocalPix2Fov(float f, float pix, bool to_deg = false); 65 | 66 | #ifdef UGU_USE_OPENCV 67 | using cv::saturate_cast; 68 | #else 69 | template 70 | T saturate_cast(const TT& v); 71 | 72 | template 73 | T saturate_cast(const TT& v) { 74 | return static_cast( 75 | std::clamp(v, static_cast(std::numeric_limits::lowest()), 76 | static_cast(std::numeric_limits::max()))); 77 | } 78 | #endif 79 | } // namespace ugu 80 | -------------------------------------------------------------------------------- /include/ugu/correspondence/correspondence_finder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/accel/kdtree.h" 9 | #include "ugu/common.h" 10 | 11 | namespace ugu { 12 | 13 | struct Corresp { 14 | int32_t fid = -1; 15 | Eigen::Vector2f uv = Eigen::Vector2f::Zero(); 16 | Eigen::Vector3f p = 17 | Eigen::Vector3f::Constant(std::numeric_limits::lowest()); 18 | float signed_dist = std::numeric_limits::lowest(); 19 | float abs_dist = std::numeric_limits::max(); 20 | Eigen::Vector3f n = 21 | Eigen::Vector3f::Constant(std::numeric_limits::lowest()); 22 | }; 23 | 24 | class CorrespFinder { 25 | public: 26 | virtual ~CorrespFinder() {} 27 | virtual bool Init(const std::vector& verts, 28 | const std::vector& verts_faces, 29 | const std::vector& vert_normals = {}) = 0; 30 | virtual Corresp Find(const Eigen::Vector3f& src_p) const = 0; 31 | virtual std::vector FindKnn(const Eigen::Vector3f& src_p, 32 | const uint32_t& nn_num = 10u) const = 0; 33 | }; 34 | using CorrespFinderPtr = std::shared_ptr; 35 | 36 | class KDTreeCorrespFinder : public CorrespFinder { 37 | public: 38 | KDTreeCorrespFinder(){}; 39 | template 40 | static std::shared_ptr Create(Args... args) { 41 | return std::make_shared(args...); 42 | } 43 | bool Init(const std::vector& verts, 44 | const std::vector& verts_faces, 45 | const std::vector& vert_normals = {}) override; 46 | Corresp Find(const Eigen::Vector3f& src_p) const override; 47 | std::vector FindKnn(const Eigen::Vector3f& src_p, 48 | const uint32_t& nn_num = 10u) const override; 49 | 50 | private: 51 | std::unique_ptr> m_tree; 52 | 53 | std::vector m_verts; 54 | std::vector m_vert_normals; 55 | std::vector m_verts_faces; 56 | std::vector m_face_centroids; 57 | // ax + by + cz + d = 0 58 | std::vector m_face_planes; 59 | }; 60 | using KDTreeCorrespFinderPtr = std::shared_ptr; 61 | 62 | } // namespace ugu 63 | -------------------------------------------------------------------------------- /include/ugu/cuda/image.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ugu/camera.h" 4 | #include "ugu/image.h" 5 | 6 | namespace ugu { 7 | 8 | void BoxFilterCuda(Image3b& img, int kernel); 9 | 10 | void BilateralFilterCuda(const Image3b& src, Image3b& dst, int kernel); 11 | 12 | bool ComputeNormalsCuda(const std::vector& depths, 13 | const std::vector& cameras, 14 | std::vector& normals, 15 | float max_connect_z_diff = 1e6f, int step = 1, 16 | bool gl_coord = false); 17 | bool ComputeNormalsCuda( 18 | const int num_images, const int width, const int height, 19 | std::vector& h_depths, std::vector& h_normals, 20 | const std::vector& h_fx, const std::vector& h_fy, 21 | const std::vector& h_cx, const std::vector& h_cy, 22 | float max_connect_z_diff = 1e6f, int step = 1, bool gl_coord = false); 23 | 24 | class NormalComputerCuda { 25 | public: 26 | NormalComputerCuda(); 27 | NormalComputerCuda(int width, int height, int num_images, const float* h_fx, 28 | const float* h_fy, const float* h_cx, const float* h_cy, 29 | float max_connect_z_diff = 1e6f, int step = 1, 30 | bool gl_coord = false, const float* h_R = nullptr, 31 | const float* h_t = nullptr); 32 | ~NormalComputerCuda(); 33 | 34 | void Init(int width, int height, int num_images, const float* h_fx, 35 | const float* h_fy, const float* h_cx, const float* h_cy, 36 | float max_connect_z_diff = 1e6f, int step = 1, 37 | bool gl_coord = false, const float* h_R = nullptr, 38 | const float* h_t = nullptr); 39 | 40 | void ComputeNormals(const float* h_depths); 41 | 42 | void GetNormalsCpu(float* h_normals) const; 43 | void GetPointsCpu(float* h_points) const; 44 | 45 | const float* GetNormalsGpu() const; 46 | const float* GetPointsGpu() const; 47 | 48 | private: 49 | class Impl; 50 | std::unique_ptr impl_; 51 | }; 52 | 53 | } // namespace ugu 54 | -------------------------------------------------------------------------------- /include/ugu/cuda/knn.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Eigen/Core" 7 | 8 | namespace ugu { 9 | 10 | struct KNnGridSearchResult { 11 | size_t index; 12 | double dist; 13 | }; 14 | 15 | class KNnGridCuda { 16 | public: 17 | KNnGridCuda(); 18 | ~KNnGridCuda(); 19 | 20 | void SetData(const std::vector& data); 21 | void SetVoxelLen(float voxel_len); 22 | void Build(); 23 | std::vector> SearchKnn( 24 | const std::vector& queries, uint32_t k) const; 25 | std::vector SearchKnn(const Eigen::Vector3f& query, 26 | uint32_t k) const; 27 | 28 | private: 29 | class Impl; 30 | std::unique_ptr pimpl_; 31 | }; 32 | } // namespace ugu 33 | -------------------------------------------------------------------------------- /include/ugu/cuda/voxel.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/include/ugu/cuda/voxel.h -------------------------------------------------------------------------------- /include/ugu/curvature/curvature.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "ugu/common.h" 6 | 7 | namespace ugu { 8 | 9 | bool CurvatureGaussian(const std::vector& vertices, 10 | const std::vector& faces, 11 | std::vector& curvature, 12 | std::vector& internal_angles); 13 | 14 | std::vector BarycentricCellArea( 15 | const std::vector& vertices, 16 | const std::vector& faces); 17 | 18 | } -------------------------------------------------------------------------------- /include/ugu/decimation/decimation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "ugu/mesh.h" 10 | 11 | namespace ugu { 12 | 13 | enum class QSlimType { XYZ, XYZ_UV }; 14 | 15 | bool RandomDecimation(MeshPtr mesh, QSlimType type, int32_t target_face_num, 16 | int32_t target_vertex_num, bool keep_geom_boundary = true, 17 | bool keep_uv_boundary = true); 18 | 19 | // TODO: Only valid for keep_geom_boundary = true, keep_uv_boundary = true 20 | bool QSlim(MeshPtr mesh, QSlimType type, int32_t target_face_num, 21 | int32_t target_vertex_num, bool keep_geom_boundary = true, 22 | bool keep_uv_boundary = true); 23 | 24 | } // namespace ugu -------------------------------------------------------------------------------- /include/ugu/discrete/bin_packer_2d.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/rect.h" 9 | 10 | namespace ugu { 11 | 12 | // Reference: https://blackpawn.com/texts/lightmaps/default.html 13 | // To get better result, rects should be sorted in advance 14 | bool BinPacking2D(const std::vector& rects, std::vector* packed_pos, 15 | std::vector* available_rects, int x_min, int x_max, 16 | int y_min, int y_max); 17 | bool BinPacking2D(const std::vector& rects, 18 | std::vector* packed_pos, 19 | std::vector* available_rects, float x_min, 20 | float x_max, float y_min, float y_max); 21 | 22 | Image3b DrawPackedRects(const std::vector& packed_rects, int w, int h); 23 | Image3b DrawPackedRects(const std::vector& packed_rects, int w, int h); 24 | } // namespace ugu 25 | -------------------------------------------------------------------------------- /include/ugu/editing/poisson_mesh_editing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/mesh.h" 9 | 10 | namespace ugu { 11 | 12 | MeshPtr PoissonMeshMerging(const MeshPtr pinned, 13 | const std::vector pinned_boundary_vids, 14 | const MeshPtr floating, 15 | const std::vector floating_boundary_vids); 16 | bool PoissonMeshMerging(const std::vector pinned_verts, 17 | const std::vector pinned_indices, 18 | const std::vector pinned_boundary_vids, 19 | const std::vector floating_verts, 20 | const std::vector floating_indices, 21 | const std::vector floating_boundary_vids, 22 | std::vector& merged_verts, 23 | std::vector& merged_indices); 24 | 25 | } // namespace ugu 26 | -------------------------------------------------------------------------------- /include/ugu/eigen_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #ifdef _WIN32 9 | #pragma warning(push, 0) 10 | #endif 11 | #include "Eigen/Core" 12 | #ifdef _WIN32 13 | #pragma warning(pop) 14 | #endif 15 | 16 | #include 17 | 18 | static_assert(3 <= EIGEN_WORLD_VERSION); 19 | 20 | // From 3.3, Eigen::Index is provided 21 | // http://eigen.tuxfamily.org/index.php?title=3.3 22 | #if (3 == EIGEN_WORLD_VERSION) && (EIGEN_MAJOR_VERSION < 3) 23 | namespace Eigen { 24 | typedef std::ptrdiff_t Index; 25 | } 26 | #endif 27 | 28 | namespace std { 29 | 30 | template 31 | struct hash> { 32 | // https://wjngkoh.wordpress.com/2015/03/04/c-hash-function-for-eigen-matrix-and-vector/ 33 | size_t operator()(const Eigen::Matrix& matrix) const { 34 | size_t seed = 0; 35 | for (Eigen::Index i = 0; i < matrix.size(); ++i) { 36 | Scalar elem = *(matrix.data() + i); 37 | seed ^= 38 | std::hash()(elem) + 0x9e3779b9 + (seed << 6) + (seed >> 2); 39 | } 40 | return seed; 41 | } 42 | }; 43 | 44 | } // namespace std 45 | -------------------------------------------------------------------------------- /include/ugu/external/external.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "ugu/mesh.h" 10 | #include "ugu/texturing/texture_mapper.h" 11 | 12 | namespace ugu { 13 | 14 | bool FastQuadricMeshSimplification(const Mesh& src, int target_face_num, 15 | Mesh* decimated); 16 | 17 | bool MvsTexturing(const std::vector>& keyframes, 18 | Mesh* mesh, Mesh* debug_mesh = nullptr, 19 | const std::string& save_path = "", 20 | const std::string& save_debug_path = ""); 21 | 22 | bool LibiglLscm(const std::vector& vertices, 23 | const std::vector& vertex_indices, 24 | const std::vector& boundary, 25 | std::vector& uvs); 26 | 27 | bool LibiglLscm(const std::vector& vertices, 28 | const std::vector& vertex_indices, int tex_w, 29 | int tex_h, const std::vector& cluster_areas, 30 | const std::vector>& clusters, 31 | const std::vector>& cluster_fids, 32 | const std::vector& cluster_weights, 33 | std::vector& uvs, 34 | std::vector& uv_indices); 35 | 36 | bool LibiglLscm(const std::vector& vertices, 37 | const std::vector& vertex_indices, int tex_w, 38 | int tex_h, std::vector& uvs, 39 | std::vector& uv_indices); 40 | 41 | bool LibiglLscm(Mesh& mesh, int tex_w, int tex_h); 42 | 43 | MeshPtr PoissonRecon( 44 | const std::vector& points, 45 | const std::vector& normals, 46 | const std::vector& colors = std::vector(), 47 | int depth = 8, int width = 0, float scale = 1.1f, bool linear_fit = false, 48 | int n_threads = -1, bool verbose = false); 49 | 50 | MeshPtr PoissonRecon(const MeshPtr& src, int depth = 8, int width = 0, 51 | float scale = 1.1f, bool linear_fit = false, 52 | int n_threads = -1, bool verbose = false); 53 | 54 | } // namespace ugu 55 | -------------------------------------------------------------------------------- /include/ugu/geodesic/geodesic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "ugu/mesh.h" 10 | 11 | #ifdef _WIN32 12 | #pragma warning(push, UGU_EIGEN_WARNING_LEVEL) 13 | #endif 14 | #include "Eigen/SparseCore" 15 | #ifdef _WIN32 16 | #pragma warning(pop) 17 | #endif 18 | 19 | namespace ugu { 20 | 21 | enum class GeodesicComputeMethod { DIJKSTRA, FAST_MARCHING_METHOD }; 22 | 23 | bool ComputeGeodesicDistance( 24 | const Mesh& mesh, int src_vid, Eigen::SparseMatrix& edge_dists, 25 | std::vector& dists, std::vector& min_path_edges, 26 | GeodesicComputeMethod method = GeodesicComputeMethod::FAST_MARCHING_METHOD); 27 | 28 | bool ComputeGeodesicDistance( 29 | const Mesh& mesh, const std::vector& src_vids, 30 | Eigen::SparseMatrix& edge_dists, std::vector& dists, 31 | std::vector& min_path_edges, 32 | GeodesicComputeMethod method = GeodesicComputeMethod::FAST_MARCHING_METHOD); 33 | 34 | } // namespace ugu 35 | -------------------------------------------------------------------------------- /include/ugu/image_io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/image.h" 9 | 10 | #ifdef UGU_USE_OPENCV 11 | #ifdef _WIN32 12 | #pragma warning(push, UGU_OPENCV_WARNING_LEVEL) 13 | #endif 14 | #include "opencv2/imgcodecs.hpp" 15 | #ifdef _WIN32 16 | #pragma warning(pop) 17 | #endif 18 | #endif 19 | 20 | namespace ugu { 21 | 22 | #ifdef UGU_USE_OPENCV 23 | 24 | using ImreadModes = cv::ImreadModes; 25 | 26 | using cv::imread; 27 | using cv::imwrite; 28 | 29 | #else 30 | 31 | bool WriteBinary(const ImageBase& img, const std::string& path); 32 | 33 | enum ImreadModes { 34 | IMREAD_UNCHANGED = -1, 35 | IMREAD_GRAYSCALE = 0, 36 | IMREAD_COLOR = 1, 37 | IMREAD_ANYDEPTH = 2, 38 | IMREAD_ANYCOLOR = 4, 39 | IMREAD_LOAD_GDAL = 8, 40 | IMREAD_REDUCED_GRAYSCALE_2 = 16, 41 | IMREAD_REDUCED_COLOR_2 = 17, 42 | IMREAD_REDUCED_GRAYSCALE_4 = 32, 43 | IMREAD_REDUCED_COLOR_4 = 33, 44 | IMREAD_REDUCED_GRAYSCALE_8 = 64, 45 | IMREAD_REDUCED_COLOR_8 = 65, 46 | IMREAD_IGNORE_ORIENTATION = 128, 47 | }; 48 | 49 | bool imwrite(const std::string& filename, const ImageBase& img, 50 | const std::vector& params = std::vector()); 51 | ImageBase imread(const std::string& filename, 52 | int flags = ImreadModes::IMREAD_COLOR); 53 | #endif 54 | 55 | template 56 | T Imread(const std::string& filename, int flags = ImreadModes::IMREAD_COLOR) { 57 | ImageBase loaded = imread(filename, flags); 58 | 59 | if (loaded.channels() != T().channels() || 60 | loaded.elemSize1() != T().elemSize1()) { 61 | LOGE("desired channel %d/%d, actual %d/%d\n", T().channels(), 62 | T().elemSize1(), loaded.channels(), loaded.elemSize1()); 63 | return T(); 64 | } 65 | 66 | return loaded; 67 | } 68 | 69 | } // namespace ugu 70 | -------------------------------------------------------------------------------- /include/ugu/inflation/inflation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/image.h" 9 | #include "ugu/mesh.h" 10 | #include "ugu/inpaint/inpaint.h" 11 | 12 | namespace ugu { 13 | 14 | enum class InflationMethod { 15 | BARAN // "Notes on Inflating Curves" [Baran and Lehtinen 2009]. 16 | // http://alecjacobson.com/weblog/media/notes-on-inflating-curves-2009-baran.pdf 17 | }; 18 | 19 | enum class InflationBackTextureType { MIRRORED, INPAINT }; 20 | 21 | struct InflationParams { 22 | // Common 23 | InflationMethod method = InflationMethod::BARAN; 24 | bool inverse = false; 25 | 26 | // For mesh 27 | Image3b* texture = nullptr; 28 | bool generate_back = false; 29 | InflationBackTextureType back_texture_type = 30 | InflationBackTextureType::MIRRORED; 31 | bool centering = true; 32 | 33 | // For InflationBackTextureType::INPAINT 34 | int inpaint_kernel_size = 5; 35 | InpaintMethod inpaint_method = InpaintMethod::TELEA; 36 | }; 37 | 38 | bool Inflation(const Image1b& mask, Image1f& height, 39 | const InflationParams& params = InflationParams()); 40 | bool Inflation(const Image1b& mask, Image1f& height, Mesh& mesh, 41 | const InflationParams& params = InflationParams()); 42 | 43 | } // namespace ugu 44 | -------------------------------------------------------------------------------- /include/ugu/inpaint/inpaint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | * 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "ugu/image.h" 10 | 11 | namespace ugu { 12 | 13 | // Implements Fast Marching Method (FMM) used in the following paper. 14 | // Compared to Distance Transfrom, FMM is slower but more accurate and more 15 | // smooth. Telea, Alexandru. "An image inpainting technique based on the fast 16 | // marching method." Journal of graphics tools 9.1 (2004): 23-34. 17 | void FastMarchingMethod(const Image1b& mask, Image1f& dist, 18 | float illegal_val = 0.f, float terminate_dist = -1.f); 19 | 20 | enum class InpaintMethod { NAIVE, TELEA }; 21 | 22 | void Inpaint(const Image1b& mask, Image3b& color, float inpaint_radius = 5.0f, 23 | InpaintMethod method = InpaintMethod::TELEA); 24 | 25 | void Inpaint(const Image1b& mask, Image3f& color, float inpaint_radius = 5.0f, 26 | InpaintMethod method = InpaintMethod::TELEA); 27 | 28 | } // namespace ugu 29 | -------------------------------------------------------------------------------- /include/ugu/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | namespace ugu { 9 | 10 | enum class LogLevel { 11 | kVerbose = 0, 12 | kDebug = 1, 13 | kInfo = 2, 14 | kWarning = 3, 15 | kError = 4, 16 | kNone = 5 17 | }; 18 | 19 | void set_log_level(LogLevel level); 20 | LogLevel get_log_level(); 21 | // To avoid conflict with macro 22 | #ifndef LOGD 23 | void LOGD(const char *format, ...); 24 | #endif 25 | #ifndef LOGI 26 | void LOGI(const char *format, ...); 27 | #endif 28 | #ifndef LOGW 29 | void LOGW(const char *format, ...); 30 | #endif 31 | #ifndef LOGE 32 | void LOGE(const char *format, ...); 33 | #endif 34 | 35 | } // namespace ugu 36 | -------------------------------------------------------------------------------- /include/ugu/optimizer/optimizer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "ugu/common.h" 13 | 14 | #ifdef _WIN32 15 | #pragma warning(push, UGU_EIGEN_WARNING_LEVEL) 16 | #endif 17 | #include "Eigen/Core" 18 | #include "Eigen/SparseCore" 19 | #ifdef _WIN32 20 | #pragma warning(pop) 21 | #endif 22 | 23 | namespace ugu { 24 | 25 | using OptParams = Eigen::VectorXd; 26 | using GradVec = Eigen::VectorXd; 27 | using Hessian = Eigen::MatrixXd; 28 | using OptIndex = Eigen::Index; 29 | 30 | using LossFunc = std::function; 31 | using GradFunc = std::function; 32 | using HessianFunc = std::function; 33 | // using JacobFunc 34 | // using HessianFunc 35 | 36 | struct OptimizerTerminateCriteria { 37 | int max_iter = 100; 38 | double eps = 1e-10; 39 | OptimizerTerminateCriteria(int max_iter = 10000, double eps = 1e-6) 40 | : max_iter(max_iter), eps(eps) {} 41 | 42 | bool isTerminated(int iter, double diff) const { 43 | diff = std::abs(diff); 44 | if (max_iter < 0 && 0 <= eps) { 45 | return diff < eps; 46 | } else if (0 <= max_iter && eps < 0) { 47 | return max_iter <= iter; 48 | } else if (0 <= max_iter && 0 <= eps) { 49 | return (diff < eps) || (max_iter <= iter); 50 | } 51 | throw std::invalid_argument("max_iter or eps must be positive"); 52 | } 53 | }; 54 | 55 | enum class LineSearchMethod { BACK_TRACKING }; 56 | 57 | struct OptimizerInput { 58 | OptParams init_param; 59 | LossFunc loss_func; 60 | GradFunc grad_func; 61 | double lr = 1.0; 62 | OptimizerTerminateCriteria terminate_criteria; 63 | HessianFunc hessian_func; 64 | OptIndex LBFGS_memoery_num = 10; 65 | Eigen::SparseMatrix LBFGS_init; 66 | bool use_line_search = false; 67 | LineSearchMethod line_search_method = LineSearchMethod::BACK_TRACKING; 68 | double line_search_max = 100.0; 69 | 70 | OptimizerInput() = delete; 71 | OptimizerInput( 72 | const OptParams& init_param, LossFunc loss_func, GradFunc grad_func, 73 | double lr = 0.001, 74 | OptimizerTerminateCriteria terminate_criteria = 75 | OptimizerTerminateCriteria(), 76 | HessianFunc hessian_func = HessianFunc(), int LBFGS_memoery_num = 10, 77 | Eigen::SparseMatrix LBFGS_init = Eigen::SparseMatrix(), 78 | bool use_line_search = false, 79 | LineSearchMethod line_search_method = LineSearchMethod::BACK_TRACKING, 80 | double line_search_max = 100.0) 81 | : init_param(init_param), 82 | loss_func(loss_func), 83 | grad_func(grad_func), 84 | lr(lr), 85 | terminate_criteria(terminate_criteria), 86 | hessian_func(hessian_func), 87 | LBFGS_memoery_num(LBFGS_memoery_num), 88 | LBFGS_init(LBFGS_init), 89 | use_line_search(use_line_search), 90 | line_search_method(line_search_method), 91 | line_search_max(line_search_max) { 92 | if (this->LBFGS_memoery_num < 1) { 93 | LBFGS_memoery_num = 10; 94 | } 95 | 96 | if (LBFGS_init.rows() != init_param.rows()) { 97 | this->LBFGS_init = 98 | Eigen::SparseMatrix(init_param.rows(), init_param.rows()); 99 | this->LBFGS_init.setIdentity(); 100 | } 101 | }; 102 | }; 103 | 104 | struct OptimizerOutput { 105 | double best = std::numeric_limits::max(); 106 | OptParams best_param; 107 | GradVec best_grad; 108 | int best_iter = 0; 109 | 110 | std::vector val_history; 111 | std::vector param_history; 112 | std::vector grad_history; 113 | 114 | void Clear() { 115 | best = std::numeric_limits::max(); 116 | best_grad.setZero(); 117 | best_param.setZero(); 118 | best_iter = 0; 119 | val_history.clear(); 120 | param_history.clear(); 121 | grad_history.clear(); 122 | } 123 | }; 124 | 125 | GradFunc GenNumericalGrad(LossFunc loss_func, double h); 126 | HessianFunc GenNumericalHessian(LossFunc loss_func, double h); 127 | 128 | void GradientDescent(const OptimizerInput& input, OptimizerOutput& output); 129 | void Newton(const OptimizerInput& input, OptimizerOutput& output); 130 | 131 | enum class QuasiNewtonMethod { LBFGS }; 132 | 133 | void QuasiNewton(const OptimizerInput& input, OptimizerOutput& output, 134 | QuasiNewtonMethod method = QuasiNewtonMethod::LBFGS); 135 | 136 | } // namespace ugu 137 | -------------------------------------------------------------------------------- /include/ugu/parameterize/parameterize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/mesh.h" 9 | 10 | namespace ugu { 11 | 12 | enum class ParameterizeUvType { kSimpleTriangles = 0, kSmartUv = 1 }; 13 | 14 | bool Parameterize( 15 | Mesh& mesh, int tex_w = 1024, int tex_h = 1024, 16 | ParameterizeUvType type = ParameterizeUvType::kSimpleTriangles); 17 | 18 | bool Parameterize( 19 | const std::vector& vertices, 20 | const std::vector& faces, 21 | const std::vector& face_normals, 22 | std::vector& uvs, std::vector& uv_faces, 23 | int tex_w = 1024, int tex_h = 1024, 24 | ParameterizeUvType type = ParameterizeUvType::kSimpleTriangles); 25 | 26 | bool OrthoProjectToXY(const Eigen::Vector3f& project_normal, 27 | const std::vector& points_3d, 28 | std::vector& points_2d, 29 | bool align_longest_axis_x = true, bool normalize = true, 30 | bool keep_aspect = true, bool align_top_y = true); 31 | 32 | bool PackUvIslands( 33 | const std::vector& cluster_areas, 34 | const std::vector>& clusters, 35 | const std::vector>& cluster_uvs, 36 | const std::vector>& cluster_sub_faces, 37 | const std::vector>& cluster_fids, size_t num_faces, 38 | int tex_w, int tex_h, std::vector& uvs, 39 | std::vector& uv_faces, bool flip_v = true, 40 | const std::vector& cluster_weights = std::vector()); 41 | 42 | } // namespace ugu -------------------------------------------------------------------------------- /include/ugu/plane.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/common.h" 9 | #include "ugu/line.h" 10 | 11 | namespace ugu { 12 | 13 | UGU_FLOATING_POINT_ONLY_TEMPLATE 14 | struct Plane { 15 | // nx + d = 0 16 | Eigen::Matrix n; 17 | T d = static_cast(0); 18 | Plane(){}; 19 | ~Plane(){}; 20 | Plane(const Eigen::Matrix& n, T d) : n(n.normalized()), d(d) {} 21 | Plane(const Eigen::Matrix& p0, const Eigen::Matrix& p1, 22 | const Eigen::Matrix& p2, 23 | const Eigen::Matrix& n_hint = Eigen::Matrix::Zero()) { 24 | Init(p0, p1, p2, n_hint); 25 | } 26 | 27 | bool IsNormalSide(const Eigen::Matrix& p) const { 28 | return d > -(n.dot(p)); 29 | } 30 | 31 | bool CalcIntersctionPoint(const Line3& line, T& t, 32 | Eigen::Matrix& p) const { 33 | // https://risalc.info/src/line-plane-intersection-point.html 34 | T h = -d; 35 | T denom = n.dot(line.d); 36 | if (std::abs(denom) < std::numeric_limits::epsilon()) { 37 | return false; 38 | } 39 | t = (h - n.dot(line.a)) / denom; 40 | p = line.a + t * line.d; 41 | return true; 42 | } 43 | 44 | float SignedDist(const Eigen::Matrix& p) const { 45 | // (p + tn).dot(n) + d = 0 46 | T t = -d - p.dot(n); 47 | // positive: upper, negative, lower 48 | return t; 49 | } 50 | 51 | Eigen::Matrix Project(const Eigen::Matrix& p) const { 52 | // (p + tn).dot(n) + d = 0 53 | return p + SignedDist(p) * n; 54 | } 55 | 56 | void Init( 57 | const Eigen::Matrix& p0, const Eigen::Matrix& p1, 58 | const Eigen::Matrix& p2, 59 | const Eigen::Matrix& n_hint = Eigen::Matrix::Zero()) { 60 | n = (p1 - p0).cross(p2 - p0).normalized(); 61 | d = -n.dot(p0); 62 | 63 | if (T(0.01) < n_hint.norm()) { 64 | if (n_hint.normalized().dot(n) < 0) { 65 | n = T(-1) * n; 66 | } 67 | } 68 | } 69 | }; 70 | using Planef = Plane; 71 | using Planed = Plane; 72 | 73 | bool EstimatePlaneLeastSquares( 74 | const std::vector& points, Planef& plane, 75 | const Eigen::Vector3f& normal_hint = Eigen::Vector3f::Zero()); 76 | 77 | struct PlaneEstimationStat { 78 | // Both 79 | std::vector inliers; // close & similar normal 80 | float inlier_ratio = -1.f; 81 | 82 | std::vector outliers; // others 83 | 84 | std::vector uppers; // upper points including inliers and others 85 | float upper_ratio = 86 | -1.f; // upper points ratio, possibly for objects on the ground plane 87 | 88 | float area = -1.f; 89 | float area_ratio = -1.f; 90 | }; 91 | 92 | struct PlaneEstimationResult { 93 | Planef estimation; 94 | Planef refined_least_squares; 95 | PlaneEstimationStat stat; 96 | }; 97 | 98 | struct EstimateGroundPlaneRansacParam { 99 | uint32_t max_iter = 100; 100 | float inlier_angle_th = radians(45.f); 101 | float inliner_dist_th = -1.f; 102 | int32_t seed = 0; 103 | size_t candidates_num = 3; 104 | Eigen::Vector3f normal_hint = Eigen::Vector3f::Zero(); 105 | bool use_normal_hint = false; 106 | bool refine_least_squares = true; 107 | }; 108 | 109 | bool EstimateGroundPlaneRansac(const std::vector& points, 110 | const std::vector& normals, 111 | const EstimateGroundPlaneRansacParam& param, 112 | std::vector& candidates); 113 | 114 | } // namespace ugu 115 | -------------------------------------------------------------------------------- /include/ugu/point.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "image.h" 9 | 10 | #ifdef UGU_USE_OPENCV 11 | #ifdef _WIN32 12 | #pragma warning(push, UGU_OPENCV_WARNING_LEVEL) 13 | #endif 14 | #include "opencv2/core.hpp" 15 | #ifdef _WIN32 16 | #pragma warning(pop) 17 | #endif 18 | #endif 19 | 20 | namespace ugu { 21 | 22 | #ifdef UGU_USE_OPENCV 23 | 24 | using Point = cv::Point; 25 | 26 | #else 27 | 28 | template 29 | using Point_ = Vec_; 30 | 31 | class Point2i { 32 | public: 33 | int x = -1; 34 | int y = -1; 35 | Point2i(){}; 36 | Point2i(int x_, int y_) : x(x_), y(y_){}; 37 | ~Point2i(){}; 38 | }; 39 | 40 | using Point = Point2i; 41 | 42 | #endif 43 | 44 | enum class PointOnFaceType { 45 | NAMED_POINT_ON_TRIANGLE, 46 | POINT_ON_TRIANGLE, 47 | THREED_POINT 48 | }; 49 | 50 | struct PointOnFace { 51 | std::string name; 52 | uint32_t fid = ~0u; 53 | float u = -1.f; 54 | float v = -1.f; 55 | Eigen::Vector3f pos; 56 | }; 57 | 58 | std::vector LoadPoints(const std::string& json_path, 59 | const PointOnFaceType& type); 60 | 61 | void WritePoints(const std::string& json_path, 62 | const std::vector& points, 63 | const PointOnFaceType& type); 64 | 65 | } // namespace ugu 66 | -------------------------------------------------------------------------------- /include/ugu/rect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/image.h" 9 | #include "ugu/point.h" 10 | 11 | namespace ugu { 12 | 13 | #ifdef UGU_USE_OPENCV 14 | template 15 | using Rect_ = cv::Rect_; 16 | 17 | using Rect2i = cv::Rect2i; 18 | using Rect = cv::Rect; 19 | using Rect2f = cv::Rect2f; 20 | 21 | #else 22 | template 23 | struct Rect_ { 24 | T x, y; 25 | T width, height; 26 | T area() const { return width * height; } 27 | Point_ br() const { 28 | Point_ br; 29 | br[0] = x + width; 30 | br[1] = y + height; 31 | return br; 32 | } 33 | Point_ tl() const { 34 | Point_ tl; 35 | tl[0] = x; 36 | tl[1] = y; 37 | return tl; 38 | } 39 | Rect_(T _x, T _y, T _width, T _height) 40 | : x(_x), y(_y), width(_width), height(_height) {} 41 | Rect_() : x(0), y(0), width(0), height(0) {} 42 | ~Rect_() {} 43 | }; 44 | 45 | using Rect2i = Rect_; 46 | using Rect = Rect2i; 47 | using Rect2f = Rect_; 48 | 49 | #endif 50 | 51 | } // namespace ugu 52 | -------------------------------------------------------------------------------- /include/ugu/registration/nonrigid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/accel/bvh.h" 9 | #include "ugu/point.h" 10 | #include "ugu/registration/rigid.h" 11 | 12 | namespace ugu { 13 | 14 | // An implementation of the following paper 15 | // Amberg, Brian, Sami Romdhani, and Thomas Vetter. "Optimal step nonrigid ICP 16 | // algorithms for surface registration." 2007 IEEE conference on computer vision 17 | // and pattern recognition. IEEE, 2007. 18 | 19 | class NonRigidIcp { 20 | public: 21 | NonRigidIcp(); 22 | ~NonRigidIcp(); 23 | void SetThreadNum(int thread_num); 24 | void SetSrc(const Mesh& src, 25 | const Eigen::Affine3f& transform = Eigen::Affine3f::Identity()); 26 | void SetDst(const Mesh& dst); 27 | 28 | void SetSrcLandmarks(const std::vector& src_landmarks, 29 | const std::vector& betas = {}); 30 | void SetDstLandmarkPositions( 31 | const std::vector& dst_landmark_positions); 32 | 33 | bool Init(bool check_self_itersection = false, float angle_rad_th = 0.65f, 34 | bool dst_check_geometry_border = false, 35 | bool src_check_geometry_border = false); // Initialize KDTree etc. 36 | 37 | bool FindCorrespondences(); 38 | bool Registrate(double alpha = 1000.0, double gamma = 1.0, int max_iter = 10, 39 | double min_frobenius_norm_diff = 2.0); 40 | 41 | MeshPtr GetDeformedSrc() const; 42 | 43 | void SetCorrespNnNum(uint32_t nn_num); 44 | void SetCorrespNormalTh(float rad_th); 45 | void SetCorrespDistTh(float dist_th); 46 | void SetIgnoreVids(const std::set& ignore_vids); 47 | void SetIgnoreFaceIds(const std::set& ignore_face_ids); 48 | 49 | uint32_t GetCorrespNnNum() const; 50 | float GetCorrespNormalTh() const; 51 | float GetCorrespDistTh() const; 52 | const std::set& GetIgnoreVids() const; 53 | 54 | private: 55 | bool ValidateCorrespondence(size_t src_idx, const Corresp& corresp) const; 56 | 57 | MeshPtr m_src_org = nullptr; 58 | Eigen::Affine3f m_transform = Eigen::Affine3f::Identity(); 59 | MeshPtr m_src = nullptr; 60 | MeshPtr m_src_norm = nullptr; 61 | MeshPtr m_src_norm_deformed = nullptr; 62 | MeshPtr m_src_deformed = nullptr; 63 | MeshStats m_src_stats; 64 | MeshPtr m_dst = nullptr; 65 | MeshPtr m_dst_norm = nullptr; 66 | 67 | Eigen::Vector3f m_norm2org_scale, m_org2norm_scale; 68 | 69 | KDTreeCorrespFinderPtr m_corresp_finder = nullptr; 70 | std::vector m_corresp; 71 | std::vector m_target; 72 | 73 | std::vector> m_edges; 74 | std::vector m_weights_per_node; 75 | 76 | int m_num_theads = -1; 77 | 78 | std::vector m_src_landmarks; 79 | std::vector m_dst_landmark_positions, 80 | m_dst_landmark_positions_norm; 81 | std::vector m_betas; 82 | 83 | uint32_t m_corresp_nn_num = 10u; 84 | float m_angle_rad_th = 0.65f; 85 | float m_dist_th = -1.f; 86 | 87 | bool m_dst_check_geometry_border = false; 88 | std::unordered_set m_dst_border_fids; 89 | // [fid] -> {edge_pair, ...} 90 | std::unordered_map>> m_dst_border_edges; 91 | 92 | bool m_src_check_geometry_border = false; 93 | std::unordered_set m_src_border_vids; 94 | 95 | bool m_check_self_itersection = false; 96 | BvhPtr m_bvh = nullptr; 97 | 98 | bool m_rescale = true; 99 | 100 | std::set m_ignore_vids; 101 | }; 102 | 103 | } // namespace ugu -------------------------------------------------------------------------------- /include/ugu/registration/registration.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/registration/nonrigid.h" 9 | #include "ugu/registration/rigid.h" -------------------------------------------------------------------------------- /include/ugu/renderable_mesh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/mesh.h" 9 | #include "ugu/shader/shader.h" 10 | 11 | namespace ugu { 12 | 13 | struct Vertex { 14 | Eigen::Vector3f pos; 15 | Eigen::Vector3f nor; 16 | Eigen::Vector2f uv; 17 | Eigen::Vector3f col; 18 | Eigen::Vector3f id; // [0]: face id, [1]: geom id, [2]: for extension 19 | }; 20 | 21 | class RenderableMesh; 22 | using RenderableMeshPtr = std::shared_ptr; 23 | 24 | class RenderableMesh : public Mesh { 25 | public: 26 | 27 | RenderableMesh(const Mesh& mesh); 28 | RenderableMesh(); 29 | ~RenderableMesh(); 30 | 31 | static RenderableMeshPtr Create() { 32 | return std::make_shared(); 33 | } 34 | 35 | static RenderableMeshPtr Create(const Mesh& mesh) { 36 | return std::make_shared(mesh); 37 | } 38 | 39 | void Draw(const Shader &shader) const; 40 | 41 | void BindTextures(); 42 | void SetupMesh(int geo_id); 43 | void UpdateMesh(); // Update vertices and/or faces 44 | void ClearGlState() const; 45 | 46 | uint32_t VAO = ~0u; 47 | uint32_t VBO = ~0u; 48 | uint32_t EBO = ~0u; 49 | 50 | std::vector renderable_vertices; 51 | std::vector renderable_indices; 52 | std::vector flatten_indices; 53 | std::vector texture_ids; 54 | }; 55 | 56 | } // namespace ugu 57 | -------------------------------------------------------------------------------- /include/ugu/renderer/base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | namespace ugu { 9 | 10 | // Diffuse color 11 | enum class DiffuseColor { 12 | kNone = 0, // Default white color 13 | kTexture = 1, // From diffuse uv texture 14 | kVertex = 2 // From vertex color 15 | }; 16 | 17 | // Normal used for shading 18 | // Also returned as output normal 19 | enum class ShadingNormal { 20 | kFace = 0, // Face normal 21 | kVertex = 1 // Vertex normal. Maybe average of face normals 22 | }; 23 | 24 | // Diffuse shading 25 | // Light ray same to viewing ray is used for shading 26 | enum class DiffuseShading { 27 | kNone = 0, // No shading 28 | kLambertian = 1, // Lambertian reflectance model 29 | kOrenNayar = 30 | 2 // Simplified Oren-Nayar reflectatnce model described in wikipedia 31 | // https://en.wikipedia.org/wiki/Oren%E2%80%93Nayar_reflectance_model 32 | }; 33 | 34 | struct GBuffer { 35 | Image3b color; 36 | Image3f normal_cam; 37 | Image3f normal_wld; 38 | Image3f pos_cam; 39 | Image3f pos_wld; 40 | Image1f depth_01; 41 | Image1b stencil; 42 | Image1i face_id; 43 | Image3f uv; 44 | Image3f bary; 45 | Image1i geo_id; 46 | Image3b shaded; 47 | 48 | void Init(int w, int h) { 49 | color = Image3b::zeros(h, w); 50 | normal_cam = Image3f::zeros(h, w); 51 | normal_wld = Image3f::zeros(h, w); 52 | pos_cam = Image3f::zeros(h, w); 53 | pos_wld = Image3f::zeros(h, w); 54 | depth_01 = Image1f::zeros(h, w); 55 | stencil = Image1b::zeros(h, w); 56 | face_id = Image1i::zeros(h, w); 57 | uv = Image3f::zeros(h, w); 58 | bary = Image3f::zeros(h, w); 59 | geo_id = Image1i::zeros(h, w); 60 | shaded = Image3b::zeros(h, w); 61 | } 62 | 63 | void Reset() { 64 | color.setTo(0.0); 65 | normal_cam.setTo(0.0); 66 | normal_wld.setTo(0.0); 67 | pos_cam.setTo(0.0); 68 | pos_wld.setTo(0.0); 69 | depth_01.setTo(0.0); 70 | stencil.setTo(0.0); 71 | face_id.setTo(0.0); 72 | uv.setTo(0.0); 73 | bary.setTo(0.0); 74 | geo_id.setTo(0.0); 75 | shaded.setTo(0.0); 76 | } 77 | }; 78 | 79 | } // namespace ugu 80 | -------------------------------------------------------------------------------- /include/ugu/renderer/cpu/rasterizer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "ugu/renderer/cpu/renderer.h" 11 | 12 | namespace ugu { 13 | 14 | class Rasterizer : public RendererCpu { 15 | class Impl; 16 | std::unique_ptr pimpl_; 17 | 18 | public: 19 | Rasterizer(); 20 | ~Rasterizer() override; 21 | 22 | // Set option 23 | explicit Rasterizer(const RendererCpuOption& option); 24 | void set_option(const RendererCpuOption& option) override; 25 | 26 | // Set mesh 27 | void set_mesh(std::shared_ptr mesh) override; 28 | 29 | // Should call after set_mesh() and before Render() 30 | // Don't modify mesh outside after calling PrepareMesh() 31 | bool PrepareMesh() override; 32 | 33 | // Set camera 34 | void set_camera(std::shared_ptr camera) override; 35 | 36 | // Rendering all images 37 | // If you don't need some of them, pass nullptr 38 | bool Render(Image3b* color, Image1f* depth, Image3f* normal, Image1b* mask, 39 | Image1i* face_id) const override; 40 | 41 | // Rendering a image 42 | bool RenderColor(Image3b* color) const override; 43 | bool RenderDepth(Image1f* depth) const override; 44 | bool RenderNormal(Image3f* normal) const override; 45 | bool RenderMask(Image1b* mask) const override; 46 | bool RenderFaceId(Image1i* face_id) const override; 47 | 48 | // These Image1w* depth interfaces are prepared for widely used 16 bit 49 | // (unsigned short) and mm-scale depth image format 50 | bool RenderW(Image3b* color, Image1w* depth, Image3f* normal, Image1b* mask, 51 | Image1i* face_id) const override; 52 | bool RenderDepthW(Image1w* depth) const override; 53 | }; 54 | 55 | } // namespace ugu 56 | -------------------------------------------------------------------------------- /include/ugu/renderer/cpu/raytracer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "ugu/renderer/cpu/renderer.h" 11 | 12 | namespace ugu { 13 | 14 | class Raytracer : public RendererCpu { 15 | class Impl; 16 | std::unique_ptr pimpl_; 17 | 18 | public: 19 | Raytracer(); 20 | ~Raytracer() override; 21 | 22 | // Set option 23 | explicit Raytracer(const RendererCpuOption& option); 24 | void set_option(const RendererCpuOption& option) override; 25 | 26 | // Set mesh 27 | void set_mesh(std::shared_ptr mesh) override; 28 | 29 | // Should call after set_mesh() and before Render() 30 | // Don't modify mesh outside after calling PrepareMesh() 31 | bool PrepareMesh() override; 32 | 33 | // Set camera 34 | void set_camera(std::shared_ptr camera) override; 35 | 36 | // Rendering all images 37 | // If you don't need some of them, pass nullptr 38 | bool Render(Image3b* color, Image1f* depth, Image3f* normal, Image1b* mask, 39 | Image1i* face_id) const override; 40 | 41 | // Rendering a image 42 | bool RenderColor(Image3b* color) const override; 43 | bool RenderDepth(Image1f* depth) const override; 44 | bool RenderNormal(Image3f* normal) const override; 45 | bool RenderMask(Image1b* mask) const override; 46 | bool RenderFaceId(Image1i* face_id) const override; 47 | 48 | // These Image1w* depth interfaces are prepared for widely used 16 bit 49 | // (unsigned short) and mm-scale depth image format 50 | bool RenderW(Image3b* color, Image1w* depth, Image3f* normal, Image1b* mask, 51 | Image1i* face_id) const override; 52 | bool RenderDepthW(Image1w* depth) const override; 53 | }; 54 | 55 | } // namespace ugu 56 | -------------------------------------------------------------------------------- /include/ugu/renderer/cpu/renderer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | #include "ugu/camera.h" 12 | #include "ugu/mesh.h" 13 | #include "ugu/renderer/base.h" 14 | 15 | namespace ugu { 16 | 17 | struct RendererCpuOption { 18 | DiffuseColor diffuse_color{DiffuseColor::kNone}; 19 | // Meaningful only if DiffuseColor::kTexture is specified otherwise ignored 20 | ColorInterpolation interp{ColorInterpolation::kBilinear}; 21 | ShadingNormal shading_normal{ShadingNormal::kVertex}; 22 | DiffuseShading diffuse_shading{DiffuseShading::kNone}; 23 | 24 | float depth_scale{1.0f}; // Multiplied to output depth 25 | bool backface_culling{true}; // Back-face culling flag 26 | float oren_nayar_sigma{0.3f}; // Oren-Nayar's sigma 27 | 28 | RendererCpuOption() {} 29 | ~RendererCpuOption() {} 30 | void CopyTo(RendererCpuOption* dst) const { 31 | dst->diffuse_color = diffuse_color; 32 | dst->depth_scale = depth_scale; 33 | dst->interp = interp; 34 | dst->shading_normal = shading_normal; 35 | dst->diffuse_shading = diffuse_shading; 36 | dst->backface_culling = backface_culling; 37 | } 38 | }; 39 | 40 | // interface (pure abstract base class with no state or defined methods) for 41 | // renderer 42 | class RendererCpu { 43 | public: 44 | virtual ~RendererCpu() {} 45 | 46 | // Set option 47 | virtual void set_option(const RendererCpuOption& option) = 0; 48 | 49 | // Set mesh 50 | virtual void set_mesh(std::shared_ptr mesh) = 0; 51 | 52 | // Should call after set_mesh() and before Render() 53 | // Don't modify mesh outside after calling PrepareMesh() 54 | virtual bool PrepareMesh() = 0; 55 | 56 | // Set camera 57 | virtual void set_camera(std::shared_ptr camera) = 0; 58 | 59 | // Rendering all images 60 | // If you don't need some of them, pass nullptr 61 | virtual bool Render(Image3b* color, Image1f* depth, Image3f* normal, 62 | Image1b* mask, Image1i* face_id) const = 0; 63 | 64 | // Rendering a image 65 | virtual bool RenderColor(Image3b* color) const = 0; 66 | virtual bool RenderDepth(Image1f* depth) const = 0; 67 | virtual bool RenderNormal(Image3f* normal) const = 0; 68 | virtual bool RenderMask(Image1b* mask) const = 0; 69 | virtual bool RenderFaceId(Image1i* face_id) const = 0; 70 | 71 | // These Image1w* depth interfaces are prepared for widely used 16 bit 72 | // (unsigned short) and mm-scale depth image format 73 | virtual bool RenderW(Image3b* color, Image1w* depth, Image3f* normal, 74 | Image1b* mask, Image1i* face_id) const = 0; 75 | virtual bool RenderDepthW(Image1w* depth) const = 0; 76 | }; 77 | 78 | using RendererCpuPtr = std::shared_ptr; 79 | 80 | } // namespace ugu 81 | -------------------------------------------------------------------------------- /include/ugu/renderer/cpu/util_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | #include "ugu/renderer/cpu/renderer.h" 12 | 13 | namespace ugu { 14 | 15 | bool ValidateAndInitBeforeRender(bool mesh_initialized, 16 | std::shared_ptr camera, 17 | std::shared_ptr mesh, 18 | const RendererCpuOption& option, 19 | Image3b* color, Image1f* depth, 20 | Image3f* normal, Image1b* mask, 21 | Image1i* face_id); 22 | 23 | } // namespace ugu 24 | -------------------------------------------------------------------------------- /include/ugu/sfs/voxel_carver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | #include "ugu/camera.h" 12 | #include "ugu/common.h" 13 | #include "ugu/image.h" 14 | #include "ugu/mesh.h" 15 | #include "ugu/voxel/voxel.h" 16 | 17 | namespace ugu { 18 | 19 | struct VoxelCarverOption { 20 | Eigen::Vector3f bb_max; 21 | Eigen::Vector3f bb_min; 22 | Eigen::Vector3f resolution{0.1f, 0.1f, 23 | 0.1f}; // default is 10cm if input is m-scale 24 | bool sdf_minmax_normalize{true}; 25 | VoxelUpdateOption update_option; 26 | }; 27 | 28 | class VoxelCarver { 29 | VoxelCarverOption option_; 30 | std::unique_ptr voxel_grid_; 31 | 32 | public: 33 | VoxelCarver(); 34 | ~VoxelCarver(); 35 | explicit VoxelCarver(VoxelCarverOption option); 36 | void set_option(VoxelCarverOption option); 37 | bool Init(); 38 | bool Carve(const Camera& camera, const Image1b& silhouette, 39 | const Eigen::Vector2i& roi_min, const Eigen::Vector2i& roi_max, 40 | Image1f* sdf); 41 | bool Carve(const Camera& camera, const Image1b& silhouette, Image1f* sdf); 42 | bool Carve(const Camera& camera, const Image1b& silhouette); 43 | bool Carve(const std::vector& cameras, 44 | const std::vector& silhouettes); 45 | void ExtractVoxel(Mesh* mesh, bool inside_empty = false); 46 | void ExtractIsoSurface(Mesh* mesh, double iso_level = 0.0); 47 | }; 48 | 49 | } // namespace ugu 50 | -------------------------------------------------------------------------------- /include/ugu/shader/shader.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2023, unclearness 4 | * All rights reserved. 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "ugu/common.h" 12 | 13 | namespace ugu { 14 | 15 | enum class FragShaderType { WHITE, UNLIT, NORMAL, POS, UV, GBUF, DEFERRED, TEXT }; 16 | enum class VertShaderType { DEFAULT, GBUF, DEFERRED, TEXT }; 17 | 18 | class Shader { 19 | public: 20 | uint32_t ID = uint32_t(~0); 21 | FragShaderType frag_type = FragShaderType::UNLIT; 22 | VertShaderType vert_type = VertShaderType::DEFAULT; 23 | 24 | Shader(); 25 | ~Shader(); 26 | 27 | void SetFragType(const FragShaderType &frag_type); 28 | void SetVertType(const VertShaderType &frag_type); 29 | bool Prepare(); 30 | 31 | bool LoadStr(const std::string &vertex_code, const std::string &fragment_code, 32 | const std::string &geometry_code = ""); 33 | bool LoadFile(const std::string &vertex_path, 34 | const std::string &fragment_path, 35 | const std::string &geometry_path = ""); 36 | void Use(); 37 | void SetBool(const std::string &name, bool value) const; 38 | void SetInt(const std::string &name, int value) const; 39 | void SetFloat(const std::string &name, float value) const; 40 | void SetVec2(const std::string &name, const Eigen::Vector2f &value) const; 41 | void SetVec2(const std::string &name, float x, float y) const; 42 | void SetVec3(const std::string &name, const Eigen::Vector3f &value) const; 43 | void SetVec3(const std::string &name, float x, float y, float z) const; 44 | void SetVec4(const std::string &name, const Eigen::Vector4f &value) const; 45 | void SetVec4(const std::string &name, float x, float y, float z, 46 | float w) const; 47 | void SetMat2(const std::string &name, const Eigen::Matrix2f &mat) const; 48 | void SetMat3(const std::string &name, const Eigen::Matrix3f &mat) const; 49 | void SetMat4(const std::string &name, const Eigen::Matrix4f &mat) const; 50 | 51 | void SetVec2Array(const std::string &name, 52 | const std::vector &values) const; 53 | void SetVec3Array(const std::string &name, 54 | const std::vector &values) const; 55 | 56 | private: 57 | inline static uint32_t ID_counter = 0; 58 | }; 59 | } // namespace ugu 60 | -------------------------------------------------------------------------------- /include/ugu/superpixel/superpixel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/image.h" 9 | 10 | namespace ugu { 11 | 12 | void Slic(const ImageBase& img, Image1i& labels, Image1b& contour_mask, 13 | int& sp_num, int region_size = 20, float ruler = 30.f, 14 | int min_element_size_percent = 10, int num_iterations = 4); 15 | 16 | enum class SimilarColorClusteringMode { MEAN = 0, MEDIAN = 1 }; 17 | 18 | void SimilarColorClustering(const ImageBase& img, Image1i& labels, 19 | int& labels_num, int region_size = 20, 20 | float ruler = 30.f, 21 | int min_element_size_percent = 10, 22 | int num_iterations = 4, size_t min_clusters = 2, 23 | double max_color_diff = 40.0, 24 | double max_boundary_strengh_for_merge = 80.0, 25 | double max_boundary_strengh_for_terminate = 120.0, 26 | SimilarColorClusteringMode mode = SimilarColorClusteringMode::MEAN); 27 | 28 | } // namespace ugu 29 | -------------------------------------------------------------------------------- /include/ugu/synthesis/bdsim.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | * 5 | * Implementation of the following paper 6 | * 7 | * Simakov, Denis, et al. "Summarizing visual data using bidirectional 8 | * similarity." 2008 IEEE Conference on Computer Vision and Pattern Recognition. 9 | * IEEE, 2008. 10 | * 11 | */ 12 | 13 | #pragma once 14 | 15 | #if __has_include("../third_party/nanopm/nanopm.h") 16 | 17 | #include "ugu/image.h" 18 | 19 | namespace ugu { 20 | 21 | enum class BdsimPatchSearchMethod { BRUTE_FORCE, PATCH_MATCH }; 22 | enum class BdsimPatchDistanceType { SSD }; 23 | 24 | struct BdsimParams { 25 | float alpha = 0.5f; 26 | int patch_size = 7; 27 | BdsimPatchSearchMethod patch_search_method = 28 | BdsimPatchSearchMethod::PATCH_MATCH; 29 | BdsimPatchDistanceType distance_type = BdsimPatchDistanceType::SSD; 30 | int iteration_in_scale = 10; 31 | 32 | float rescale_ratio = 0.05f; 33 | Size target_size; 34 | 35 | bool verbose = false; 36 | std::string debug_dir = ""; 37 | }; 38 | 39 | bool Synthesize(const Image3b& src, Image3b& dst, const BdsimParams& params); 40 | 41 | } // namespace ugu 42 | 43 | #endif -------------------------------------------------------------------------------- /include/ugu/textrans/texture_transfer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/image.h" 9 | #include "ugu/image_proc.h" 10 | #include "ugu/mesh.h" 11 | 12 | namespace ugu { 13 | 14 | struct TexTransNoCorrespOutput { 15 | Image3f dst_tex; 16 | Image1b dst_mask; 17 | Image1i nn_fid_tex; 18 | Image3f nn_pos_tex; 19 | Image3f nn_bary_tex; 20 | Image3f srcpos_tex; 21 | }; 22 | 23 | bool TexTransNoCorresp(const Image3f& src_tex, 24 | const std::vector& src_uvs, 25 | const std::vector& src_uv_faces, 26 | const std::vector& src_verts, 27 | const std::vector& src_verts_faces, 28 | const std::vector& dst_uvs, 29 | const std::vector& dst_uv_faces, 30 | const std::vector& dst_verts, 31 | const std::vector& dst_vert_faces, 32 | int32_t dst_tex_h, int32_t dst_tex_w, 33 | TexTransNoCorrespOutput& output, 34 | int32_t interp = InterpolationFlags::INTER_LINEAR, 35 | int32_t nn_num = 10); 36 | 37 | bool TexTransNoCorresp(const Image3f& src_tex, const Mesh& src_mesh, 38 | const Mesh& dst_mesh, int32_t dst_tex_h, 39 | int32_t dst_tex_w, TexTransNoCorrespOutput& output, 40 | int32_t interp = InterpolationFlags::INTER_LINEAR, 41 | int32_t nn_num = 10); 42 | 43 | bool TexTransNoCorresp(const Image3f& src_tex, const Mesh& src_mesh, 44 | const Eigen::Affine3f& src_trans, const Mesh& dst_mesh, 45 | const Eigen::Affine3f& dst_trans, int32_t dst_tex_h, 46 | int32_t dst_tex_w, TexTransNoCorrespOutput& output, 47 | int32_t interp = InterpolationFlags::INTER_LINEAR, 48 | int32_t nn_num = 10); 49 | 50 | bool TexTransFromColoredPoints( 51 | const std::vector& src_verts, 52 | const std::vector& src_cols, 53 | const std::vector& dst_uvs, 54 | const std::vector& dst_uv_faces, 55 | const std::vector& dst_verts, 56 | const std::vector& dst_vert_faces, int32_t dst_tex_h, 57 | int32_t dst_tex_w, Image3f& dst_tex, Image1b& dst_mask, 58 | int32_t interp = InterpolationFlags::INTER_LINEAR, int32_t nn_num = 10); 59 | 60 | bool TexTransFromColoredPoints( 61 | const Mesh& src_mesh, const Mesh& dst_mesh, int32_t dst_tex_h, 62 | int32_t dst_tex_w, Image3f& dst_tex, Image1b& dst_mask, 63 | int32_t interp = InterpolationFlags::INTER_LINEAR, int32_t nn_num = 10); 64 | 65 | } // namespace ugu 66 | -------------------------------------------------------------------------------- /include/ugu/texturing/texture_mapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/texturing/visibility_tester.h" 9 | 10 | namespace ugu { 11 | 12 | enum TextureMappingType { kSimpleProjection = 0 }; 13 | 14 | enum TexturingOutputUvType { 15 | kGenerateSimpleTile = 0, 16 | kUseOriginalMeshUv = 1, 17 | kGenerateSimpleTriangles = 2, 18 | kGenerateSimpleCharts = 3, 19 | kConcatHorizontally = 4, 20 | kConcatVertically = 5, 21 | }; 22 | 23 | struct TextureMappingOption { 24 | ViewSelectionCriteria criteria = ViewSelectionCriteria::kMaxArea; 25 | TextureMappingType type = TextureMappingType::kSimpleProjection; 26 | TexturingOutputUvType uv_type = TexturingOutputUvType::kGenerateSimpleTile; 27 | std::string texture_base_name = "ugutex"; 28 | int tex_w = 1024; 29 | int tex_h = 1024; 30 | int padding_kernel = 3; 31 | }; 32 | 33 | bool TextureMapping(const std::vector>& keyframes, 34 | const VisibilityInfo& info, Mesh* mesh, 35 | const TextureMappingOption& option); 36 | 37 | } // namespace ugu 38 | -------------------------------------------------------------------------------- /include/ugu/texturing/vertex_colorizer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "visibility_tester.h" 9 | 10 | namespace ugu { 11 | 12 | class VertexColorizer { 13 | public: 14 | VertexColorizer(); 15 | ~VertexColorizer(); 16 | bool Colorize(const VisibilityInfo& info, Mesh* mesh, 17 | ViewSelectionCriteria criteria = 18 | ViewSelectionCriteria::kMinViewingAngle) const; 19 | }; 20 | 21 | } // namespace ugu 22 | -------------------------------------------------------------------------------- /include/ugu/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | #include //NOLINT 8 | #include 9 | #include 10 | 11 | namespace ugu { 12 | 13 | template 14 | class Timer { 15 | std::chrono::system_clock::time_point start_t_, end_t_; 16 | T elapsed_msec_{-1}; 17 | size_t history_num_{30}; 18 | std::vector history_; 19 | 20 | public: 21 | Timer() {} 22 | ~Timer() {} 23 | explicit Timer(size_t history_num) : history_num_(history_num) {} 24 | 25 | std::chrono::system_clock::time_point start_t() const { return start_t_; } 26 | std::chrono::system_clock::time_point end_t() const { return end_t_; } 27 | 28 | void Start() { start_t_ = std::chrono::system_clock::now(); } 29 | void End() { 30 | end_t_ = std::chrono::system_clock::now(); 31 | elapsed_msec_ = static_cast( 32 | std::chrono::duration_cast(end_t_ - start_t_) 33 | .count() * 34 | 0.001); 35 | 36 | history_.push_back(elapsed_msec_); 37 | if (history_num_ < history_.size()) { 38 | history_.erase(history_.begin()); 39 | } 40 | } 41 | T elapsed_msec() const { return elapsed_msec_; } 42 | T average_msec() const { 43 | if (history_.empty()) { 44 | return elapsed_msec_; 45 | } 46 | return static_cast( 47 | std::accumulate(history_.begin(), history_.end(), T(0)) / 48 | history_.size()); 49 | } 50 | }; 51 | 52 | } // namespace ugu 53 | -------------------------------------------------------------------------------- /include/ugu/util/camera_util.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2022, unclearness 4 | * All rights reserved. 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include "ugu/common.h" 13 | 14 | namespace ugu { 15 | void WriteTumFormat(const std::vector& poses, 16 | const std::string& path); 17 | bool LoadTumFormat(const std::string& path, 18 | std::vector* poses); 19 | bool LoadTumFormat(const std::string& path, 20 | std::vector>* poses); 21 | bool LoadTumFormatExtend( 22 | const std::string& path, 23 | std::vector>>* 24 | poses); 25 | 26 | void c2w(const Eigen::Vector3f& position, const Eigen::Vector3f& target, 27 | const Eigen::Vector3f& up, Eigen::Matrix3f* R, bool gl_coord = false); 28 | void c2w(const Eigen::Vector3d& position, const Eigen::Vector3d& target, 29 | const Eigen::Vector3d& up, Eigen::Matrix3d* R, bool gl_coord = false); 30 | 31 | void c2w(const Eigen::Vector3f& position, const Eigen::Vector3f& target, 32 | const Eigen::Vector3f& up, Eigen::Matrix4f* R, bool gl_coord = false); 33 | void c2w(const Eigen::Vector3d& position, const Eigen::Vector3d& target, 34 | const Eigen::Vector3d& up, Eigen::Matrix4d* R, bool gl_coord = false); 35 | 36 | Eigen::Affine3d ConvertCvAndGlWldToCam(const Eigen::Affine3d& w2c); 37 | Eigen::Affine3d ConvertCvAndGlCamToWld(const Eigen::Affine3d& c2w); 38 | Eigen::Affine3d ConvertCvAndGlCamToWldRotOnly(const Eigen::Affine3d& c2w); 39 | 40 | Eigen::Matrix4f GetProjectionMatrixOpenGl(float l, float r, float b, float t, 41 | float n, float f); 42 | Eigen::Matrix4f GetProjectionMatrixOpenGl(float fovY, float aspect, 43 | float z_near, float z_far); 44 | Eigen::Matrix4f GetProjectionMatrixOpenGlForPinhole(int width, int height, 45 | float fx, float fy, 46 | float cx, float cy, 47 | float z_near, float z_far); 48 | Eigen::Matrix4f GetProjectionMatrixOpenGlForOrtho(float xmin, float xmax, 49 | float ymin, float ymax, 50 | float zmin = -1.f, 51 | float zmax = 1.f); 52 | void DistortPixelOpencv(float* u, float* v, float fx, float fy, float cx, 53 | float cy, float k1, float k2, float p1, float p2, 54 | float k3 = 0.0f, float k4 = 0.0f, float k5 = 0.0f, 55 | float k6 = 0.0f); 56 | 57 | void UndistortPixelOpencv(float* u, float* v, float fx, float fy, float cx, 58 | float cy, float k1, float k2, float p1, float p2, 59 | float k3 = 0.0f, float k4 = 0.0f, float k5 = 0.0f, 60 | float k6 = 0.0f); 61 | 62 | void RescaleIntrinsicByCropping(int min_x, int min_y, float& cx, float& cy); 63 | 64 | } // namespace ugu -------------------------------------------------------------------------------- /include/ugu/util/io_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "ugu/image.h" 11 | #include "ugu/util/string_util.h" 12 | 13 | namespace ugu { 14 | 15 | void WriteFaceIdAsText(const Image1i& face_id, const std::string& path); 16 | 17 | inline bool LoadBinaryBase(const std::string& path, std::vector* data) { 18 | std::ifstream ifs(path, std::ios::binary); 19 | 20 | ifs.seekg(0, std::ios::end); 21 | long long int size = ifs.tellg(); 22 | ifs.seekg(0); 23 | 24 | data->resize(size); 25 | ifs.read(data->data(), size); 26 | 27 | return true; 28 | } 29 | 30 | inline bool LoadBinaryBase(const std::string& path, char* data) { 31 | std::ifstream ifs(path, std::ios::binary); 32 | 33 | ifs.seekg(0, std::ios::end); 34 | long long int size = ifs.tellg(); 35 | ifs.seekg(0); 36 | 37 | ifs.read(data, size); 38 | 39 | return true; 40 | } 41 | 42 | template 43 | bool LoadBinary(const std::string& path, std::vector* data) { 44 | std::vector internal_data; 45 | LoadBinaryBase(path, &internal_data); 46 | size_t elem_num = internal_data.size() / sizeof(T); 47 | data->resize(elem_num); 48 | 49 | std::memcpy(data->data(), internal_data.data(), internal_data.size()); 50 | 51 | return true; 52 | } 53 | 54 | std::string LoadTxt(const std::string& path); 55 | 56 | template 57 | std::vector LoadTxtAsVector(const std::string& path) { 58 | std::ifstream ifs(path); 59 | std::vector data; 60 | 61 | std::string line; 62 | while (std::getline(ifs, line)) { 63 | data.push_back(static_cast(std::atof(line.c_str()))); 64 | } 65 | return data; 66 | } 67 | 68 | template 69 | std::vector> LoadTxtAsVectorVector(const std::string& path, 70 | const char sep = ' ') { 71 | std::ifstream ifs(path); 72 | std::vector> data_list; 73 | 74 | std::string line; 75 | while (std::getline(ifs, line)) { 76 | std::vector splited = Split(line, sep); 77 | 78 | std::vector data; 79 | for (const auto& s : splited) { 80 | data.push_back(static_cast(std::atof(s.c_str()))); 81 | } 82 | 83 | data_list.push_back(data); 84 | } 85 | 86 | return data_list; 87 | } 88 | 89 | template 90 | std::vector LoadTxtAsEigenVec(const std::string& path, 91 | const char sep = ' ') { 92 | std::ifstream ifs(path); 93 | std::vector data; 94 | 95 | std::string line; 96 | while (std::getline(ifs, line)) { 97 | if (line.substr(0, 1) == "#") { 98 | continue; 99 | } 100 | 101 | std::vector splited = Split(line, sep); 102 | 103 | if (splited.size() != T::RowsAtCompileTime) { 104 | LOGW("load error\n"); 105 | continue; 106 | } 107 | 108 | std::vector v; 109 | for (const auto& s : splited) { 110 | v.push_back(std::atof(s.c_str())); 111 | } 112 | 113 | Eigen::VectorXd v2 = 114 | Eigen::Map(v.data(), v.size()); 115 | 116 | data.push_back(T(v2.cast())); 117 | } 118 | return data; 119 | } 120 | 121 | template 122 | bool WriteTxt(const std::string& path, const std::vector& data) { 123 | std::ofstream ofs(path); 124 | if (!ofs.is_open()) { 125 | return false; 126 | } 127 | 128 | for (const T& d : data) { 129 | ofs << d << std::endl; 130 | } 131 | 132 | return true; 133 | } 134 | 135 | inline bool WriteBinary(const std::string& path, void* data, size_t size) { 136 | std::ofstream ofs(path, std::ios::binary); 137 | ofs.write(reinterpret_cast(data), size); 138 | 139 | if (ofs.bad()) { 140 | return false; 141 | } 142 | return true; 143 | } 144 | 145 | inline bool WriteBinary(const std::string& path, ImageBase& image) { 146 | size_t size_in_bytes = image.total() * image.elemSize(); 147 | return WriteBinary(path, image.data, size_in_bytes); 148 | } 149 | 150 | inline bool LoadBinary(const std::string& path, ImageBase& image) { 151 | std::vector internal_data; 152 | LoadBinaryBase(path, &internal_data); 153 | 154 | size_t size_in_bytes = image.total() * image.elemSize(); 155 | 156 | if (size_in_bytes != internal_data.size()) { 157 | return false; 158 | } 159 | 160 | std::memcpy(image.data, internal_data.data(), size_in_bytes); 161 | 162 | return true; 163 | } 164 | 165 | } // namespace ugu 166 | -------------------------------------------------------------------------------- /include/ugu/util/path_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | namespace ugu { 12 | 13 | bool Exists(const std::string& path); 14 | 15 | bool DirExists(const std::string& path); 16 | 17 | bool FileExists(const std::string& path); 18 | 19 | bool EnsureDirExists(const std::string& path); 20 | 21 | bool MkDir(const std::string& path); 22 | 23 | bool RmDir(const std::string& path); 24 | 25 | bool RmFile(const std::string& path, bool check_exists = true); 26 | 27 | bool Rename(const std::string& from, const std::string& to); 28 | 29 | bool CpFile(const std::string& src, const std::string& dst); 30 | 31 | std::vector ListDir(const std::string& path); 32 | 33 | } // namespace ugu 34 | -------------------------------------------------------------------------------- /include/ugu/util/rgbd_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | #include "ugu/camera.h" 12 | #include "ugu/image.h" 13 | #include "ugu/mesh.h" 14 | 15 | namespace ugu { 16 | 17 | bool Depth2PointCloud(const Image1f& depth, const Camera& camera, 18 | Image3f* point_cloud, bool gl_coord = false); 19 | 20 | bool Depth2PointCloud(const Image1f& depth, const Camera& camera, 21 | Mesh* point_cloud, bool gl_coord = false); 22 | 23 | bool Depth2PointCloud(const Image1f& depth, const Image3b& color, 24 | const Camera& camera, Mesh* point_cloud, 25 | bool gl_coord = false); 26 | 27 | bool Depth2Mesh(const Image1f& depth, const Camera& camera, Mesh* mesh, 28 | float max_connect_z_diff, int x_step = 1, int y_step = 1, 29 | bool gl_coord = false, Image3f* point_cloud = nullptr, 30 | Image3f* normal = nullptr); 31 | 32 | bool Depth2Mesh(const Image1f& depth, const Image3b& color, 33 | const Camera& camera, Mesh* mesh, float max_connect_z_diff, 34 | int x_step = 1, int y_step = 1, bool gl_coord = false, 35 | const std::string& material_name = "Depth2Mesh_mat", 36 | bool with_vertex_color = false, Image3f* point_cloud = nullptr, 37 | Image3f* normal = nullptr); 38 | 39 | bool Depth2Mesh(const Image1f& depth, const Image3b& color, 40 | const Camera& depth_camera, const Camera& color_camera, 41 | const Eigen::Affine3f depth2color, Mesh* mesh, 42 | float max_connect_z_diff, int x_step = 1, int y_step = 1, 43 | bool gl_coord = false, 44 | const std::string& material_name = "Depth2Mesh_mat", 45 | bool with_vertex_color = false, Image3f* point_cloud = nullptr, 46 | Image3f* normal = nullptr); 47 | 48 | bool ComputeNormal(const Image1f& depth, const Camera& depth_camera, 49 | Image3f* normal, float max_connect_z_diff, int x_step = 1, 50 | int y_step = 1, bool gl_coord = false, bool to_world = true, 51 | Image3f* organized_pc = nullptr, 52 | Image1b* valid_mask = nullptr, uint32_t num_threads = 1); 53 | 54 | bool ComputeNormal(const Image3f& organized_pc, Image3f* normal, 55 | float max_connect_z_diff, int x_step = 1, int y_step = 1, 56 | Image1b* valid_mask = nullptr, uint32_t num_threads = 1); 57 | 58 | } // namespace ugu 59 | -------------------------------------------------------------------------------- /include/ugu/util/string_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace ugu { 14 | 15 | std::string ExtractFilename(const std::string& path, bool without_ext = false); 16 | std::string ExtractDir(const std::string& path); 17 | std::string ExtractExt(const std::string& path, bool no_dot = true); 18 | std::string ExtractPathWithoutExt(const std::string& fn); 19 | std::string ReplaceExtention(const std::string& path, const std::string& ext); 20 | 21 | std::vector Split(const std::string& input, char delimiter); 22 | 23 | template 24 | std::string zfill(const T& val, int num = 5) { 25 | std::ostringstream sout; 26 | sout << std::setfill('0') << std::setw(num) << val; 27 | return sout.str(); 28 | } 29 | 30 | // Optimized C++ 11.1.6 31 | std::streamoff stream_size(std::istream& f); 32 | bool stream_read_string(std::istream& f, std::string& result); 33 | 34 | } // namespace ugu 35 | -------------------------------------------------------------------------------- /include/ugu/util/thread_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | 12 | namespace ugu { 13 | 14 | // Used only if > 0 15 | inline uint32_t UGU_THREADS_NUM = 0; 16 | 17 | void parallel_for(int st, int ed, std::function func, 18 | int num_theads = -1, int inc = 1); 19 | void parallel_for(size_t st, size_t ed, std::function func, 20 | int num_theads = -1, size_t inc = 1); 21 | 22 | } // namespace ugu 23 | -------------------------------------------------------------------------------- /include/ugu/voxel/extract_voxel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "ugu/mesh.h" 9 | #include "ugu/voxel/voxel.h" 10 | 11 | namespace ugu { 12 | 13 | void ExtractVoxel(VoxelGrid* voxel_grid, Mesh* mesh, bool inside_empty); 14 | 15 | } // namespace ugu 16 | -------------------------------------------------------------------------------- /include/ugu/voxel/marching_cubes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | // original code is from 7 | // http://paulbourke.net/geometry/polygonise/ 8 | 9 | #pragma once 10 | 11 | #include "ugu/mesh.h" 12 | #include "ugu/voxel/voxel.h" 13 | 14 | namespace ugu { 15 | 16 | void MarchingCubes(const VoxelGrid& voxel_grid, Mesh* mesh, 17 | double iso_level = 0.0, bool with_color = false); 18 | 19 | } // namespace ugu 20 | -------------------------------------------------------------------------------- /python/test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import os 4 | this_abs_path = os.path.abspath(os.path.join(os.path.abspath(__file__), "..")) 5 | sys.path.insert(0, os.path.abspath(os.path.join(this_abs_path, "../lib/Release"))) 6 | import ugu_py 7 | import numpy as np 8 | import json 9 | import obj_io 10 | 11 | 12 | def umeyama(src, dst, estimate_scale): 13 | """Estimate N-D similarity transformation with or without scaling. 14 | 15 | Parameters 16 | ---------- 17 | src : (M, N) array_like 18 | Source coordinates. 19 | dst : (M, N) array_like 20 | Destination coordinates. 21 | estimate_scale : bool 22 | Whether to estimate scaling factor. 23 | 24 | Returns 25 | ------- 26 | T : (N + 1, N + 1) 27 | The homogeneous similarity transformation matrix. The matrix contains 28 | NaN values only if the problem is not well-conditioned. 29 | 30 | References 31 | ---------- 32 | .. [1] "Least-squares estimation of transformation parameters between two 33 | point patterns", Shinji Umeyama, PAMI 1991, :DOI:`10.1109/34.88573` 34 | 35 | """ 36 | src = np.asarray(src) 37 | dst = np.asarray(dst) 38 | 39 | num = src.shape[0] 40 | dim = src.shape[1] 41 | 42 | # Compute mean of src and dst. 43 | src_mean = src.mean(axis=0) 44 | dst_mean = dst.mean(axis=0) 45 | 46 | # Subtract mean from src and dst. 47 | src_demean = src - src_mean 48 | dst_demean = dst - dst_mean 49 | 50 | # Eq. (38). 51 | A = dst_demean.T @ src_demean / num 52 | 53 | # Eq. (39). 54 | d = np.ones((dim,), dtype=np.float64) 55 | if np.linalg.det(A) < 0: 56 | d[dim - 1] = -1 57 | 58 | T = np.eye(dim + 1, dtype=np.float64) 59 | 60 | U, S, V = np.linalg.svd(A) 61 | 62 | # Eq. (40) and (43). 63 | rank = np.linalg.matrix_rank(A) 64 | if rank == 0: 65 | return np.nan * T 66 | elif rank == dim - 1: 67 | if np.linalg.det(U) * np.linalg.det(V) > 0: 68 | T[:dim, :dim] = U @ V 69 | else: 70 | s = d[dim - 1] 71 | d[dim - 1] = -1 72 | T[:dim, :dim] = U @ np.diag(d) @ V 73 | d[dim - 1] = s 74 | else: 75 | T[:dim, :dim] = U @ np.diag(d) @ V 76 | 77 | if estimate_scale: 78 | # Eq. (41) and (42). 79 | scale = 1.0 / src_demean.var(axis=0).sum() * (S @ d) 80 | else: 81 | scale = 1.0 82 | 83 | T[:dim, dim] = dst_mean - scale * (T[:dim, :dim] @ src_mean.T) 84 | T[:dim, :dim] *= scale 85 | 86 | return T 87 | 88 | 89 | def load_lmk(path, verts, indices): 90 | src_fids = [] 91 | src_barys = [] 92 | with open(path) as fp: 93 | j = json.load(fp) 94 | for p in j: 95 | src_fids.append(int(p[0])) 96 | src_barys.append([float(p[1]), float(p[2])]) 97 | src_fids = np.array(src_fids, dtype=np.int32) 98 | src_barys = np.array(src_barys, dtype=np.float32) 99 | src_lmks = [] 100 | for fid, uv in zip(src_fids, src_barys): 101 | src_lmks.append(verts[indices[fid][0]] * uv[0] + verts[indices[fid][1]] * uv[1] + verts[indices[fid][2]] * (1.0 - uv[0] - uv[1])) 102 | src_lmks = np.array(src_lmks, dtype=np.float32) 103 | return src_fids, src_barys, src_lmks 104 | 105 | 106 | src = obj_io.loadObj("../data/face/ict-facekit_tri.obj") 107 | dst = obj_io.loadObj("../data/face/max-planck.obj") 108 | src_fids, src_barys, src_lmks = load_lmk(os.path.join(this_abs_path, "../data/face/ict-facekit_lmk.json"), src.verts, src.indices) 109 | dst_fids, dst_barys, dst_lmks = load_lmk(os.path.join(this_abs_path, "../data/face/max-planck_lmk.json"), dst.verts, dst.indices) 110 | 111 | T = umeyama(src_lmks, dst_lmks, True) 112 | R = T[:3, :3] 113 | t = T[:3, 3] 114 | 115 | src_verts = (R @ src.verts.T).T + t 116 | src.verts = src_verts 117 | obj_io.saveObj("umeyama.obj", src) 118 | 119 | lmk_w = np.ones(len(src_fids), dtype=np.float32) 120 | lmk_w[9] = 10.0 121 | 122 | src_ignore_face_ids = set() 123 | for k, v in src.mtl_per_faces.items(): 124 | if k != "M_Face" and k != "M_EarBack": 125 | for idx in v: 126 | src_ignore_face_ids.add(idx) 127 | 128 | src_ignore_face_ids = np.array(list(src_ignore_face_ids), dtype=np.int32) 129 | params = ugu_py.NonrigidIcpParams(True, False, False, 0.075, 0.05, 60.0, 45.0, 2.0, 0.1, 10.0, 20, 10) 130 | deformed_verts = ugu_py.NonrigidIcp(src_verts, src.indices, src_fids, src_barys, lmk_w, src_ignore_face_ids, dst.verts, dst.indices, dst_lmks, params) 131 | 132 | src.verts = deformed_verts 133 | obj_io.saveObj("deformed.obj", src) 134 | -------------------------------------------------------------------------------- /rebuild.bat: -------------------------------------------------------------------------------- 1 | cmake --build win_build -------------------------------------------------------------------------------- /reconfigure.bat: -------------------------------------------------------------------------------- 1 | rem rd /s /q win_build 2 | 3 | IF NOT EXIST win_build ( 4 | md win_build 5 | ) 6 | 7 | cd win_build 8 | 9 | IF EXIST CMakeCache.txt ( 10 | del CMakeCache.txt 11 | ) 12 | IF EXIST "C:\\Program Files\\Microsoft Visual Studio\\2022\\" ( 13 | cmake -G "Visual Studio 17 2022" .. 14 | ) ELSE IF EXIST "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\" ( 15 | cmake -G "Visual Studio 16 2019" .. 16 | ) ELSE IF EXIST "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\" ( 17 | cmake -G "Visual Studio 15 2017 Win64" .. 18 | ) 19 | 20 | cd .. 21 | 22 | pause 23 | -------------------------------------------------------------------------------- /script/glsl2header.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | root_dir = "../src/shader" 5 | glsl_dir = "../src/shader/glsl" 6 | 7 | shader_types = ["vert", "frag", "geom"] 8 | 9 | cpp_header = """/* 10 | * Automatically generated by script/glsl2header.py 11 | */ 12 | /* 13 | * Copyright (C) 2023, unclearness 14 | * All rights reserved. 15 | */ 16 | 17 | 18 | 19 | #pragma once 20 | 21 | #include 22 | 23 | namespace ugu { 24 | """ 25 | 26 | cpp_footer = "}\n" 27 | 28 | for shader_type in shader_types: 29 | shader_header = cpp_header 30 | shader_dir = os.path.join(glsl_dir, shader_type) 31 | for shader_name in os.listdir(shader_dir): 32 | if not shader_name.endswith(shader_type): 33 | continue 34 | shader_path = os.path.join(shader_dir, shader_name) 35 | with open(shader_path, 'r') as fp: 36 | shader_body = ['R"('] 37 | for line in fp: 38 | line = line.rstrip() 39 | shader_body.append(line) 40 | shader_body = "\n".join(shader_body) 41 | shader_cpp_var_name = shader_type + "_" + \ 42 | shader_name.split('.')[0] + "_code" 43 | shader_header += '\n' 44 | shader_header += f"static inline std::string {shader_cpp_var_name} = \n" 45 | shader_header += shader_body + ')";' 46 | shader_header += "\n" 47 | shader_header += cpp_footer 48 | cpp_header_path = os.path.join(root_dir, shader_type + ".h") 49 | with open(cpp_header_path, 'w') as fp: 50 | fp.write(shader_header) 51 | subprocess.run(["clang-format", cpp_header_path, "-i"]) 52 | -------------------------------------------------------------------------------- /src/camera.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/camera.h" 7 | 8 | namespace ugu {} // namespace ugu 9 | -------------------------------------------------------------------------------- /src/common.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/common.h" 7 | 8 | namespace { 9 | 10 | // borrow from glm 11 | // radians 12 | template 13 | genType radiansImpl(const genType& degrees) { 14 | // "'radians' only accept floating-point input" 15 | static_assert(std::numeric_limits::is_iec559); 16 | 17 | return degrees * static_cast(0.01745329251994329576923690768489); 18 | } 19 | 20 | // degrees 21 | template 22 | genType degreesImpl(const genType& radians) { 23 | // "'degrees' only accept floating-point input" 24 | static_assert(std::numeric_limits::is_iec559); 25 | 26 | return radians * static_cast(57.295779513082320876798154814105); 27 | } 28 | 29 | } // namespace 30 | 31 | namespace ugu { 32 | 33 | float radians(const float& degrees) { return radiansImpl(degrees); } 34 | double radians(const double& degrees) { return radiansImpl(degrees); } 35 | 36 | float degrees(const float& radians) { return degreesImpl(radians); } 37 | double degrees(const double& radians) { return degreesImpl(radians); } 38 | 39 | float Fov2FocalPix(float fov, float pix, bool is_deg) { 40 | if (is_deg) { 41 | fov = radians(fov); 42 | } 43 | return pix * 0.5f / static_cast(std::tan(fov * 0.5)); 44 | } 45 | 46 | float FocalPix2Fov(float f, float pix, bool to_deg) { 47 | float fov = 2.f * std::atan(pix * 0.5f / f); 48 | if (to_deg) { 49 | fov = degrees(fov); 50 | } 51 | return fov; 52 | } 53 | 54 | } // namespace ugu 55 | -------------------------------------------------------------------------------- /src/cuda/image.cu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/src/cuda/image.cu -------------------------------------------------------------------------------- /src/cuda/image.cuh: -------------------------------------------------------------------------------- 1 | 2 | namespace ugu { 3 | 4 | void BoxFilterCuda3b(int width, int height, void* data, int k); 5 | 6 | void ComputeNormalsCudaImpl(int width, int height, float* h_depths, 7 | int num_images, const float* h_fx, 8 | const float* h_fy, const float* h_cx, 9 | const float* h_cy, float* h_normals, 10 | float max_connect_z_diff, int step, bool gl_coord); 11 | 12 | } // namespace ugu -------------------------------------------------------------------------------- /src/cuda/knn.cuh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Eigen/Core" 6 | 7 | namespace ugu { 8 | 9 | void SearchKnnCuda(const float* d_data, const uint32_t* d_voxel_start_indices, 10 | const uint32_t* d_voxel_point_indices, uint32_t grid_size_x, 11 | uint32_t grid_size_y, uint32_t grid_size_z, float voxel_len, 12 | Eigen::Vector3f min_bound, float* d_queries, 13 | uint32_t num_queries, uint32_t k, uint32_t* d_knn_indices, 14 | float* d_knn_dists); 15 | } 16 | // namespace ugu -------------------------------------------------------------------------------- /src/cuda/voxel.cc: -------------------------------------------------------------------------------- 1 | #include "ugu/cuda/voxel.h" 2 | 3 | #ifdef UGU_USE_CUDA 4 | #include 5 | 6 | #include "./helper_cuda.h" 7 | #include "./voxel.cuh" 8 | 9 | #endif 10 | 11 | namespace ugu { 12 | 13 | #ifdef UGU_USE_CUDA 14 | 15 | #else 16 | VoxelGridCuda::VoxelGridCuda(int hash_table_size, int voxel_block_count, 17 | float mu, float voxel_size) {} 18 | 19 | VoxelGridCuda::~VoxelGridCuda() {} 20 | 21 | void VoxelGridCuda::Init(int hash_table_size, int voxel_block_count, float mu, 22 | float voxel_size) {} 23 | 24 | #endif 25 | 26 | } // namespace ugu 27 | -------------------------------------------------------------------------------- /src/cuda/voxel.cuh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace ugu { 5 | 6 | 7 | } 8 | // namespace ugu -------------------------------------------------------------------------------- /src/curvature/curvature.cc: -------------------------------------------------------------------------------- 1 | #include "ugu/curvature/curvature.h" 2 | 3 | #include 4 | 5 | #include "ugu/face_adjacency.h" 6 | #include "ugu/util/raster_util.h" 7 | 8 | namespace { 9 | 10 | template 11 | bool CurvatureGaussianImpl(const std::vector& vertices, 12 | const std::vector& faces, 13 | std::vector& curvature, 14 | std::vector& internal_angles) { 15 | internal_angles.resize(faces.size()); 16 | curvature.resize(vertices.size(), static_cast(2 * ugu::pi)); 17 | 18 | typedef typename DerivedV::Scalar Scalar; 19 | 20 | auto corner = [](const DerivedV& x, const DerivedV& y, const DerivedV& z) { 21 | auto v1 = x - y; 22 | auto v2 = z - y; 23 | return Scalar(2) * std::atan((v1 / v1.norm() - v2 / v2.norm()).norm() / 24 | (v1 / v1.norm() + v2 / v2.norm()).norm()); 25 | }; 26 | 27 | for (size_t i = 0; i < faces.size(); ++i) { 28 | internal_angles[i][0] = corner(vertices[faces[i][2]], vertices[faces[i][0]], 29 | vertices[faces[i][1]]); 30 | internal_angles[i][1] = corner(vertices[faces[i][0]], vertices[faces[i][1]], 31 | vertices[faces[i][2]]); 32 | internal_angles[i][2] = corner(vertices[faces[i][1]], vertices[faces[i][2]], 33 | vertices[faces[i][0]]); 34 | curvature[faces[i][0]] -= internal_angles[i][0]; 35 | curvature[faces[i][1]] -= internal_angles[i][1]; 36 | curvature[faces[i][2]] -= internal_angles[i][2]; 37 | } 38 | 39 | return true; 40 | }; 41 | 42 | } // namespace 43 | 44 | namespace ugu { 45 | 46 | bool CurvatureGaussian(const std::vector& vertices, 47 | const std::vector& faces, 48 | std::vector& curvature, 49 | std::vector& internal_angles) { 50 | return CurvatureGaussianImpl(vertices, faces, curvature, internal_angles); 51 | } 52 | 53 | std::vector BarycentricCellArea( 54 | const std::vector& vertices, 55 | const std::vector& faces) { 56 | // Adjacency vertex_adjacency = GenerateVertexAdjacency( 57 | // faces, static_cast(vertices.size())); 58 | 59 | auto v2f = GenerateVertex2FaceMap(faces, vertices.size()); 60 | 61 | std::vector area(vertices.size(), 0.f); 62 | 63 | for (size_t v_idx = 0; v_idx < vertices.size(); v_idx++) { 64 | const auto& f_idxs = v2f.at(static_cast(v_idx)); 65 | 66 | for (const auto& f_idx : f_idxs) { 67 | const auto& face = faces[f_idx]; 68 | area[v_idx] += 69 | TriArea(vertices[face[0]], vertices[face[1]], vertices[face[2]]); 70 | } 71 | area[v_idx] /= 3.f; 72 | } 73 | 74 | return area; 75 | } 76 | 77 | } // namespace ugu -------------------------------------------------------------------------------- /src/external/fast_quadric_mesh_simplification.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, unclearness 3 | * All rights reserved. 4 | * 5 | */ 6 | 7 | #include "ugu/external/external.h" 8 | 9 | #ifdef UGU_USE_FAST_QUADRIC_MESH_SIMPLIFICATION 10 | 11 | #ifdef _WIN32 12 | #pragma warning(push, 0) 13 | #endif 14 | 15 | #include "Simplify.h" 16 | 17 | #ifdef _WIN32 18 | #pragma warning(pop) 19 | #endif 20 | 21 | #endif 22 | 23 | namespace ugu { 24 | 25 | bool FastQuadricMeshSimplification(const Mesh& src, int target_face_num, 26 | Mesh* decimated) { 27 | #ifdef UGU_USE_FAST_QUADRIC_MESH_SIMPLIFICATION 28 | if (target_face_num > src.vertex_indices().size()) { 29 | return false; 30 | } 31 | 32 | // convert vertices and faces 33 | Simplify::vertices.clear(); 34 | Simplify::triangles.clear(); 35 | Simplify::refs.clear(); 36 | Simplify::materials.clear(); 37 | 38 | Simplify::vertices.resize(src.vertices().size()); 39 | for (int i = 0; i < static_cast(src.vertices().size()); i++) { 40 | Simplify::Vertex& v = Simplify::vertices[i]; 41 | v.p.x = src.vertices()[i].x(); 42 | v.p.y = src.vertices()[i].y(); 43 | v.p.z = src.vertices()[i].z(); 44 | } 45 | 46 | Simplify::triangles.resize(src.vertex_indices().size()); 47 | for (int i = 0; i < static_cast(src.vertex_indices().size()); i++) { 48 | Simplify::Triangle& t = Simplify::triangles[i]; 49 | for (int j = 0; j < 3; j++) { 50 | t.v[j] = src.vertex_indices()[i][j]; 51 | } 52 | } 53 | 54 | std::array agressiveness_list = { 55 | {1.0, 1.5, 2.0, 2.5, 3.0, 5.0, 7.0, 100.0}}; 56 | 57 | bool ret = true; 58 | const int max_iter = static_cast(agressiveness_list.size()); 59 | 60 | for (int i = 0; i < max_iter; i++) { 61 | double agressiveness = agressiveness_list[i]; 62 | Simplify::simplify_mesh(target_face_num, agressiveness, false); 63 | ugu::LOGI( 64 | "FastQuadricMeshSimplification: iter %d, agressiveness %f, current " 65 | "%d\n", 66 | i, agressiveness, Simplify::triangles.size()); 67 | if (Simplify::triangles.size() <= target_face_num) { 68 | break; 69 | } 70 | } 71 | 72 | if (Simplify::triangles.size() > target_face_num) { 73 | ret = false; 74 | ugu::LOGE("FastQuadricMeshSimplification failed: target %d, result: %d\n", 75 | target_face_num, Simplify::triangles.size()); 76 | } else { 77 | ugu::LOGI( 78 | "FastQuadricMeshSimplification succeeded: target %d, result: %d\n", 79 | target_face_num, Simplify::triangles.size()); 80 | } 81 | 82 | // convert back vertices and faces 83 | decimated->Clear(); 84 | 85 | std::vector vertices(Simplify::vertices.size()); 86 | for (int i = 0; i < static_cast(vertices.size()); i++) { 87 | Simplify::Vertex& v = Simplify::vertices[i]; 88 | vertices[i].x() = static_cast(v.p.x); 89 | vertices[i].y() = static_cast(v.p.y); 90 | vertices[i].z() = static_cast(v.p.z); 91 | } 92 | 93 | std::vector vertex_indices(Simplify::triangles.size()); 94 | for (int i = 0; i < static_cast(vertex_indices.size()); i++) { 95 | Simplify::Triangle& t = Simplify::triangles[i]; 96 | for (int j = 0; j < 3; j++) { 97 | vertex_indices[i][j] = t.v[j]; 98 | } 99 | } 100 | 101 | // TODO: multiple uv for a single vertex (obj format) 102 | decimated->set_materials(src.materials()); 103 | std::vector material_ids(vertex_indices.size(), 0); 104 | decimated->set_material_ids(material_ids); 105 | 106 | decimated->set_vertices(vertices); 107 | decimated->set_vertex_indices(vertex_indices); 108 | 109 | decimated->RemoveUnreferencedVertices(); 110 | decimated->CalcNormal(); 111 | 112 | return ret; 113 | #else 114 | (void)src; 115 | (void)target_face_num; 116 | (void)decimated; 117 | ugu::LOGE("Not available in current configuration\n"); 118 | return false; 119 | #endif 120 | } 121 | 122 | } // namespace ugu 123 | -------------------------------------------------------------------------------- /src/image.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/image.h" 7 | 8 | namespace ugu { 9 | #ifdef UGU_USE_OPENCV 10 | #else 11 | int GetBitsFromCvType(int cv_type) { 12 | int cv_depth = CV_MAT_DEPTH(cv_type); 13 | 14 | if (cv_depth < 0) { 15 | throw std::runtime_error(""); 16 | } 17 | 18 | if (cv_depth <= CV_8S) { 19 | return 8; 20 | } else if (cv_depth <= CV_16S) { 21 | return 16; 22 | } else if (cv_depth <= CV_32S) { 23 | return 32; 24 | } else if (cv_depth <= CV_32F) { 25 | return 32; 26 | } else if (cv_depth <= CV_64F) { 27 | return 64; 28 | } else if (cv_depth <= CV_16F) { 29 | return 16; 30 | } 31 | 32 | throw std::runtime_error(""); 33 | } 34 | 35 | const std::type_info& GetTypeidFromCvType(int cv_type) { 36 | int cv_depth = CV_MAT_DEPTH(cv_type); 37 | 38 | if (cv_depth < CV_8S) { 39 | return typeid(uint8_t); 40 | } else if (cv_depth < CV_16U) { 41 | return typeid(int8_t); 42 | } else if (cv_depth < CV_16S) { 43 | return typeid(uint16_t); 44 | } else if (cv_depth < CV_32S) { 45 | return typeid(int16_t); 46 | } else if (cv_depth < CV_32F) { 47 | return typeid(int32_t); 48 | } else if (cv_depth < CV_64F) { 49 | return typeid(float); 50 | } else if (cv_depth < CV_16F) { 51 | return typeid(double); 52 | } 53 | 54 | throw std::runtime_error(""); 55 | } 56 | 57 | size_t SizeInBytes(const ImageBase& mat) { 58 | // https://stackoverflow.com/questions/26441072/finding-the-size-in-bytes-of-cvmat 59 | return size_t(mat.step[0] * mat.rows); 60 | } 61 | 62 | InputOutputArray noArray() { 63 | static _InputOutputArray no_array; 64 | return no_array; 65 | } 66 | 67 | int MakeCvType(const std::type_info* info, int ch) { 68 | int code = -1; 69 | 70 | if (info == &typeid(uint8_t)) { 71 | code = CV_MAKETYPE(CV_8U, ch); 72 | } else if (info == &typeid(int8_t)) { 73 | code = CV_MAKETYPE(CV_8S, ch); 74 | } else if (info == &typeid(uint16_t)) { 75 | code = CV_MAKETYPE(CV_16U, ch); 76 | } else if (info == &typeid(int16_t)) { 77 | code = CV_MAKETYPE(CV_16S, ch); 78 | } else if (info == &typeid(int32_t)) { 79 | code = CV_MAKETYPE(CV_32S, ch); 80 | } else if (info == &typeid(float)) { 81 | code = CV_MAKETYPE(CV_32F, ch); 82 | } else if (info == &typeid(double)) { 83 | code = CV_MAKETYPE(CV_64F, ch); 84 | } else { 85 | throw std::runtime_error("type error"); 86 | } 87 | 88 | return code; 89 | } 90 | #endif 91 | 92 | } // namespace ugu 93 | -------------------------------------------------------------------------------- /src/image_proc.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/src/image_proc.cc -------------------------------------------------------------------------------- /src/log.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/log.h" 7 | 8 | #include 9 | #include 10 | 11 | // multi line macro with do {...} while (0) guard 12 | #define PRINT_MACRO \ 13 | do { \ 14 | va_list va; \ 15 | va_start(va, format); \ 16 | vprintf(format, va); \ 17 | va_end(va); \ 18 | } while (0) 19 | 20 | namespace { 21 | ugu::LogLevel g_log_level_ = ugu::LogLevel::kVerbose; 22 | } 23 | 24 | namespace ugu { 25 | 26 | void set_log_level(LogLevel level) { g_log_level_ = level; } 27 | 28 | LogLevel get_log_level() { return g_log_level_; } 29 | 30 | #ifndef LOGD 31 | void LOGD(const char *format, ...) { 32 | if (LogLevel::kDebug >= g_log_level_) { 33 | PRINT_MACRO; 34 | } 35 | } 36 | #endif 37 | 38 | #ifndef LOGI 39 | void LOGI(const char *format, ...) { 40 | if (LogLevel::kInfo >= g_log_level_) { 41 | PRINT_MACRO; 42 | } 43 | } 44 | #endif 45 | 46 | #ifndef LOGW 47 | void LOGW(const char *format, ...) { 48 | if (LogLevel::kWarning >= g_log_level_) { 49 | PRINT_MACRO; 50 | } 51 | } 52 | #endif 53 | 54 | #ifndef LOGE 55 | void LOGE(const char *format, ...) { 56 | if (LogLevel::kError >= g_log_level_) { 57 | PRINT_MACRO; 58 | } 59 | } 60 | #endif 61 | 62 | } // namespace ugu 63 | -------------------------------------------------------------------------------- /src/registration/registration.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/registration/registration.h" 7 | -------------------------------------------------------------------------------- /src/registration/rigid.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/src/registration/rigid.cc -------------------------------------------------------------------------------- /src/renderer/cpu/util_private.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/renderer/cpu/util_private.h" 7 | 8 | #include 9 | 10 | namespace ugu { 11 | 12 | bool ValidateAndInitBeforeRender(bool mesh_initialized, 13 | std::shared_ptr camera, 14 | std::shared_ptr mesh, 15 | const RendererCpuOption& option, 16 | Image3b* color, Image1f* depth, 17 | Image3f* normal, Image1b* mask, 18 | Image1i* face_id) { 19 | if (camera == nullptr) { 20 | LOGE("camera has not been set\n"); 21 | return false; 22 | } 23 | if (!mesh_initialized) { 24 | LOGE("mesh has not been initialized\n"); 25 | return false; 26 | } 27 | if (option.backface_culling && mesh->face_normals().empty()) { 28 | LOGE("specified back-face culling but face normal is empty.\n"); 29 | return false; 30 | } 31 | if (option.diffuse_color == DiffuseColor::kTexture && 32 | mesh->materials().empty()) { 33 | LOGE("specified texture as diffuse color but texture is empty.\n"); 34 | return false; 35 | } 36 | if (option.diffuse_color == DiffuseColor::kTexture) { 37 | for (int i = 0; i < static_cast(mesh->materials().size()); i++) { 38 | if (mesh->materials()[i].diffuse_tex.empty()) { 39 | LOGE("specified texture as diffuse color but %d th texture is empty.\n", 40 | i); 41 | return false; 42 | } 43 | } 44 | } 45 | if (option.diffuse_color == DiffuseColor::kVertex && 46 | mesh->vertex_colors().empty()) { 47 | LOGE( 48 | "specified vertex color as diffuse color but vertex color is empty.\n"); 49 | return false; 50 | } 51 | if (option.shading_normal == ShadingNormal::kFace && 52 | mesh->face_normals().empty()) { 53 | LOGE("specified face normal as shading normal but face normal is empty.\n"); 54 | return false; 55 | } 56 | if (option.shading_normal == ShadingNormal::kVertex && 57 | mesh->normals().empty()) { 58 | LOGE( 59 | "specified vertex normal as shading normal but vertex normal is " 60 | "empty.\n"); 61 | return false; 62 | } 63 | if (color == nullptr && depth == nullptr && normal == nullptr && 64 | mask == nullptr && face_id == nullptr) { 65 | LOGE("all arguments are nullptr. nothing to do\n"); 66 | return false; 67 | } 68 | 69 | int width = camera->width(); 70 | int height = camera->height(); 71 | 72 | if (color != nullptr) { 73 | Init(color, width, height, static_cast(0)); 74 | } 75 | if (depth != nullptr) { 76 | Init(depth, width, height, 0.0f); 77 | } 78 | if (normal != nullptr) { 79 | Init(normal, width, height, 0.0f); 80 | } 81 | if (mask != nullptr) { 82 | Init(mask, width, height, static_cast(0)); 83 | } 84 | if (face_id != nullptr) { 85 | // initialize with -1 (no hit) 86 | Init(face_id, width, height, -1); 87 | } 88 | 89 | return true; 90 | } 91 | 92 | } // namespace ugu 93 | -------------------------------------------------------------------------------- /src/renderer/gl/font/Open_Sans/README.txt: -------------------------------------------------------------------------------- 1 | Open Sans Variable Font 2 | ======================= 3 | 4 | This download contains Open Sans as both variable fonts and static fonts. 5 | 6 | Open Sans is a variable font with these axes: 7 | wdth 8 | wght 9 | 10 | This means all the styles are contained in these files: 11 | OpenSans-VariableFont_wdth,wght.ttf 12 | OpenSans-Italic-VariableFont_wdth,wght.ttf 13 | 14 | If your app fully supports variable fonts, you can now pick intermediate styles 15 | that aren’t available as static fonts. Not all apps support variable fonts, and 16 | in those cases you can use the static font files for Open Sans: 17 | static/OpenSans_Condensed/OpenSans_Condensed-Light.ttf 18 | static/OpenSans_Condensed/OpenSans_Condensed-Regular.ttf 19 | static/OpenSans_Condensed/OpenSans_Condensed-Medium.ttf 20 | static/OpenSans_Condensed/OpenSans_Condensed-SemiBold.ttf 21 | static/OpenSans_Condensed/OpenSans_Condensed-Bold.ttf 22 | static/OpenSans_Condensed/OpenSans_Condensed-ExtraBold.ttf 23 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Light.ttf 24 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Regular.ttf 25 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Medium.ttf 26 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-SemiBold.ttf 27 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Bold.ttf 28 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-ExtraBold.ttf 29 | static/OpenSans/OpenSans-Light.ttf 30 | static/OpenSans/OpenSans-Regular.ttf 31 | static/OpenSans/OpenSans-Medium.ttf 32 | static/OpenSans/OpenSans-SemiBold.ttf 33 | static/OpenSans/OpenSans-Bold.ttf 34 | static/OpenSans/OpenSans-ExtraBold.ttf 35 | static/OpenSans_Condensed/OpenSans_Condensed-LightItalic.ttf 36 | static/OpenSans_Condensed/OpenSans_Condensed-Italic.ttf 37 | static/OpenSans_Condensed/OpenSans_Condensed-MediumItalic.ttf 38 | static/OpenSans_Condensed/OpenSans_Condensed-SemiBoldItalic.ttf 39 | static/OpenSans_Condensed/OpenSans_Condensed-BoldItalic.ttf 40 | static/OpenSans_Condensed/OpenSans_Condensed-ExtraBoldItalic.ttf 41 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-LightItalic.ttf 42 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Italic.ttf 43 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-MediumItalic.ttf 44 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-SemiBoldItalic.ttf 45 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-BoldItalic.ttf 46 | static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-ExtraBoldItalic.ttf 47 | static/OpenSans/OpenSans-LightItalic.ttf 48 | static/OpenSans/OpenSans-Italic.ttf 49 | static/OpenSans/OpenSans-MediumItalic.ttf 50 | static/OpenSans/OpenSans-SemiBoldItalic.ttf 51 | static/OpenSans/OpenSans-BoldItalic.ttf 52 | static/OpenSans/OpenSans-ExtraBoldItalic.ttf 53 | 54 | Get started 55 | ----------- 56 | 57 | 1. Install the font files you want to use 58 | 59 | 2. Use your app's font picker to view the font family and all the 60 | available styles 61 | 62 | Learn more about variable fonts 63 | ------------------------------- 64 | 65 | https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts 66 | https://variablefonts.typenetwork.com 67 | https://medium.com/variable-fonts 68 | 69 | In desktop apps 70 | 71 | https://theblog.adobe.com/can-variable-fonts-illustrator-cc 72 | https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts 73 | 74 | Online 75 | 76 | https://developers.google.com/fonts/docs/getting_started 77 | https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide 78 | https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts 79 | 80 | Installing fonts 81 | 82 | MacOS: https://support.apple.com/en-us/HT201749 83 | Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux 84 | Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows 85 | 86 | Android Apps 87 | 88 | https://developers.google.com/fonts/docs/android 89 | https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts 90 | 91 | License 92 | ------- 93 | Please read the full license text (OFL.txt) to understand the permissions, 94 | restrictions and requirements for usage, redistribution, and modification. 95 | 96 | You can use them in your products & projects – print or digital, 97 | commercial or otherwise. 98 | 99 | This isn't legal advice, please consider consulting a lawyer and see the full 100 | license for all details. 101 | -------------------------------------------------------------------------------- /src/renderer/gl/font/Open_Sans/static/OpenSans/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/src/renderer/gl/font/Open_Sans/static/OpenSans/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /src/shader/geom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Automatically generated by script/glsl2header.py 3 | */ 4 | /* 5 | * Copyright (C) 2023, unclearness 6 | * All rights reserved. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | namespace ugu { 14 | 15 | static inline std::string geom_dummy_code = 16 | R"( 17 | #version 330 18 | layout(triangles) in; 19 | layout(triangle_strip, max_vertices = 3) out; 20 | 21 | uniform vec2 WIN_SCALE; 22 | uniform float FLAT_NORMAL; 23 | 24 | in vec3 vFragPos[]; 25 | in vec3 vViewPos[]; 26 | in vec2 vTexCoords[]; 27 | in vec3 vNormal[]; 28 | in vec3 vWldNormal[]; 29 | in vec3 vVertexColor[]; 30 | in vec3 vVertexId[]; 31 | 32 | out vec3 fragPos; 33 | out vec3 viewPos; 34 | out vec2 texCoords; 35 | out vec3 normal; 36 | out vec3 wldNormal; 37 | out vec3 vertexColor; 38 | out vec3 vertexId; 39 | out vec2 bary; 40 | out vec3 dist; 41 | 42 | void main() { 43 | vec3[3] dists = 44 | vec3[](vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 0.0)); 45 | 46 | vec4 p0_3d = gl_in[0].gl_Position; 47 | vec4 p1_3d = gl_in[1].gl_Position; 48 | vec4 p2_3d = gl_in[2].gl_Position; 49 | 50 | vec2 p0 = p0_3d.xy / p0_3d.w; 51 | vec2 p1 = p1_3d.xy / p1_3d.w; 52 | vec2 p2 = p2_3d.xy / p2_3d.w; 53 | 54 | vec2 v10 = WIN_SCALE * (p1 - p0); 55 | vec2 v20 = WIN_SCALE * (p2 - p0); 56 | float area0 = abs(v10.x * v20.y - v10.y * v20.x); 57 | float h0 = area0 / length(v10 - v20); 58 | dists[0] = vec3(h0, 0.0, 0.0); 59 | 60 | vec2 v01 = WIN_SCALE * (p0 - p1); 61 | vec2 v21 = WIN_SCALE * (p2 - p1); 62 | float area1 = abs(v01.x * v21.y - v01.y * v21.x); 63 | float h1 = area1 / length(v01 - v21); 64 | dists[1] = vec3(0.0, h1, 0.0); 65 | 66 | vec2 v02 = WIN_SCALE * (p0 - p2); 67 | vec2 v12 = WIN_SCALE * (p1 - p2); 68 | float area2 = abs(v02.x * v12.y - v02.y * v12.x); 69 | float h2 = area2 / length(v02 - v12); 70 | dists[2] = vec3(0.0, 0.0, h2); 71 | 72 | vec3 flat_normal = normalize(cross(normalize(vFragPos[1] - vFragPos[0]), 73 | normalize(vFragPos[2] - vFragPos[0]))); 74 | 75 | for (int i = 0; i < gl_in.length(); ++i) { 76 | gl_Position = gl_in[i].gl_Position; 77 | gl_PrimitiveID = gl_PrimitiveIDIn; 78 | // fid = gl_PrimitiveIDIn; 79 | fragPos = vFragPos[i]; 80 | viewPos = vViewPos[i]; 81 | texCoords = vTexCoords[i]; 82 | normal = vNormal[i]; 83 | wldNormal = mix(vWldNormal[i], flat_normal, FLAT_NORMAL); 84 | vertexColor = vVertexColor[i]; 85 | vertexId = vVertexId[i]; 86 | if (i == 0) { 87 | bary = vec2(0.0, 0.0); 88 | } else if (i == 1) { 89 | bary = vec2(1.0, 0.0); 90 | } else { 91 | bary = vec2(0.0, 1.0); 92 | } 93 | dist = dists[i]; 94 | EmitVertex(); 95 | } 96 | EndPrimitive(); 97 | })"; 98 | } 99 | -------------------------------------------------------------------------------- /src/shader/glsl/frag/deferred.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | out vec4 FragColor; 3 | 4 | in vec2 TexCoords; 5 | 6 | uniform sampler2D gPosition; 7 | uniform sampler2D gNormal; 8 | uniform sampler2D gAlbedoSpec; 9 | uniform sampler2D gId; 10 | uniform sampler2D gFace; 11 | 12 | uniform bool showWire; 13 | uniform vec3 wireCol; 14 | uniform float nearZ; 15 | uniform float farZ; 16 | uniform vec3 bkgCol; 17 | 18 | const int N_GEOMS = 4; 19 | const int N_POSITIONS = 128; 20 | // uniform vec3 selectedPositions[N_POSITIONS]; 21 | uniform vec3 selectedPositions[N_POSITIONS * N_GEOMS]; 22 | uniform float selectedPosDepthTh; 23 | uniform vec2 viewportOffset; 24 | uniform vec3 selectedPosColors[N_GEOMS]; 25 | 26 | struct Light { 27 | vec3 Position; 28 | vec3 Color; 29 | 30 | float Linear; 31 | float Quadratic; 32 | }; 33 | const int NR_LIGHTS = 32; 34 | uniform Light lights[NR_LIGHTS]; 35 | uniform vec3 viewPos; 36 | 37 | void main() { 38 | // retrieve data from gbuffer 39 | vec3 FragPos = texture(gPosition, TexCoords).rgb; 40 | vec3 Normal = texture(gNormal, TexCoords).rgb; 41 | vec3 Diffuse = texture(gAlbedoSpec, TexCoords).rgb; 42 | float Specular = texture(gAlbedoSpec, TexCoords).a; 43 | vec4 Face = texture(gFace, TexCoords); 44 | vec4 Id = texture(gId, TexCoords); 45 | 46 | // then calculate lighting as usual 47 | vec3 lighting = Diffuse * 0.1; // hard-coded ambient component 48 | vec3 viewDir = normalize(viewPos - FragPos); 49 | for (int i = 0; i < NR_LIGHTS; ++i) { 50 | // diffuse 51 | vec3 lightDir = normalize(lights[i].Position - FragPos); 52 | vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * lights[i].Color; 53 | // specular 54 | vec3 halfwayDir = normalize(lightDir + viewDir); 55 | float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0); 56 | vec3 specular = lights[i].Color * spec * Specular; 57 | // attenuation 58 | float distance = length(lights[i].Position - FragPos); 59 | float attenuation = 1.0 / (1.0 + lights[i].Linear * distance + 60 | lights[i].Quadratic * distance * distance); 61 | diffuse *= attenuation; 62 | specular *= attenuation; 63 | lighting += diffuse + specular; 64 | } 65 | // FragColor = vec4((Id.y * 3) * 0.2, 0.5, 0.6, 1.0); 66 | vec4 wireCol4 = vec4(wireCol, 1.0); 67 | float wire = mix(0.0, Specular, showWire); 68 | float depth = Id.z; 69 | // FragColor = vec4(Specular, Specular, Specular, 1.0); 70 | 71 | vec3 surface_col = vec3(1.0, 1.0, 1.0); 72 | float min_offset = 0.1; 73 | float positive_ratio = 0.7; 74 | float ratio = min_offset + positive_ratio; 75 | float scale = dot(viewDir, Normal); 76 | if (scale > 0.0) { 77 | scale = scale * positive_ratio + (1.0 - positive_ratio); 78 | } else { 79 | scale = (scale + 1.0) * (1.0 - ratio) + min_offset; 80 | } 81 | //(dot(viewDir, Normal) + 1.0) * 0.5, * ratio + (1.0 - ratio); 82 | Diffuse = Diffuse * surface_col * scale; 83 | 84 | FragColor = vec4(Diffuse, 1.0) * (1.0 - wire) + wire * wireCol4; 85 | bool is_frg = (nearZ < depth) && (depth < farZ); 86 | 87 | if (is_frg) { 88 | int geoid = int(round(Id.y - 1)); 89 | vec3 selectPosColor = selectedPosColors[geoid]; 90 | const float SELECT_COLOR_RADIUS = 10; 91 | for (int i = 0; i < N_POSITIONS; ++i) { 92 | // Ignore defualt [0, 0] 93 | vec3 selected_pos = selectedPositions[geoid * N_POSITIONS + i]; 94 | if (selected_pos.x < 1.0 || selected_pos.y < 1.0) { 95 | continue; 96 | } 97 | // Handle occulsion by depth check 98 | if (selected_pos.z - depth > selectedPosDepthTh) { 99 | continue; 100 | } 101 | vec2 posInBuf = gl_FragCoord.xy - viewportOffset; 102 | float dist = distance(posInBuf, selected_pos.xy); 103 | if (dist <= SELECT_COLOR_RADIUS) { 104 | FragColor = vec4(selectPosColor, 1.0); 105 | } 106 | } 107 | } else { 108 | FragColor = vec4(bkgCol, 1.0); 109 | } 110 | } -------------------------------------------------------------------------------- /src/shader/glsl/frag/gbuf.frag: -------------------------------------------------------------------------------- 1 | #version 330 2 | layout(location = 0) out vec3 gPosition; 3 | layout(location = 1) out vec3 gNormal; 4 | layout(location = 2) out vec4 gAlbedoSpec; 5 | layout(location = 3) out vec4 gId; 6 | layout(location = 4) out vec4 gFace; 7 | 8 | in vec3 fragPos; 9 | in vec3 viewPos; 10 | in vec2 texCoords; 11 | in vec3 normal; 12 | in vec3 wldNormal; 13 | in vec3 vertexColor; 14 | in vec3 vertexId; 15 | in vec2 bary; 16 | in vec3 dist; 17 | 18 | uniform sampler2D texture_diffuse1; 19 | uniform sampler2D texture_specular1; 20 | 21 | void main() { 22 | // store the fragment position vector in the first gbuffer texture 23 | gPosition = fragPos; 24 | // also store the per-fragment normals into the gbuffer 25 | gNormal = normalize(wldNormal); 26 | // and the diffuse per-fragment color 27 | gAlbedoSpec.rgb = texture(texture_diffuse1, texCoords).rgb; 28 | // store specular intensity in gAlbedoSpec's alpha component 29 | gAlbedoSpec.a = texture(texture_specular1, texCoords).r; 30 | 31 | gId.x = float(gl_PrimitiveID + 1); // vertedId.x; 32 | gId.y = vertexId.y; 33 | 34 | gId.z = -viewPos.z; // Linear depth 35 | 36 | gFace.xy = bary; 37 | gFace.zw = texCoords; 38 | 39 | vec3 dist_vec = dist; 40 | float d = min(dist_vec[0], min(dist_vec[1], dist_vec[2])); 41 | float I = exp2(-2.0 * d * d); 42 | // Use specular for wire intensity 43 | gAlbedoSpec.a = clamp(I, 0.0, 1.0); 44 | } -------------------------------------------------------------------------------- /src/shader/glsl/frag/text.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | in vec2 TexCoords; 3 | out vec4 FragColor; 4 | 5 | uniform sampler2D text; 6 | uniform vec3 textColor; 7 | 8 | void main() { 9 | vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r); 10 | FragColor = vec4(textColor, 1.0) * sampled; 11 | } -------------------------------------------------------------------------------- /src/shader/glsl/geom/dummy.geom: -------------------------------------------------------------------------------- 1 | #version 330 2 | layout(triangles) in; 3 | layout(triangle_strip, max_vertices = 3) out; 4 | 5 | uniform vec2 WIN_SCALE; 6 | uniform float FLAT_NORMAL; 7 | 8 | in vec3 vFragPos[]; 9 | in vec3 vViewPos[]; 10 | in vec2 vTexCoords[]; 11 | in vec3 vNormal[]; 12 | in vec3 vWldNormal[]; 13 | in vec3 vVertexColor[]; 14 | in vec3 vVertexId[]; 15 | 16 | out vec3 fragPos; 17 | out vec3 viewPos; 18 | out vec2 texCoords; 19 | out vec3 normal; 20 | out vec3 wldNormal; 21 | out vec3 vertexColor; 22 | out vec3 vertexId; 23 | out vec2 bary; 24 | out vec3 dist; 25 | 26 | void main() { 27 | vec3[3] dists = 28 | vec3[](vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 0.0)); 29 | 30 | vec4 p0_3d = gl_in[0].gl_Position; 31 | vec4 p1_3d = gl_in[1].gl_Position; 32 | vec4 p2_3d = gl_in[2].gl_Position; 33 | 34 | vec2 p0 = p0_3d.xy / p0_3d.w; 35 | vec2 p1 = p1_3d.xy / p1_3d.w; 36 | vec2 p2 = p2_3d.xy / p2_3d.w; 37 | 38 | vec2 v10 = WIN_SCALE * (p1 - p0); 39 | vec2 v20 = WIN_SCALE * (p2 - p0); 40 | float area0 = abs(v10.x * v20.y - v10.y * v20.x); 41 | float h0 = area0 / length(v10 - v20); 42 | dists[0] = vec3(h0, 0.0, 0.0); 43 | 44 | vec2 v01 = WIN_SCALE * (p0 - p1); 45 | vec2 v21 = WIN_SCALE * (p2 - p1); 46 | float area1 = abs(v01.x * v21.y - v01.y * v21.x); 47 | float h1 = area1 / length(v01 - v21); 48 | dists[1] = vec3(0.0, h1, 0.0); 49 | 50 | vec2 v02 = WIN_SCALE * (p0 - p2); 51 | vec2 v12 = WIN_SCALE * (p1 - p2); 52 | float area2 = abs(v02.x * v12.y - v02.y * v12.x); 53 | float h2 = area2 / length(v02 - v12); 54 | dists[2] = vec3(0.0, 0.0, h2); 55 | 56 | vec3 flat_normal = normalize(cross(normalize(vFragPos[1] - vFragPos[0]), 57 | normalize(vFragPos[2] - vFragPos[0]))); 58 | 59 | for (int i = 0; i < gl_in.length(); ++i) { 60 | gl_Position = gl_in[i].gl_Position; 61 | gl_PrimitiveID = gl_PrimitiveIDIn; 62 | // fid = gl_PrimitiveIDIn; 63 | fragPos = vFragPos[i]; 64 | viewPos = vViewPos[i]; 65 | texCoords = vTexCoords[i]; 66 | normal = vNormal[i]; 67 | wldNormal = mix(vWldNormal[i], flat_normal, FLAT_NORMAL); 68 | vertexColor = vVertexColor[i]; 69 | vertexId = vVertexId[i]; 70 | if (i == 0) { 71 | bary = vec2(0.0, 0.0); 72 | } else if (i == 1) { 73 | bary = vec2(1.0, 0.0); 74 | } else { 75 | bary = vec2(0.0, 1.0); 76 | } 77 | dist = dists[i]; 78 | EmitVertex(); 79 | } 80 | EndPrimitive(); 81 | } 82 | -------------------------------------------------------------------------------- /src/shader/glsl/vert/deferred.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | layout(location = 0) in vec3 aPos; 3 | layout(location = 1) in vec2 aTexCoords; 4 | 5 | out vec2 TexCoords; 6 | 7 | void main() { 8 | TexCoords = aTexCoords; 9 | gl_Position = vec4(aPos, 1.0); 10 | } -------------------------------------------------------------------------------- /src/shader/glsl/vert/gbuf.vert: -------------------------------------------------------------------------------- 1 | #version 330 2 | layout(location = 0) in vec3 aPos; 3 | layout(location = 1) in vec3 aNormal; 4 | layout(location = 2) in vec2 aTexCoords; 5 | layout(location = 3) in vec3 aVertexColor; 6 | layout(location = 4) in vec3 aVertexId; 7 | 8 | uniform mat4 model; 9 | uniform mat4 view; 10 | uniform mat4 projection; 11 | 12 | // out vec3 fragPos; 13 | // out vec3 viewPos; 14 | // out vec2 texCoords; 15 | // out vec3 normal; 16 | // out vec3 wldNormal; 17 | // out vec3 vertexColor; 18 | 19 | // void main() { 20 | // vec4 worldPos = model * vec4(aPos, 1.0); 21 | // vec4 view_Pos = view * worldPos; 22 | // fragPos = worldPos.xyz; 23 | // viewPos = view_Pos.xyz; 24 | // texCoords = aTexCoords; 25 | // vertexColor = aVertexColor; 26 | 27 | // mat3 normalMatrix = transpose(inverse(mat3(model))); 28 | // normal = normalMatrix * aNormal; 29 | // wldNormal = aNormal; 30 | 31 | // gl_Position = projection * view_Pos; 32 | // } 33 | 34 | out vec3 vFragPos; 35 | out vec3 vViewPos; 36 | out vec2 vTexCoords; 37 | out vec3 vNormal; 38 | out vec3 vWldNormal; 39 | out vec3 vVertexColor; 40 | out vec3 vVertexId; 41 | 42 | void main() { 43 | vec4 worldPos = model * vec4(aPos, 1.0); 44 | vec4 view_Pos = view * worldPos; 45 | vFragPos = worldPos.xyz; 46 | vViewPos = view_Pos.xyz; 47 | vTexCoords = aTexCoords; 48 | vVertexColor = aVertexColor; 49 | 50 | mat3 normalMatrix = transpose(inverse(mat3(model))); 51 | vNormal = normalMatrix * aNormal; 52 | vWldNormal = aNormal; 53 | vVertexId = aVertexId; 54 | 55 | gl_Position = projection * view_Pos; 56 | } -------------------------------------------------------------------------------- /src/shader/glsl/vert/text.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | layout(location = 0) in vec4 vertex; // 3 | out vec2 TexCoords; 4 | 5 | uniform mat4 projection; 6 | 7 | void main() { 8 | gl_Position = projection * vec4(vertex.xy, 0.0, 1.0); 9 | TexCoords = vertex.zw; 10 | } -------------------------------------------------------------------------------- /src/shader/vert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Automatically generated by script/glsl2header.py 3 | */ 4 | /* 5 | * Copyright (C) 2023, unclearness 6 | * All rights reserved. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | namespace ugu { 14 | 15 | static inline std::string vert_deferred_code = 16 | R"( 17 | #version 330 core 18 | layout(location = 0) in vec3 aPos; 19 | layout(location = 1) in vec2 aTexCoords; 20 | 21 | out vec2 TexCoords; 22 | 23 | void main() { 24 | TexCoords = aTexCoords; 25 | gl_Position = vec4(aPos, 1.0); 26 | })"; 27 | static inline std::string vert_gbuf_code = 28 | R"( 29 | #version 330 30 | layout(location = 0) in vec3 aPos; 31 | layout(location = 1) in vec3 aNormal; 32 | layout(location = 2) in vec2 aTexCoords; 33 | layout(location = 3) in vec3 aVertexColor; 34 | layout(location = 4) in vec3 aVertexId; 35 | 36 | uniform mat4 model; 37 | uniform mat4 view; 38 | uniform mat4 projection; 39 | 40 | // out vec3 fragPos; 41 | // out vec3 viewPos; 42 | // out vec2 texCoords; 43 | // out vec3 normal; 44 | // out vec3 wldNormal; 45 | // out vec3 vertexColor; 46 | 47 | // void main() { 48 | // vec4 worldPos = model * vec4(aPos, 1.0); 49 | // vec4 view_Pos = view * worldPos; 50 | // fragPos = worldPos.xyz; 51 | // viewPos = view_Pos.xyz; 52 | // texCoords = aTexCoords; 53 | // vertexColor = aVertexColor; 54 | 55 | // mat3 normalMatrix = transpose(inverse(mat3(model))); 56 | // normal = normalMatrix * aNormal; 57 | // wldNormal = aNormal; 58 | 59 | // gl_Position = projection * view_Pos; 60 | // } 61 | 62 | out vec3 vFragPos; 63 | out vec3 vViewPos; 64 | out vec2 vTexCoords; 65 | out vec3 vNormal; 66 | out vec3 vWldNormal; 67 | out vec3 vVertexColor; 68 | out vec3 vVertexId; 69 | 70 | void main() { 71 | vec4 worldPos = model * vec4(aPos, 1.0); 72 | vec4 view_Pos = view * worldPos; 73 | vFragPos = worldPos.xyz; 74 | vViewPos = view_Pos.xyz; 75 | vTexCoords = aTexCoords; 76 | vVertexColor = aVertexColor; 77 | 78 | mat3 normalMatrix = transpose(inverse(mat3(model))); 79 | vNormal = normalMatrix * aNormal; 80 | vWldNormal = aNormal; 81 | vVertexId = aVertexId; 82 | 83 | gl_Position = projection * view_Pos; 84 | })"; 85 | static inline std::string vert_text_code = 86 | R"( 87 | #version 330 core 88 | layout(location = 0) in vec4 vertex; // 89 | out vec2 TexCoords; 90 | 91 | uniform mat4 projection; 92 | 93 | void main() { 94 | gl_Position = projection * vec4(vertex.xy, 0.0, 1.0); 95 | TexCoords = vertex.zw; 96 | })"; 97 | } // namespace ugu 98 | -------------------------------------------------------------------------------- /src/stb.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu_stb.h" 7 | 8 | #ifdef UGU_USE_STB 9 | #ifdef _WIN32 10 | #pragma warning(push) 11 | #pragma warning(disable : 4100) 12 | #endif 13 | #define STB_IMAGE_IMPLEMENTATION 14 | #include "stb_image.h" 15 | #ifdef _WIN32 16 | #pragma warning(pop) 17 | #endif 18 | 19 | #ifdef _WIN32 20 | #pragma warning(push) 21 | #pragma warning(disable : 4996) 22 | #endif 23 | #define STB_IMAGE_WRITE_IMPLEMENTATION 24 | #include "stb_image_write.h" 25 | #ifdef _WIN32 26 | #pragma warning(pop) 27 | #endif 28 | 29 | #ifdef _WIN32 30 | #pragma warning(push) 31 | #pragma warning(disable : 4996) 32 | #endif 33 | #define STB_IMAGE_RESIZE_IMPLEMENTATION 34 | #include "stb_image_resize2.h" 35 | #ifdef _WIN32 36 | #pragma warning(pop) 37 | #endif 38 | 39 | #include 40 | 41 | namespace { 42 | STBIDEF unsigned char *stbi_xload(stbi__context *s, int *x, int *y, int *frames, 43 | int **delays) { 44 | int comp; 45 | unsigned char *result = 0; 46 | 47 | if (stbi__gif_test(s)) 48 | return reinterpret_cast( 49 | stbi__load_gif_main(s, delays, x, y, frames, &comp, 4)); 50 | 51 | stbi__result_info ri; 52 | result = reinterpret_cast( 53 | stbi__load_main(s, x, y, &comp, 4, &ri, 8)); 54 | *frames = !!result; 55 | 56 | if (ri.bits_per_channel != 8) { 57 | STBI_ASSERT(ri.bits_per_channel == 16); 58 | result = stbi__convert_16_to_8((stbi__uint16 *)result, *x, *y, 4); 59 | ri.bits_per_channel = 8; 60 | } 61 | 62 | return result; 63 | } 64 | } // namespace 65 | 66 | namespace ugu { 67 | 68 | STBIDEF unsigned char *stbi_xload_file(char const *filename, int *x, int *y, 69 | int *frames, int **delays) { 70 | FILE *f; 71 | stbi__context s; 72 | unsigned char *result = 0; 73 | f = stbi__fopen(filename, "rb"); 74 | if (!f) { 75 | return stbi__errpuc("can't fopen", "Unable to open file"); 76 | } 77 | 78 | stbi__start_file(&s, f); 79 | result = stbi_xload(&s, x, y, frames, delays); 80 | fclose(f); 81 | 82 | return result; 83 | } 84 | 85 | std::vector LoadGif(const std::string &filename, int &x, int &y, 86 | int &frames, std::vector &delays) { 87 | std::vector data; 88 | 89 | delays.clear(); 90 | 91 | int *tmp_delays = NULL; 92 | unsigned char *tmp_data = 93 | stbi_xload_file(filename.c_str(), &x, &y, &frames, &tmp_delays); 94 | 95 | if (tmp_data == NULL) { 96 | return data; 97 | } 98 | 99 | for (int i = 0; i < frames; i++) { 100 | delays.push_back(tmp_delays[i]); 101 | } 102 | 103 | // Copy data 104 | const size_t num_pix = static_cast(x) * static_cast(y) * 4 * 105 | static_cast(frames); 106 | data.resize(num_pix, 0); 107 | std::memcpy(data.data(), tmp_data, sizeof(unsigned char) * num_pix); 108 | 109 | // Free tmp data allocated by stb 110 | STBI_FREE(tmp_delays); 111 | STBI_FREE(tmp_data); 112 | 113 | return data; 114 | } 115 | 116 | } // namespace ugu 117 | 118 | #endif -------------------------------------------------------------------------------- /src/synthesis/bdsim.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unclearness/ugu/a93cc523378813e6b1056a93447184b3fee358d4/src/synthesis/bdsim.cc -------------------------------------------------------------------------------- /src/texturing/vertex_colorizer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/texturing/vertex_colorizer.h" 7 | 8 | namespace ugu { 9 | 10 | VertexColorizer::VertexColorizer() {} 11 | VertexColorizer::~VertexColorizer() {} 12 | bool VertexColorizer::Colorize(const VisibilityInfo& info, Mesh* mesh, 13 | ViewSelectionCriteria criteria) const { 14 | if (!info.has_vertex_stat) { 15 | LOGE("no vertex stat\n"); 16 | return false; 17 | } 18 | 19 | assert(info.vertex_info_list.size() == mesh->vertices().size()); 20 | 21 | std::vector vertex_colors; 22 | 23 | std::function select = 24 | [&](const VertexInfo& info) -> Eigen::Vector3f { 25 | return info.min_viewing_angle_color; 26 | }; 27 | if (criteria == ViewSelectionCriteria::kMinViewingAngle) { 28 | select = [&](const VertexInfo& info) { 29 | return info.min_viewing_angle_color; 30 | }; 31 | } else if (criteria == ViewSelectionCriteria::kMinDistance) { 32 | select = [&](const VertexInfo& info) { return info.min_distance_color; }; 33 | } else if (criteria == ViewSelectionCriteria::kMeanViewingAngle) { 34 | select = [&](const VertexInfo& info) { 35 | return info.mean_viewing_angle_color; 36 | }; 37 | } else if (criteria == ViewSelectionCriteria::kMedianViewingAngle) { 38 | select = [&](const VertexInfo& info) { 39 | return info.median_viewing_angle_color; 40 | }; 41 | } else if (criteria == ViewSelectionCriteria::kMeanDistance) { 42 | select = [&](const VertexInfo& info) { return info.mean_distance_color; }; 43 | } else if (criteria == ViewSelectionCriteria::kMedianDistance) { 44 | select = [&](const VertexInfo& info) { return info.median_distance_color; }; 45 | } else if (criteria == ViewSelectionCriteria::kMinIntensity) { 46 | select = [&](const VertexInfo& info) { return info.min_intensity_color; }; 47 | } else if (criteria == ViewSelectionCriteria::kMedianIntensity) { 48 | select = [&](const VertexInfo& info) { 49 | return info.median_intensity_color; 50 | }; 51 | } else if (criteria == ViewSelectionCriteria::kMode) { 52 | select = [&](const VertexInfo& info) { 53 | return info.mode; 54 | ; 55 | }; 56 | } else if (criteria == ViewSelectionCriteria::kModeViewingAngle) { 57 | select = [&](const VertexInfo& info) { 58 | return info.mode_viewing_angle_color; 59 | ; 60 | }; 61 | } else if (criteria == ViewSelectionCriteria::kCustom) { 62 | select = [&](const VertexInfo& info) { 63 | return info.custom_best; 64 | ; 65 | }; 66 | } 67 | 68 | for (size_t i = 0; i < info.vertex_info_list.size(); i++) { 69 | vertex_colors.push_back(select(info.vertex_info_list[i])); 70 | } 71 | 72 | mesh->set_vertex_colors(vertex_colors); 73 | 74 | return true; 75 | } 76 | 77 | } // namespace ugu 78 | -------------------------------------------------------------------------------- /src/ugu_stb.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef UGU_USE_STB 4 | #ifdef _WIN32 5 | #pragma warning(push) 6 | #pragma warning(disable : 4100) 7 | #endif 8 | #include "stb_image.h" 9 | #ifdef _WIN32 10 | #pragma warning(pop) 11 | #endif 12 | 13 | #include 14 | #include 15 | 16 | namespace ugu { 17 | STBIDEF unsigned char* stbi_xload_file(char const* filename, int* x, int* y, 18 | int* frames, int** delays); 19 | 20 | std::vector LoadGif(const std::string& filename, int& x, int& y, 21 | int& frames, std::vector& delays); 22 | } // namespace ugu 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/util/io_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/util/io_util.h" 7 | 8 | #include 9 | 10 | namespace ugu { 11 | 12 | std::string LoadTxt(const std::string& path) { 13 | std::ifstream ifs(path); 14 | if (ifs.fail()) { 15 | return ""; 16 | } 17 | std::string str((std::istreambuf_iterator(ifs)), 18 | std::istreambuf_iterator()); 19 | return str; 20 | } 21 | 22 | void WriteFaceIdAsText(const Image1i& face_id, const std::string& path) { 23 | std::ofstream ofs; 24 | ofs.open(path, std::ios::out); 25 | 26 | for (int y = 0; y < face_id.rows; y++) { 27 | for (int x = 0; x < face_id.cols; x++) { 28 | ofs << face_id.at(y, x) << "\n"; 29 | } 30 | } 31 | 32 | ofs.flush(); 33 | } 34 | 35 | } // namespace ugu 36 | -------------------------------------------------------------------------------- /src/util/math_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/util/math_util.h" 7 | 8 | #include "ugu/util/geom_util.h" 9 | 10 | namespace { 11 | 12 | template 13 | void ComputeAxisForPointsImpl(const std::vector>& points, 14 | std::array, N>& axis, 15 | std::array& weights, 16 | Eigen::Matrix& means) { 17 | ugu::Pca pca; 18 | Eigen::MatrixXd pca_data; 19 | pca_data.resize(N, static_cast(points.size())); 20 | 21 | for (size_t i = 0; i < points.size(); i++) { 22 | for (int j = 0; j < N; j++) { 23 | pca_data(j, i) = static_cast(points[i][j]); 24 | } 25 | } 26 | 27 | pca.Compute(pca_data); 28 | 29 | // ugu::LOGI("\n"); 30 | for (int j = 0; j < N; j++) { 31 | axis[j] = Eigen::Matrix(pca.vecs.col(j).cast()); 32 | weights[j] = T(pca.coeffs(j, 0)); 33 | // ugu::LOGI("%d %f\n", j, weights[j]); 34 | } 35 | 36 | means = pca.means.cast(); 37 | // ugu::LOGI("\n"); 38 | } 39 | 40 | } // namespace 41 | 42 | namespace ugu { 43 | 44 | Eigen::Vector3f MedianColor(const std::vector& colors) { 45 | Eigen::Vector3f median; 46 | std::vector> ith_channel_list(3); 47 | for (const auto& color : colors) { 48 | for (int i = 0; i < 3; i++) { 49 | ith_channel_list[i].push_back(color[i]); 50 | } 51 | } 52 | for (int i = 0; i < 3; i++) { 53 | median[i] = Median(ith_channel_list[i]); 54 | } 55 | return median; 56 | } 57 | 58 | void ComputeAxisForPoints(const std::vector& points, 59 | std::array& axes, 60 | std::array& weights, 61 | Eigen::Vector3f& means) { 62 | ComputeAxisForPointsImpl(points, axes, weights, means); 63 | } 64 | 65 | void ComputeAxisForPoints(const std::vector& points, 66 | std::array& axes, 67 | std::array& weights, 68 | Eigen::Vector2f& means) { 69 | ComputeAxisForPointsImpl(points, axes, weights, means); 70 | } 71 | 72 | OrientedBoundingBox::OrientedBoundingBox(){}; 73 | OrientedBoundingBox::OrientedBoundingBox( 74 | const std::vector& points) { 75 | Init(points); 76 | } 77 | OrientedBoundingBox::~OrientedBoundingBox(){}; 78 | void OrientedBoundingBox::Init(const std::vector& points) { 79 | std::array weights; 80 | Eigen::Vector3f means; 81 | ComputeAxisForPoints(points, axes, weights, means); 82 | bb2wld.col(0) = axes[0]; 83 | bb2wld.col(1) = axes[1]; 84 | bb2wld.col(2) = axes[2]; 85 | wld2bb = bb2wld.inverse(); 86 | std::vector points_bb; 87 | std::transform(points.begin(), points.end(), std::back_inserter(points_bb), 88 | [&](const Eigen::Vector3f& p) { return wld2bb * p; }); 89 | max_bb = ComputeMaxBound(points_bb); 90 | min_bb = ComputeMinBound(points_bb); 91 | 92 | center_wld = bb2wld * (0.5f * (max_bb + min_bb)); 93 | len = max_bb - min_bb; 94 | offset = len.minCoeff() * 0.001f; 95 | } 96 | 97 | bool OrientedBoundingBox::IsInside(const Eigen::Vector3f& p_wld) { 98 | auto p_bb = wld2bb * p_wld; 99 | for (int i = 0; i < 3; i++) { 100 | if (p_bb[i] < min_bb[i] - offset || max_bb[i] + offset < p_bb[i]) { 101 | return false; 102 | } 103 | } 104 | return true; 105 | } 106 | 107 | } // namespace ugu 108 | -------------------------------------------------------------------------------- /src/util/raster_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/util/raster_util.h" 7 | 8 | namespace ugu { 9 | bool GenerateUvMask(const std::vector& uvs, 10 | const std::vector& uv_indices, 11 | Image1b& mask, uint8_t color, int width, int height, 12 | int num_threads) { 13 | ugu::Image3b mask3b = ugu::Image3b::zeros(height, width); 14 | float c_ = static_cast(color); 15 | bool ret = GenerateUvMask(uvs, uv_indices, mask3b, {c_, c_, c_}, width, 16 | height, num_threads); 17 | ugu::Image1b mask_ = ugu::Image1b::zeros(height, width); 18 | for (int y = 0; y < mask_.rows; y++) { 19 | for (int x = 0; x < mask_.cols; x++) { 20 | mask_.at(y, x) = mask3b.at(y, x)[0]; 21 | } 22 | } 23 | mask = mask_; 24 | return ret; 25 | } 26 | 27 | } // namespace ugu 28 | -------------------------------------------------------------------------------- /src/util/string_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/util/string_util.h" 7 | 8 | #include 9 | 10 | namespace { 11 | std::string::size_type FindLastSeparatorPos(const std::string& path) { 12 | std::string::size_type pos = std::string::npos; 13 | const std::string::size_type unix_pos = path.find_last_of('/'); 14 | const std::string::size_type windows_pos = path.find_last_of('\\'); 15 | if (unix_pos != std::string::npos) { 16 | if (pos == std::string::npos) { 17 | pos = unix_pos; 18 | } else { 19 | pos = std::max(pos, unix_pos); 20 | } 21 | } 22 | if (windows_pos != std::string::npos) { 23 | if (pos == std::string::npos) { 24 | pos = windows_pos; 25 | } else { 26 | pos = std::max(pos, unix_pos); 27 | } 28 | } 29 | return pos; 30 | } 31 | 32 | } // namespace 33 | 34 | namespace ugu { 35 | 36 | std::string ExtractFilename(const std::string& path, bool without_ext) { 37 | std::string::size_type pos = FindLastSeparatorPos(path); 38 | std::string fn = 39 | (pos == std::string::npos) ? path : path.substr(pos + 1, path.size()); 40 | if (without_ext) { 41 | return ExtractPathWithoutExt(fn); 42 | } 43 | return fn; 44 | } 45 | 46 | std::string ExtractDir(const std::string& path) { 47 | std::string::size_type pos = FindLastSeparatorPos(path); 48 | return (pos == std::string::npos) ? "./" : path.substr(0, pos + 1); 49 | } 50 | 51 | std::string ExtractExt(const std::string& path, bool no_dot) { 52 | size_t ext_i = path.find_last_of("."); 53 | if (ext_i == std::string::npos) { 54 | return ""; 55 | } 56 | std::string extname = no_dot ? path.substr(ext_i + 1, path.size() - ext_i) 57 | : path.substr(ext_i, path.size() - ext_i); 58 | return extname; 59 | } 60 | 61 | std::vector Split(const std::string& input, char delimiter) { 62 | std::istringstream stream(input); 63 | std::string field; 64 | std::vector result; 65 | while (std::getline(stream, field, delimiter)) { 66 | result.push_back(field); 67 | } 68 | return result; 69 | } 70 | 71 | std::streamoff stream_size(std::istream& f) { 72 | std::istream::pos_type current_pos = f.tellg(); 73 | if (-1 == current_pos) { 74 | return -1; 75 | } 76 | f.seekg(0, std::istream::end); 77 | std::istream::pos_type end_pos = f.tellg(); 78 | f.seekg(current_pos); 79 | return end_pos - current_pos; 80 | } 81 | 82 | bool stream_read_string(std::istream& f, 83 | std::string& result) { // NOLINT 84 | std::streamoff len = stream_size(f); 85 | if (len == -1) { 86 | return false; 87 | } 88 | 89 | result.resize(static_cast(len)); 90 | 91 | f.read(&result[0], result.length()); 92 | return true; 93 | } 94 | 95 | std::string ExtractPathWithoutExt(const std::string& fn) { 96 | std::string::size_type pos; 97 | if ((pos = fn.find_last_of(".")) == std::string::npos) { 98 | return fn; 99 | } 100 | 101 | return fn.substr(0, pos); 102 | } 103 | 104 | std::string ReplaceExtention(const std::string& path, const std::string& ext) { 105 | return ExtractPathWithoutExt(path) + ext; 106 | } 107 | 108 | } // namespace ugu 109 | -------------------------------------------------------------------------------- /src/util/thread_util.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | #include "ugu/util/thread_util.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace { 15 | 16 | template 17 | void parallel_for_impl(Index st, Index ed, Func func, int num_theads = -1, 18 | Index inc = Index(1)) { 19 | uint32_t num_cpu = num_theads > 0 20 | ? std::min(static_cast(num_theads), 21 | std::thread::hardware_concurrency()) 22 | : std::thread::hardware_concurrency(); 23 | 24 | // Prefer to UGU_THREADS_NUM 25 | if (ugu::UGU_THREADS_NUM > 0) { 26 | num_cpu = ugu::UGU_THREADS_NUM; 27 | } 28 | 29 | assert(num_cpu > 0); 30 | 31 | if (num_cpu == 1) { 32 | for (Index j = st; j < ed; j += inc) { 33 | func(j); 34 | } 35 | return; 36 | } 37 | 38 | const Index jobs_per_thread = 39 | static_cast((ed - st + num_cpu - 1) / num_cpu); 40 | 41 | std::vector threads; 42 | 43 | for (Index i = st; i < ed; i += jobs_per_thread) { 44 | Index end_this_thread = std::min(i + jobs_per_thread, ed); 45 | threads.emplace_back([i, end_this_thread, inc, &func]() { 46 | for (Index j = i; j < end_this_thread; j += inc) { 47 | func(j); 48 | } 49 | }); 50 | } 51 | 52 | // Wait all threads... 53 | for (auto& t : threads) { 54 | if (t.joinable()) { 55 | t.join(); 56 | } 57 | } 58 | } 59 | } // namespace 60 | namespace ugu { 61 | 62 | void parallel_for(int st, int ed, std::function func, int num_theads, 63 | int inc) { 64 | parallel_for_impl(st, ed, func, num_theads, inc); 65 | } 66 | void parallel_for(size_t st, size_t ed, std::function func, 67 | int num_theads, size_t inc) { 68 | parallel_for_impl(st, ed, func, num_theads, inc); 69 | } 70 | 71 | } // namespace ugu 72 | -------------------------------------------------------------------------------- /src/voxel/marching_cubes_lut.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, unclearness 3 | * All rights reserved. 4 | */ 5 | 6 | // original code is from 7 | // http://paulbourke.net/geometry/polygonise/ 8 | 9 | #include "ugu/voxel/marching_cubes_lut.h" 10 | 11 | #include 12 | 13 | namespace ugu { 14 | namespace marching_cubes_lut {} 15 | } // namespace ugu 16 | --------------------------------------------------------------------------------