├── .clang-format ├── .editorconfig ├── .gitignore ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── micromesh_core ├── CMakeLists.txt ├── README.md ├── include │ ├── micromesh │ │ ├── micromesh_api.h │ │ ├── micromesh_format_types.h │ │ ├── micromesh_gpu.h │ │ ├── micromesh_operations.h │ │ ├── micromesh_types.h │ │ └── micromesh_utils.h │ └── micromesh_internal │ │ ├── micromesh_containers.h │ │ ├── micromesh_context.h │ │ └── micromesh_math.h ├── src │ ├── context.cpp │ ├── convert.cpp │ ├── mesh.cpp │ ├── micromap.cpp │ ├── sanitize.cpp │ └── utils.cpp └── test │ └── test_core.cpp ├── micromesh_displacement_compression ├── CMakeLists.txt ├── README.md ├── include │ └── micromesh │ │ └── micromesh_displacement_compression.h ├── src │ ├── cpp_compatibility.cpp │ ├── cpp_compatibility.h │ ├── displacement_block_codec.cpp │ ├── displacement_block_codec.h │ ├── displacement_compression.cpp │ ├── displacement_configs.cpp │ ├── displacement_configs.h │ ├── displacement_diagnostic_utils.h │ ├── displacement_mesh_codec.cpp │ └── displacement_mesh_codec.h └── test │ └── test_compression.cpp └── micromesh_displacement_remeshing ├── CMakeLists.txt ├── README.md ├── cmake ├── FindVulkanSDK.cmake └── vulkan.cmake ├── include └── micromesh │ └── micromesh_displacement_remeshing.h ├── shaders ├── remesh_accessors.h ├── remesh_apply_min_displacement.comp.glsl ├── remesh_apply_min_displacement.h ├── remesh_bindings.h ├── remesh_clear_edge_list.comp.glsl ├── remesh_clear_edge_list.h ├── remesh_clear_hash_map.comp.glsl ├── remesh_clear_hash_map.h ├── remesh_clear_micromesh_data.comp.glsl ├── remesh_clear_micromesh_data.h ├── remesh_collapse_flag.comp.glsl ├── remesh_collapse_flag.h ├── remesh_collapse_propagate.comp.glsl ├── remesh_collapse_propagate.h ├── remesh_collapse_resolve.comp.glsl ├── remesh_collapse_resolve.h ├── remesh_common.h ├── remesh_compact_indices.comp.glsl ├── remesh_compact_indices.h ├── remesh_compact_vertices.comp.glsl ├── remesh_compact_vertices.h ├── remesh_deduplicate.comp.glsl ├── remesh_deduplicate.h ├── remesh_deduplicate_base.comp.glsl ├── remesh_deduplicate_base.h ├── remesh_deduplicate_finalize.comp.glsl ├── remesh_deduplicate_finalize.h ├── remesh_deduplicate_finalize_base.comp.glsl ├── remesh_deduplicate_finalize_base.h ├── remesh_deduplicate_save_aliases_base.comp.glsl ├── remesh_deduplicate_save_aliases_base.h ├── remesh_edge_cost_distribute.comp.glsl ├── remesh_edge_cost_distribute.h ├── remesh_edge_list.comp.glsl ├── remesh_edge_list.h ├── remesh_edge_list_finalize.comp.glsl ├── remesh_edge_list_finalize.h ├── remesh_generate_subdivision_info.comp.glsl ├── remesh_generate_subdivision_info.h ├── remesh_host_device.h ├── remesh_init_quadrics.comp.glsl ├── remesh_init_quadrics.h ├── remesh_link_high_low_vertices.comp.glsl ├── remesh_link_high_low_vertices.h ├── remesh_quadrics.comp.glsl └── remesh_quadrics.h ├── src ├── remeshing_cpu.cpp ├── remeshing_gpu.cpp └── remeshing_internal.h └── test └── test_remeshing.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | AccessModifierOffset: '-2' 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveAssignments: 'true' 5 | AlignConsecutiveDeclarations: 'true' 6 | AlignOperands: 'true' 7 | AlignTrailingComments: 'true' 8 | AllowAllParametersOfDeclarationOnNextLine: 'false' 9 | AllowShortBlocksOnASingleLine: 'false' 10 | AllowShortCaseLabelsOnASingleLine: 'false' 11 | AllowShortFunctionsOnASingleLine: Inline 12 | AllowShortIfStatementsOnASingleLine: 'false' 13 | AllowShortLoopsOnASingleLine: 'false' 14 | AlwaysBreakAfterReturnType: None 15 | AlwaysBreakBeforeMultilineStrings: 'true' 16 | AlwaysBreakTemplateDeclarations: 'true' 17 | BinPackArguments: 'true' 18 | BinPackParameters: 'false' 19 | ExperimentalAutoDetectBinPacking: 'false' 20 | BreakBeforeBinaryOperators: NonAssignment 21 | BreakBeforeBraces: Custom 22 | BreakBeforeTernaryOperators: 'false' 23 | BreakConstructorInitializersBeforeComma: 'true' 24 | ColumnLimit: '120' 25 | ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' 26 | Cpp11BracedListStyle: 'true' 27 | IndentCaseLabels: 'false' 28 | IndentWidth: '4' 29 | KeepEmptyLinesAtTheStartOfBlocks: 'false' 30 | Language: Cpp 31 | MaxEmptyLinesToKeep: '2' 32 | NamespaceIndentation: None 33 | ObjCSpaceBeforeProtocolList: 'true' 34 | PointerAlignment: Left 35 | SpaceAfterCStyleCast: 'false' 36 | SpaceBeforeAssignmentOperators: 'true' 37 | SpaceBeforeParens: Never 38 | SpaceInEmptyParentheses: 'false' 39 | SpacesBeforeTrailingComments: '2' 40 | SpacesInAngles: 'false' 41 | SpacesInCStyleCastParentheses: 'false' 42 | SpacesInParentheses: 'false' 43 | SpacesInSquareBrackets: 'false' 44 | Standard: Cpp11 45 | TabWidth: '2' 46 | UseTab: Never 47 | SortIncludes: 'false' 48 | ReflowComments: 'false' 49 | BraceWrapping: { 50 | AfterClass: 'true' 51 | AfterControlStatement: 'true' 52 | AfterEnum: 'true' 53 | AfterFunction: 'true' 54 | AfterNamespace: 'true' 55 | AfterStruct: 'true' 56 | AfterUnion: 'true' 57 | BeforeCatch: 'true' 58 | BeforeElse: 'true' 59 | IndentBraces: 'false' 60 | } 61 | PenaltyExcessCharacter: 1 62 | PenaltyBreakBeforeFirstCallParameter: 40 63 | PenaltyBreakFirstLessLess: 1 64 | PenaltyBreakComment: 30 65 | PenaltyBreakString: 30 66 | PenaltyReturnTypeOnItsOwnLine: 9999 67 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This is the top-most editor config file 2 | root = true 3 | 4 | # Default to 4 space indentation for C/C++ files 5 | [*.{c,cpp,h,hpp,inl}] 6 | indent_size = 4 7 | indent_style = space 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | _build 3 | inst*/ 4 | _inst*/ 5 | **/Debug 6 | **/Release/* 7 | **/CMakeFiles 8 | **/cmake_install.cmake 9 | /.vs 10 | .vscode/ 11 | *.sln 12 | *.vcxproj 13 | *.vcxproj.filters 14 | *.vcxproj.user 15 | cmake_build 16 | micromesh_displacement_remeshing/cmake_build 17 | micromesh_displacement_remeshing/_autogen/ 18 | micromesh_displacement_remeshing/b/ 19 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVIDIAGameWorks/Displacement-MicroMap-SDK/bf41d657fa40c7b1ad0d1ff3767e18e45b93fc4d/LICENSE.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!IMPORTANT] 2 | > This project has been archived and is no longer maintained. The vulkan 3 | > extension `VK_NV_displacement_micromap` is no longer available. 4 | > 5 | > We recommend exploring [**NVIDIA RTX Mega 6 | > Geometry**](https://developer.nvidia.com/blog/nvidia-rtx-mega-geometry-now-available-with-new-vulkan-samples/), 7 | > which can provide similar functionality with greater flexibility. See 8 | > [vk_tessellated_clusters](https://github.com/nvpro-samples/vk_tessellated_clusters), 9 | > which demonstrates raytracing displacement with Vulkan. 10 | 11 | # NVIDIA Displacement Micro-Map SDK 12 | 13 | For more information about NVIDIA Micro-Mesh Technology visit [NVIDIA developer](https://developer.nvidia.com/rtx/ray-tracing/micro-mesh) 14 | 15 | The libraries in this repository aid 3D asset content creation using displacement Micro-Maps. 16 | Please refer to the [NVIDIA Displacement-MicroMap-Toolkit](https://github.com/NVIDIAGameWorks/Displacement-MicroMap-Toolkit) to see them being used. 17 | 18 | This SDK provides a low-level API meant for embedding in other applications and tools. 19 | It has a C-style API as well as an API agnostic GPU interface to facilitate this. 20 | As a result it is sometimes a bit less easy to use. All functionality is provided 21 | through the `micromesh` namespace and it makes frequent use of the `micromesh::ArrayInfo` 22 | structure, which allows it to pass data as a pointer & stride combination. All user visible data 23 | is allocated by the user, so some operations are executed in two steps where a *micromeshOpSomethingBegin* returns 24 | the sizing required, while *micromeshOpSomethingEnd* completes it. One can also abort such 25 | operations with *micromeshOpContextAbort*. The `micromesh::Context` therefore is stateful 26 | but fairly lightweight, in case you want to create one per thread. Right now there is also some rudimentary 27 | automatic threading within the context. 28 | 29 | - [`micromesh_core`](/micromesh_core/README.md): Library for basic data structures, utilities and operations to create or modify micromap and micromesh data. 30 | - [`micromesh_displacement_compression`](/micromesh_displacement_compression/README.md): Library that handles the compression of displacement micromaps. 31 | - [`micromesh_displacement_remeshing`](/micromesh_displacement_remeshing/README.md): Library for GPU-based remeshing (currently only a Vulkan/SPIR-V based implementation for the GPU exists). 32 | 33 | ## About the Latest Release 34 | 35 | Version 2.1 36 | 37 | - Add OpTessellateMesh_input::pfnProvideTriangleVertices for control over the 38 | output location. 39 | - Add micromeshOpChangeLayoutPacked for format conversion 40 | - Fixed bugs in compressor bit packing 41 | 42 | Version 2.0 43 | 44 | - API break: micromesh::OpGrowTriangleSelection_input::topology is now a const array 45 | - Fix UB in compressor due to possible negative shifts 46 | - Step towards remesher determinism 47 | 48 | ## Support Contact 49 | 50 | Feel free to file issues directly on the GitHub page or reach out to NVIDIA at 51 | 52 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security 2 | 3 | NVIDIA is dedicated to the security and trust of our software products and services, including all source code repositories managed through our organization. 4 | 5 | If you need to report a security issue, please use the appropriate contact points outlined below. **Please do not report security vulnerabilities through GitHub/GitLab.** 6 | 7 | ## Reporting Potential Security Vulnerability in an NVIDIA Product 8 | 9 | To report a potential security vulnerability in any NVIDIA product: 10 | - Web: [Security Vulnerability Submission Form](https://www.nvidia.com/object/submit-security-vulnerability.html) 11 | - E-Mail: psirt@nvidia.com 12 | - We encourage you to use the following PGP key for secure email communication: [NVIDIA public PGP Key for communication](https://www.nvidia.com/en-us/security/pgp-key) 13 | - Please include the following information: 14 | - Product and driver version/branch that contains the vulnerability 15 | - Type of vulnerability (code execution, denial of service, buffer overflow, etc.) 16 | - Instructions to reproduce the vulnerability 17 | - Proof-of-concept or exploit code 18 | - Potential impact of the vulnerability, including how an attacker could exploit the vulnerability 19 | 20 | While NVIDIA currently does not have a bug bounty program, we do offer acknowledgement when an externally reported security issue is addressed under our coordinated vulnerability disclosure policy. Please visit our [Product Security Incident Response Team (PSIRT)](https://www.nvidia.com/en-us/security/psirt-policies/) policies page for more information. 21 | 22 | ## NVIDIA Product Security 23 | 24 | For all security-related concerns, please visit NVIDIA's Product Security portal at https://www.nvidia.com/en-us/security -------------------------------------------------------------------------------- /micromesh_core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | # Set the C/C++ specified in the projects as requirements 4 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 5 | set(CMAKE_C_STANDARD_REQUIRED ON) 6 | set(CMAKE_CXX_STANDARD 17) 7 | 8 | project(micromesh_core VERSION 2.1.0) 9 | 10 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 11 | 12 | if(UNIX) 13 | add_definitions(-DLINUX) 14 | endif() 15 | 16 | # XXXX we might be able to force this by setting CMAKE_GENERATOR_PLATFORM ?? 17 | if(NOT (CMAKE_SIZEOF_VOID_P EQUAL 8)) 18 | message( FATAL_ERROR "64-bit builds only : reconfigure with -A x64" ) 19 | endif() 20 | 21 | set(CMAKE_DEBUG_POSTFIX "_d") 22 | set(CMAKE_RELWITHDEBINFO_POSTFIX "_rd") 23 | 24 | find_package(Threads REQUIRED) 25 | 26 | # 27 | # build 28 | # 29 | 30 | set(PUBLIC_HEADER_FILES 31 | include/micromesh/micromesh_api.h 32 | include/micromesh/micromesh_types.h 33 | include/micromesh/micromesh_gpu.h 34 | include/micromesh/micromesh_utils.h 35 | include/micromesh/micromesh_operations.h 36 | include/micromesh/micromesh_format_types.h 37 | ) 38 | install(FILES ${PUBLIC_HEADER_FILES} DESTINATION "include") 39 | 40 | set(INTERNAL_HEADER_FILES 41 | include/micromesh_internal/micromesh_context.h 42 | include/micromesh_internal/micromesh_containers.h 43 | include/micromesh_internal/micromesh_math.h 44 | ) 45 | 46 | set(SOURCE_FILES 47 | src/context.cpp 48 | src/convert.cpp 49 | src/utils.cpp 50 | src/sanitize.cpp 51 | src/micromap.cpp 52 | src/mesh.cpp 53 | ) 54 | 55 | source_group("public_include" FILES ${PUBLIC_HEADER_FILES}) 56 | source_group("internal_include" FILES ${INTERNAL_HEADER_FILES}) 57 | source_group("source" FILES ${SOURCE_FILES}) 58 | 59 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}") 60 | 61 | # static lib 62 | 63 | add_library(micromesh_core STATIC ${SOURCE_FILES} ${PUBLIC_HEADER_FILES} ${INTERNAL_HEADER_FILES}) 64 | target_link_libraries(micromesh_core PUBLIC Threads::Threads) # So other projects link with the system thread library 65 | 66 | set_target_properties(micromesh_core PROPERTIES FOLDER "micromesh_core" 67 | POSITION_INDEPENDENT_CODE ON) 68 | 69 | target_include_directories(micromesh_core PUBLIC 70 | $ $/include>) 71 | 72 | install(TARGETS micromesh_core DESTINATION "lib" EXPORT "micromeshCoreTargets") 73 | 74 | # tests 75 | 76 | set(MICROMESH_CORE_BUILD_TESTS OFF CACHE BOOL "Build the unit tests for micromesh core") 77 | if(MICROMESH_CORE_BUILD_TESTS) 78 | set(TEST_FILES test/test_core.cpp) 79 | source_group("tests" FILES ${TEST_FILES}) 80 | add_executable(micromesh_core_test ${TEST_FILES}) 81 | target_link_libraries(micromesh_core_test micromesh_core) 82 | set_target_properties(micromesh_core_test PROPERTIES FOLDER "micromesh_core") 83 | endif() 84 | 85 | install(EXPORT "micromeshCoreTargets" FILE "micromeshCoreTargets.cmake" EXPORT_LINK_INTERFACE_LIBRARIES DESTINATION "cmake") 86 | 87 | # 88 | # package target 89 | # 90 | 91 | set(CPACK_GENERATOR "ZIP") 92 | set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") 93 | set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") 94 | set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") 95 | include(CPack) 96 | -------------------------------------------------------------------------------- /micromesh_core/README.md: -------------------------------------------------------------------------------- 1 | # micromesh_core 2 | 3 | New core library for micromesh / micromap data processing. 4 | 5 | Other `micromesh_...` libraries will provide additional functionality and depend on it. 6 | 7 | ## Goals 8 | 9 | - "stable" C-style interface, just passing structs to API functions. 10 | - Utility inline functions allow C++ types. 11 | - Try to use simple data types / structs 12 | - No allocation management for user data 13 | - No serialization of user data 14 | - No additional dependencies 15 | 16 | ## Public Data Structures (`micromesh/micromesh_types.h`) 17 | 18 | Within are the most common data types used to communicate with the library. 19 | 20 | At the core lies the `micromesh::ArrayInfo` and its various "typed" variants (e.g. `micromesh::ArrayInfo_uint32`). 21 | This allows passing values and properties as pointer & stride combination so that the library can operate on 22 | data that can be embedded in the users' structs. 23 | 24 | **Note:** To avoid having a lot of types in the API the `ArrayInfo` stores a non-const `void*` data pointer. Which means 25 | some of the utility functions do a `const_cast`. When ArrayInfo structs are passed const, then the data pointer is used 26 | const only as well. 27 | 28 | The most commonly used interface will be the `micromesh::Micromap` struct, which contains information 29 | for a typical micromap using several `micromesh::ArrayInfo` for its properties. 30 | 31 | ``` c++ 32 | micromesh::Micromap micromap; 33 | 34 | // different ways to init arrays 35 | // manually construct / set fields 36 | micromap.values = {myvalues.data(), myvalues.size(), micromesh::Format:eR32_sfloat, sizeof(float)}; 37 | // use a typed array (_type suffix) constructor which implicitly sets ArrayInfo::format and `byteStride`. 38 | // In this example it would be to `Format:eR32_sfloat` and `byteStride = sizeof(float)` 39 | micromap.values = micromesh::ArrayInfo_float(myvalues.data(), myvalues.size()); 40 | 41 | // for already typed ones might just set data alone 42 | struct MyTriangle { 43 | uint16_t subdivLevel; 44 | uint16_t foo; 45 | }; 46 | std::vector triangles(100); 47 | // micromap.triangleSubdivLevels is ArrayInfo_uint16 48 | arraySetData(micromap.triangleSubdivLevels, &triangles[0].subdivLevel, triangles.size(), sizeof(Triangle)); 49 | 50 | // can also derive information from containers with .size(), .data() and value_type. 51 | std::vector myOffsets(100); 52 | // this assert that `sizeof(myOffsets's value_type)` matches sizeof(uint32_t) 53 | // as micromap.triangleValueIndexOffsets is ArrayInfo_uint32. 54 | arraySetDataVec(micromap.triangleValueIndexOffsets, myOffsets); 55 | 56 | ``` 57 | 58 | `micromesh::MeshTopology` is another frequently used interface to provide information about connectivity 59 | within a triangle mesh. It is, for example, used to ensure watertight values along triangle edges within micromaps. 60 | 61 | Other structs in this header only exist for documentation purposes to give information about how certain variable 62 | and struct field names are used in a standardized fashion. 63 | 64 | ## Utilities (`micromesh/micromesh_utils.h`) 65 | 66 | Several functions to work with the data structures or setup default interfaces. Some of these may not be required 67 | by users, given they target development of other micromesh libraries. For example, we do not recommend users to 68 | iterate data using the various `array` functions, given users bring their own data structures 69 | for storage. 70 | 71 | ## Operations (`micromesh/micromesh_operations.h`) 72 | 73 | - `micromesh::OpContext` implements some very simple multi-thread support to accelerate larger operations. A context is provided to all threaded operations. 74 | Any non-context functions are thread-safe. 75 | 76 | Most complex operations tend to use following pattern (replacing ``): 77 | 78 | - `struct micromesh::Op_input`: Interface struct for read-only inputs to an operation 79 | - `struct micromesh::Op_output`: Interface struct for written outputs of an operation 80 | - `Result micromesh::micromeshOpBegin(context, &input, &output)`: The **begin function** prepares the outputs and provides information about allocation sizes. Users should check the documentation which output fields are written and must be reacted upon (most commonly the `micromesh::ArrayInfo::count`). The begin function must be followed by corresponding end function or aborted via `micromeshOpContextAbort(context)`. 81 | - `Result micromesh::micromeshOpEnd(context, &output)`: The **end function** now assumes that all pointers in output are valid and properly sized to complete the operation. 82 | - `callbacks` passed to the operations must be thread-safe. They will be passed a `userData` pointer as well as a `threadIndex` that lies within the number of threads that the context is allowed to use. 83 | 84 | ## GPU Operation Interfaces (`micromesh/micromesh_gpu.h`) 85 | 86 | - Experimental design, work in progress 87 | - API agnostic interface that allows to run certain library operations on GPU. 88 | - All API calling must be done by the users, as well as uploads/downloads etc. 89 | - The library operations that do have GPU support, will expose functions to query detailed information 90 | about which shaders/pipelines and bindings are expected to be set and what kind of draws or dispatches to execute for each pass. 91 | 92 | ## Extended format types (`micromesh/micromesh_format_types.h`) 93 | 94 | For those interested in the use of `auto` etc. The various `micromesh::Format` enums can be mapped to structs and vice versa. 95 | This header is not used by the library itself, nor is it mandatory for the users. 96 | 97 | ## Tests (`tests/test_core.cpp`) 98 | 99 | [This file](tests/test_core.cpp) doesn't test all functions yet, but shows a bit how the API and utilities are used. 100 | 101 | ## Internals (`micromesh_internal/...`) 102 | 103 | These files are meant solely for micromesh library development and should 104 | never be included by users of this or other micromesh libraries. 105 | 106 | 107 | -------------------------------------------------------------------------------- /micromesh_core/include/micromesh/micromesh_api.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // NVIDIA CORPORATION and its licensors retain all intellectual property 5 | // and proprietary rights in and to this software, related documentation 6 | // and any modifications thereto. Any use, reproduction, disclosure or 7 | // distribution of this software and related documentation without an express 8 | // license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | // 10 | 11 | #pragma once 12 | 13 | #if defined(_MSC_VER) 14 | #define MICROMESH_CALL __fastcall 15 | #elif !defined(__aarch64__) && !defined(__x86_64) && (defined(__GNUC__) || defined(__clang__)) 16 | #define MICROMESH_CALL __attribute__((fastcall)) 17 | #else 18 | #define MICROMESH_CALL 19 | #endif 20 | 21 | // anticipate dll etc. 22 | 23 | #ifndef MICROMESH_API 24 | #define MICROMESH_API extern "C" 25 | #endif 26 | -------------------------------------------------------------------------------- /micromesh_core/include/micromesh/micromesh_gpu.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // NVIDIA CORPORATION and its licensors retain all intellectual property 5 | // and proprietary rights in and to this software, related documentation 6 | // and any modifications thereto. Any use, reproduction, disclosure or 7 | // distribution of this software and related documentation without an express 8 | // license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | // 10 | 11 | #pragma once 12 | 13 | #include "micromesh_types.h" 14 | 15 | namespace micromesh 16 | { 17 | namespace gpu 18 | { 19 | 20 | ////////////////////////////////////////////////////////////////////////// 21 | /// WARNING: the gpu interface is still subject to change 22 | 23 | enum ShaderType : uint32_t 24 | { 25 | eShaderCompute, 26 | eShaderMaxTypes, 27 | }; 28 | 29 | enum ShaderCodeType : uint32_t 30 | { 31 | eShaderCodeGLSL, 32 | eShaderCodeHLSL, 33 | eShaderCodeSPIRV, 34 | eShaderCodeDXIL, 35 | eShaderCodePTX, 36 | eShaderCodeInvalid, 37 | eShaderCodeMaxTypes = eShaderCodeInvalid, 38 | }; 39 | 40 | struct AvailableShaderCodeTypes 41 | { 42 | bool isAvailable[eShaderCodeMaxTypes]; 43 | }; 44 | 45 | struct ShaderCode 46 | { 47 | ShaderType type = eShaderMaxTypes; 48 | ShaderCodeType codeType = eShaderCodeMaxTypes; 49 | const void* data = nullptr; 50 | uint64_t size = 0; 51 | const char* entryName = nullptr; 52 | const char* fileName = nullptr; 53 | }; 54 | 55 | enum class PipelineType : uint32_t 56 | { 57 | eCompute, 58 | eGraphics, 59 | }; 60 | 61 | enum class DescriptorType : uint32_t 62 | { 63 | eInvalid, 64 | // 65 | eConstantBuffer, 66 | // byte address buffer in dx / ssbo in vk 67 | eBufferRead, 68 | // byte address buffer UAV in dx / ssbo in vk 69 | eBufferReadWrite, 70 | }; 71 | 72 | struct DescriptorRangeInfo 73 | { 74 | DescriptorType descriptorType = DescriptorType::eInvalid; 75 | uint32_t baseRegisterIndex = 0; 76 | uint32_t descriptorCount = 0; 77 | }; 78 | 79 | struct DescriptorSetAllocationInfo 80 | { 81 | // overall number of bindings required 82 | uint32_t setMaxCount = 0; 83 | 84 | uint32_t constantBufferMaxCount = 0; 85 | uint32_t bufferMaxCount = 0; 86 | uint32_t storageBufferMaxCount = 0; 87 | 88 | // uint32_t structuredBufferMaxCount = 0; 89 | // uint32_t storageStructuredBufferMaxCount = 0; 90 | // uint32_t staticSamplerMaxCount = 0; 91 | // uint32_t textureMaxCount = 0; 92 | // uint32_t storageTextureMaxCount = 0; 93 | }; 94 | 95 | struct ConstantBufferInfo 96 | { 97 | uint32_t registerIndex = 0; 98 | uint32_t maxDataSize = 0; 99 | }; 100 | 101 | struct BufferAllocInfo 102 | { 103 | uint64_t size; 104 | }; 105 | 106 | struct ImageAllocInfo 107 | { 108 | uint16_t width; 109 | uint16_t height; 110 | uint16_t depth; 111 | uint16_t mips; 112 | uint16_t layers; 113 | }; 114 | 115 | struct ResourceAllocInfo 116 | { 117 | DescriptorType type; 118 | union 119 | { 120 | BufferAllocInfo buffer; 121 | ImageAllocInfo image; 122 | }; 123 | }; 124 | 125 | struct PersistentResourceInfo 126 | { 127 | uint32_t scratchPersistentCount; 128 | ResourceAllocInfo* scratchPersistentAllocs; 129 | }; 130 | 131 | struct PipelineLayoutInfo 132 | { 133 | // sets (1< 298 | struct ResourceInfo 299 | { 300 | // operation specific enums 301 | union 302 | { 303 | TresourceEnum resourceEnum; 304 | uint32_t resourceIndex; 305 | }; 306 | // uint32_t staticSamplerIndex; 307 | }; 308 | 309 | template 310 | struct ReadResourceData 311 | { 312 | uint32_t resourceCount; 313 | ResourceInfo* resources; 314 | void** resourceDatas; 315 | uint64_t* resourceDataSizes; 316 | }; 317 | 318 | template 319 | struct CommandSequenceInfo 320 | { 321 | void* userData; 322 | PFN_generateGpuCommand pfnGenerateGpuCommand = nullptr; 323 | const ReadResourceData* previousReadData = nullptr; 324 | }; 325 | 326 | struct CmdBindPipeline 327 | { 328 | // operation specific pipeline 329 | uint32_t pipelineIndex; 330 | }; 331 | 332 | template 333 | struct CmdBindUserPipeline 334 | { 335 | // operation specific enums 336 | // we expect the user to do certain work 337 | union 338 | { 339 | TuserPipeEnum userPipelineEnum; 340 | uint32_t userPipelineIndex; 341 | }; 342 | }; 343 | 344 | template 345 | struct CmdBindResources 346 | { 347 | // operation specific pipeline layout 348 | uint32_t pipelineLayoutIndex; 349 | 350 | // flattened resources to match all ranges within 351 | // pipelineLayout 352 | uint32_t resourceCount; 353 | const ResourceInfo* resources; 354 | }; 355 | 356 | template 357 | struct CmdClearResources 358 | { 359 | // operation specific enums 360 | uint32_t resourceCount; 361 | const ResourceInfo* resources; 362 | uint32_t clearValue; 363 | }; 364 | 365 | template 366 | struct CmdReadResources 367 | { 368 | // operation specific enums 369 | uint32_t resourceCount; 370 | const ResourceInfo* resources; 371 | }; 372 | 373 | struct CmdGlobalConstants 374 | { 375 | uint32_t byteSize; 376 | const void* data; 377 | }; 378 | 379 | struct CmdLocalConstants 380 | { 381 | // operation specific pipeline 382 | uint32_t pipelineLayoutIndex; 383 | uint32_t byteSize; 384 | const void* data; 385 | }; 386 | 387 | enum BarrierBits : uint32_t 388 | { 389 | eBarrierNone, 390 | eBarrierBufferBit = 1 << 1, 391 | eBarrierImageBit = 1 << 2, 392 | eBarrierColorBit = 1 << 3, 393 | eBarrierDepthStencilBit = 1 << 4, 394 | eBarrierIndirectBit = 1 << 5, 395 | }; 396 | 397 | struct CmdBarrier 398 | { 399 | uint32_t readBits; 400 | uint32_t writeBits; 401 | }; 402 | 403 | struct CmdDispatch 404 | { 405 | uint32_t gridX; 406 | uint32_t gridY; 407 | uint32_t gridZ; 408 | }; 409 | 410 | template 411 | struct CmdDispatchIndirect 412 | { 413 | ResourceInfo indirectBuffer; 414 | uint64_t indirectBufferOffset; 415 | }; 416 | 417 | struct CmdBeginLabel 418 | { 419 | const char* labelName; 420 | }; 421 | 422 | } // namespace gpu 423 | 424 | } // namespace micromesh -------------------------------------------------------------------------------- /micromesh_core/include/micromesh_internal/micromesh_containers.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // NVIDIA CORPORATION and its licensors retain all intellectual property 5 | // and proprietary rights in and to this software, related documentation 6 | // and any modifications thereto. Any use, reproduction, disclosure or 7 | // distribution of this software and related documentation without an express 8 | // license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | // 10 | 11 | #pragma once 12 | 13 | // let's route all heap-based allocation data-structures through here 14 | // and for now just use STL 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace micromesh 21 | { 22 | namespace container 23 | { 24 | template 25 | using vector = std::vector; 26 | 27 | template 28 | using unordered_map = std::unordered_map; 29 | 30 | template 31 | using unordered_set = std::unordered_set; 32 | 33 | template 34 | void fill(vector& vec, T value) 35 | { 36 | for(size_t i = 0; i < vec.size(); i++) 37 | { 38 | vec[i] = value; 39 | } 40 | } 41 | 42 | } // namespace container 43 | } // namespace micromesh 44 | -------------------------------------------------------------------------------- /micromesh_core/include/micromesh_internal/micromesh_math.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // NVIDIA CORPORATION and its licensors retain all intellectual property 5 | // and proprietary rights in and to this software, related documentation 6 | // and any modifications thereto. Any use, reproduction, disclosure or 7 | // distribution of this software and related documentation without an express 8 | // license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | // 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace micromesh 16 | { 17 | namespace math 18 | { 19 | inline Vector_float_3 cross(Vector_float_3 a, Vector_float_3 b) 20 | { 21 | Vector_float_3 ret; 22 | ret.x = a.y * b.z - a.z * b.y; 23 | ret.y = a.z * b.x - a.x * b.z; 24 | ret.z = a.x * b.y - a.y * b.x; 25 | return ret; 26 | } 27 | 28 | inline float dot(Vector_float_3 a, Vector_float_3 b) 29 | { 30 | return a.x * b.x + a.y * b.y + a.z * b.z; 31 | } 32 | 33 | inline float length(Vector_float_3 v) 34 | { 35 | return sqrtf(dot(v, v)); 36 | } 37 | 38 | inline Vector_float_3 normalize(Vector_float_3 v) 39 | { 40 | float norm = sqrtf(dot(v, v)); 41 | if(norm > FLT_EPSILON) 42 | norm = 1.0f / norm; 43 | else 44 | norm = 0.0f; 45 | v.x *= norm; 46 | v.y *= norm; 47 | v.z *= norm; 48 | return v; 49 | } 50 | } // namespace math 51 | 52 | inline Vector_float_3 makeVector_float_3(Vector_float_2 in) 53 | { 54 | return {in.x, in.y, 0}; 55 | } 56 | 57 | inline Vector_float_4 makeVector_float_4(Vector_float_2 in) 58 | { 59 | return {in.x, in.y, 0, 0}; 60 | } 61 | 62 | inline Vector_float_4 makeVector_float_4(Vector_float_3 in) 63 | { 64 | return {in.x, in.y, in.z, 0}; 65 | } 66 | 67 | inline Vector_float_3 operator+(Vector_float_3 lhs, const Vector_float_3& rhs) 68 | { 69 | Vector_float_3 ret; 70 | ret.x = lhs.x + rhs.x; 71 | ret.y = lhs.y + rhs.y; 72 | ret.z = lhs.z + rhs.z; 73 | return ret; 74 | } 75 | 76 | inline Vector_float_3 operator-(Vector_float_3 lhs, const Vector_float_3& rhs) 77 | { 78 | Vector_float_3 ret; 79 | ret.x = lhs.x - rhs.x; 80 | ret.y = lhs.y - rhs.y; 81 | ret.z = lhs.z - rhs.z; 82 | return ret; 83 | } 84 | 85 | inline Vector_float_3 operator*(Vector_float_3 lhs, const Vector_float_3& rhs) 86 | { 87 | Vector_float_3 ret; 88 | ret.x = lhs.x * rhs.x; 89 | ret.y = lhs.y * rhs.y; 90 | ret.z = lhs.z * rhs.z; 91 | return ret; 92 | } 93 | 94 | inline Vector_float_3 operator/(Vector_float_3 lhs, const Vector_float_3& rhs) 95 | { 96 | Vector_float_3 ret; 97 | ret.x = lhs.x / rhs.x; 98 | ret.y = lhs.y / rhs.y; 99 | ret.z = lhs.z / rhs.z; 100 | return ret; 101 | } 102 | 103 | inline Vector_float_3 operator+(Vector_float_3 lhs, float rhs) 104 | { 105 | Vector_float_3 ret; 106 | ret.x = lhs.x + rhs; 107 | ret.y = lhs.y + rhs; 108 | ret.z = lhs.z + rhs; 109 | return ret; 110 | } 111 | 112 | inline Vector_float_3 operator-(Vector_float_3 lhs, float rhs) 113 | { 114 | Vector_float_3 ret; 115 | ret.x = lhs.x - rhs; 116 | ret.y = lhs.y - rhs; 117 | ret.z = lhs.z - rhs; 118 | return ret; 119 | } 120 | 121 | inline Vector_float_3 operator*(Vector_float_3 lhs, float rhs) 122 | { 123 | Vector_float_3 ret; 124 | ret.x = lhs.x * rhs; 125 | ret.y = lhs.y * rhs; 126 | ret.z = lhs.z * rhs; 127 | return ret; 128 | } 129 | 130 | inline Vector_float_3 operator/(Vector_float_3 lhs, float rhs) 131 | { 132 | Vector_float_3 ret; 133 | ret.x = lhs.x / rhs; 134 | ret.y = lhs.y / rhs; 135 | ret.z = lhs.z / rhs; 136 | return ret; 137 | } 138 | 139 | inline Vector_float_2 operator+(Vector_float_2 lhs, const Vector_float_2& rhs) 140 | { 141 | Vector_float_2 ret; 142 | ret.x = lhs.x + rhs.x; 143 | ret.y = lhs.y + rhs.y; 144 | return ret; 145 | } 146 | 147 | inline Vector_float_2 operator-(Vector_float_2 lhs, const Vector_float_2& rhs) 148 | { 149 | Vector_float_2 ret; 150 | ret.x = lhs.x - rhs.x; 151 | ret.y = lhs.y - rhs.y; 152 | return ret; 153 | } 154 | 155 | inline Vector_float_2 operator*(Vector_float_2 lhs, const Vector_float_2& rhs) 156 | { 157 | Vector_float_2 ret; 158 | ret.x = lhs.x * rhs.x; 159 | ret.y = lhs.y * rhs.y; 160 | return ret; 161 | } 162 | 163 | inline Vector_float_2 operator/(Vector_float_2 lhs, const Vector_float_2& rhs) 164 | { 165 | Vector_float_2 ret; 166 | ret.x = lhs.x / rhs.x; 167 | ret.y = lhs.y / rhs.y; 168 | return ret; 169 | } 170 | 171 | inline Vector_float_2 operator+(Vector_float_2 lhs, float rhs) 172 | { 173 | Vector_float_2 ret; 174 | ret.x = lhs.x + rhs; 175 | ret.y = lhs.y + rhs; 176 | return ret; 177 | } 178 | 179 | inline Vector_float_2 operator-(Vector_float_2 lhs, float rhs) 180 | { 181 | Vector_float_2 ret; 182 | ret.x = lhs.x - rhs; 183 | ret.y = lhs.y - rhs; 184 | return ret; 185 | } 186 | 187 | inline Vector_float_2 operator*(Vector_float_2 lhs, float rhs) 188 | { 189 | Vector_float_2 ret; 190 | ret.x = lhs.x * rhs; 191 | ret.y = lhs.y * rhs; 192 | return ret; 193 | } 194 | 195 | inline Vector_float_2 operator/(Vector_float_2 lhs, float rhs) 196 | { 197 | Vector_float_2 ret; 198 | ret.x = lhs.x / rhs; 199 | ret.y = lhs.y / rhs; 200 | return ret; 201 | } 202 | 203 | struct Vector_int32_2 204 | { 205 | int32_t x; 206 | int32_t y; 207 | 208 | inline int32_t& operator[](size_t idx) 209 | { 210 | assert(idx < 2); 211 | return (&x)[idx]; 212 | } 213 | inline const int32_t& operator[](size_t idx) const 214 | { 215 | assert(idx < 2); 216 | return (&x)[idx]; 217 | } 218 | }; 219 | 220 | 221 | inline Vector_int32_2 operator+(Vector_int32_2 lhs, const Vector_int32_2& rhs) 222 | { 223 | Vector_int32_2 ret; 224 | ret.x = lhs.x + rhs.x; 225 | ret.y = lhs.y + rhs.y; 226 | return ret; 227 | } 228 | 229 | inline Vector_int32_2 operator-(Vector_int32_2 lhs, const Vector_int32_2& rhs) 230 | { 231 | Vector_int32_2 ret; 232 | ret.x = lhs.x - rhs.x; 233 | ret.y = lhs.y - rhs.y; 234 | return ret; 235 | } 236 | 237 | inline Vector_int32_2 operator*(Vector_int32_2 lhs, const Vector_int32_2& rhs) 238 | { 239 | Vector_int32_2 ret; 240 | ret.x = lhs.x * rhs.x; 241 | ret.y = lhs.y * rhs.y; 242 | return ret; 243 | } 244 | 245 | inline Vector_int32_2 operator/(Vector_int32_2 lhs, const Vector_int32_2& rhs) 246 | { 247 | Vector_int32_2 ret; 248 | ret.x = lhs.x / rhs.x; 249 | ret.y = lhs.y / rhs.y; 250 | return ret; 251 | } 252 | 253 | inline Vector_int32_2 operator+(Vector_int32_2 lhs, int32_t rhs) 254 | { 255 | Vector_int32_2 ret; 256 | ret.x = lhs.x + rhs; 257 | ret.y = lhs.y + rhs; 258 | return ret; 259 | } 260 | 261 | inline Vector_int32_2 operator-(Vector_int32_2 lhs, int32_t rhs) 262 | { 263 | Vector_int32_2 ret; 264 | ret.x = lhs.x - rhs; 265 | ret.y = lhs.y - rhs; 266 | return ret; 267 | } 268 | 269 | inline Vector_int32_2 operator*(Vector_int32_2 lhs, int32_t rhs) 270 | { 271 | Vector_int32_2 ret; 272 | ret.x = lhs.x * rhs; 273 | ret.y = lhs.y * rhs; 274 | return ret; 275 | } 276 | 277 | inline Vector_int32_2 operator/(Vector_int32_2 lhs, int32_t rhs) 278 | { 279 | Vector_int32_2 ret; 280 | ret.x = lhs.x / rhs; 281 | ret.y = lhs.y / rhs; 282 | return ret; 283 | } 284 | 285 | } // namespace micromesh 286 | -------------------------------------------------------------------------------- /micromesh_core/src/context.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // NVIDIA CORPORATION and its licensors retain all intellectual property 5 | // and proprietary rights in and to this software, related documentation 6 | // and any modifications thereto. Any use, reproduction, disclosure or 7 | // distribution of this software and related documentation without an express 8 | // license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | // 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace micromesh 18 | { 19 | static_assert(sizeof(bool) == 1, "bool must be 1 byte in size"); 20 | 21 | // nvprintf2-like function, but for micromesh logging. 22 | void logPrintfSeverity(const MessageCallbackInfo* messageCallbackInfo, 23 | uint32_t threadIndex, 24 | const MessageSeverity severity, 25 | const char* fmt, 26 | std::va_list vlist) 27 | { 28 | if(!messageCallbackInfo || !messageCallbackInfo->pfnCallback) 29 | return; 30 | 31 | // Format the inputs into an std::string. 32 | // Copy vlist as it may be modified by vsnprintf. 33 | std::string formattedStr; 34 | std::va_list vlistCopy; 35 | va_copy(vlistCopy, vlist); 36 | const int charactersNeeded = std::vsnprintf(nullptr, 0, fmt, vlistCopy); 37 | va_end(vlistCopy); 38 | if((charactersNeeded < 0) || (size_t(charactersNeeded) > formattedStr.max_size() - 1)) 39 | { 40 | // Formatting error 41 | messageCallbackInfo->pfnCallback(MessageSeverity::eError, "Internal message formatting error.", threadIndex, 42 | messageCallbackInfo->userData); 43 | return; 44 | } 45 | 46 | // Resize the string; add 1, because vsnprintf doesn't count the 47 | // terminating null character. This can potentially throw an exception. 48 | try 49 | { 50 | formattedStr.resize(charactersNeeded + 1); 51 | } 52 | catch(...) 53 | { 54 | messageCallbackInfo->pfnCallback(MessageSeverity::eError, "Error resizing buffer to hold message.", threadIndex, 55 | messageCallbackInfo->userData); 56 | return; 57 | } 58 | 59 | // Format it and send it to the message callback! 60 | (void)std::vsnprintf(formattedStr.data(), formattedStr.size(), fmt, vlist); 61 | messageCallbackInfo->pfnCallback(severity, formattedStr.c_str(), threadIndex, messageCallbackInfo->userData); 62 | } 63 | 64 | // Logs a message through only the OpContext callback info. 65 | void messageLog(const MessageCallbackInfo* messageCallbackInfo, 66 | uint32_t threadIndex, 67 | const MessageSeverity severity, 68 | #ifdef _MSC_VER 69 | _Printf_format_string_ 70 | #endif 71 | const char* fmt, 72 | ...) 73 | { 74 | std::va_list vlist; 75 | va_start(vlist, fmt); 76 | logPrintfSeverity(messageCallbackInfo, threadIndex, severity, fmt, vlist); 77 | va_end(vlist); 78 | } 79 | 80 | // Logs a message through an OpContext. Checks that ctx != nullptr. 81 | void contextLog(const OpContext ctx, 82 | uint32_t threadIndex, 83 | const MessageSeverity severity, 84 | #ifdef _MSC_VER 85 | _Printf_format_string_ 86 | #endif 87 | const char* fmt, 88 | ...) 89 | { 90 | if(!ctx) 91 | return; 92 | std::va_list vlist; 93 | va_start(vlist, fmt); 94 | logPrintfSeverity(&ctx->m_messageCallbackInfo, threadIndex, severity, fmt, vlist); 95 | va_end(vlist); 96 | } 97 | 98 | MICROMESH_API Result MICROMESH_CALL micromeshCreateOpContext(const OpConfig* config, OpContext* pContext, const MessageCallbackInfo* messageCallback) 99 | { 100 | CHECK_NONNULLM(messageCallback, config); 101 | 102 | if(config->contextType != OpContextType::eImmediateAutomaticThreading) 103 | { 104 | MLOGE(messageCallback, "config->contextType must be eImmediateAutomaticThreading, but it was %u.", 105 | (uint32_t)config->contextType); 106 | return Result::eInvalidValue; 107 | } 108 | 109 | if(config->threadCount == 0) 110 | { 111 | MLOGE(messageCallback, "config->threadCount must be non-zero, but it was."); 112 | return Result::eInvalidValue; 113 | } 114 | 115 | *pContext = new OpContext_s(*config); 116 | 117 | // Set the default message callback by default if provided in case the 118 | // developer doesn't set it. It can be cleared by using 119 | // micromeshOpContextSetMessageCallback(context, {}). 120 | if(messageCallback) 121 | micromeshOpContextSetMessageCallback(*pContext, *messageCallback); 122 | 123 | return Result::eSuccess; 124 | } 125 | 126 | MICROMESH_API void MICROMESH_CALL micromeshDestroyOpContext(OpContext context) 127 | { 128 | if(context) 129 | { 130 | delete context; 131 | } 132 | } 133 | 134 | MICROMESH_API void MICROMESH_CALL micromeshOpContextAbort(OpContext context) 135 | { 136 | if(!context) 137 | return; 138 | 139 | context->resetSequence(); 140 | } 141 | 142 | MICROMESH_API void MICROMESH_CALL micromeshOpContextSetMessageCallback(OpContext context, const MessageCallbackInfo info) 143 | { 144 | if(!context) 145 | return; 146 | context->m_messageCallbackInfo = info; 147 | } 148 | 149 | MICROMESH_API MessageCallbackInfo MICROMESH_CALL micromeshOpContextGetMessageCallback(OpContext context) 150 | { 151 | if(!context) 152 | { 153 | return MessageCallbackInfo(); 154 | } 155 | return context->m_messageCallbackInfo; 156 | } 157 | 158 | MICROMESH_API OpConfig MICROMESH_CALL micromeshOpContextGetConfig(OpContext context) 159 | { 160 | if(!context) 161 | { 162 | return OpConfig(); 163 | } 164 | 165 | return context->m_config; 166 | } 167 | 168 | MICROMESH_API Result MICROMESH_CALL micromeshOpDistributeWork(OpContext ctx, const OpDistributeWork_input* input, uint64_t totalWorkload) 169 | { 170 | CHECK_CTX_NONNULL(ctx); 171 | CHECK_NONNULL(ctx, input); 172 | CHECK_CTX_BEGIN(ctx); 173 | 174 | if(totalWorkload) 175 | { 176 | if(input->pfnGenericSingleWorkload) 177 | { 178 | ctx->parallel_items(totalWorkload, input->pfnGenericSingleWorkload, input->userData, input->batchSize); 179 | } 180 | else if(input->pfnGenericRangeWorkload) 181 | { 182 | ctx->parallel_item_ranges(totalWorkload, input->pfnGenericRangeWorkload, input->userData, input->batchSize); 183 | } 184 | } 185 | 186 | return Result::eSuccess; 187 | } 188 | 189 | MICROMESH_API OpConfig MICROMESH_CALL micromeshGetDefaultOpConfig() 190 | { 191 | micromesh::OpConfig config; 192 | config.contextType = micromesh::OpContextType::eImmediateAutomaticThreading; 193 | config.threadCount = std::thread::hardware_concurrency(); 194 | return config; 195 | } 196 | 197 | } // namespace micromesh 198 | -------------------------------------------------------------------------------- /micromesh_displacement_compression/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | # Set the C/C++ specified in the projects as requirements 4 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 5 | set(CMAKE_C_STANDARD_REQUIRED ON) 6 | set(CMAKE_CXX_STANDARD 17) 7 | 8 | project(micromesh_displacement_compression VERSION 1.0.0) 9 | 10 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 11 | 12 | 13 | if (NOT TARGET micromesh_core AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../micromesh_core) 14 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../micromesh_core ${CMAKE_BINARY_DIR}/micromesh_core) 15 | endif() 16 | 17 | 18 | if(UNIX) 19 | add_definitions(-DLINUX) 20 | endif() 21 | 22 | # XXXX we might be able to force this by setting CMAKE_GENERATOR_PLATFORM ?? 23 | if(NOT (CMAKE_SIZEOF_VOID_P EQUAL 8)) 24 | message( FATAL_ERROR "64-bit builds only : reconfigure with -A x64" ) 25 | endif() 26 | 27 | set(CMAKE_DEBUG_POSTFIX "_d") 28 | set(CMAKE_RELWITHDEBINFO_POSTFIX "_rd") 29 | 30 | # 31 | # build 32 | # 33 | 34 | set(PUBLIC_HEADER_FILES 35 | include/micromesh/micromesh_displacement_compression.h 36 | ) 37 | install(FILES ${PUBLIC_HEADER_FILES} DESTINATION "include") 38 | 39 | set(INTERNAL_HEADER_FILES 40 | src/cpp_compatibility.h 41 | src/displacement_block_codec.h 42 | src/displacement_configs.h 43 | src/displacement_diagnostic_utils.h 44 | src/displacement_mesh_codec.h 45 | ) 46 | 47 | set(SOURCE_FILES 48 | src/cpp_compatibility.cpp 49 | src/displacement_block_codec.cpp 50 | src/displacement_compression.cpp 51 | src/displacement_configs.cpp 52 | src/displacement_mesh_codec.cpp 53 | ) 54 | 55 | source_group("public_include" FILES ${PUBLIC_HEADER_FILES}) 56 | source_group("internal_include" FILES ${INTERNAL_HEADER_FILES}) 57 | source_group("source" FILES ${SOURCE_FILES}) 58 | 59 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}") 60 | 61 | # static lib 62 | 63 | add_library(micromesh_displacement_compression STATIC ${SOURCE_FILES} ${PUBLIC_HEADER_FILES} ${INTERNAL_HEADER_FILES}) 64 | target_link_libraries(micromesh_displacement_compression micromesh_core) 65 | 66 | set_target_properties(micromesh_displacement_compression PROPERTIES FOLDER "micromesh_displacement_compression" 67 | POSITION_INDEPENDENT_CODE ON) 68 | 69 | target_include_directories(micromesh_displacement_compression PUBLIC 70 | $ $/include>) 71 | 72 | install(TARGETS micromesh_displacement_compression DESTINATION "lib" EXPORT "micromeshDisplacementCompressionTargets") 73 | 74 | # tests 75 | 76 | set(MICROMESH_DISPLACEMENT_COMPRESSION_BUILD_TESTS OFF CACHE BOOL "Build the unit tests for micromesh_displacement_compression") 77 | if(MICROMESH_DISPLACEMENT_COMPRESSION_BUILD_TESTS) 78 | set(TEST_FILES test/test_compression.cpp) 79 | source_group("tests" FILES ${TEST_FILES}) 80 | add_executable(micromesh_displacement_compression_test ${TEST_FILES}) 81 | target_link_libraries(micromesh_displacement_compression_test micromesh_displacement_compression micromesh_core) 82 | set_target_properties(micromesh_displacement_compression_test PROPERTIES FOLDER "micromesh_displacement_compression") 83 | endif() 84 | 85 | install(EXPORT "micromeshDisplacementCompressionTargets" FILE "micromeshDisplacementCompressionTargets.cmake" EXPORT_LINK_INTERFACE_LIBRARIES DESTINATION "cmake") 86 | 87 | # 88 | # package target 89 | # 90 | 91 | set(CPACK_GENERATOR "ZIP") 92 | set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") 93 | set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") 94 | set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") 95 | include(CPack) 96 | -------------------------------------------------------------------------------- /micromesh_displacement_compression/src/cpp_compatibility.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | #include "cpp_compatibility.h" 12 | 13 | #ifndef NVDISP_COMPAT_USE_CPP20 14 | 15 | #ifdef _MSC_VER // MSVC 16 | #include 17 | #endif 18 | 19 | namespace micromesh::compat 20 | { 21 | int countl_zero(unsigned int x) noexcept 22 | { 23 | #ifdef _MSC_VER // MSVC 24 | unsigned long result = 0; 25 | if(_BitScanReverse(&result, x) == 0) 26 | { 27 | // No set bits were found 28 | return 32; 29 | } 30 | return static_cast(31 - result); 31 | #else // GCC, clang 32 | if(x != 0) 33 | { 34 | return __builtin_clz(x); 35 | } 36 | return 32; 37 | #endif 38 | } 39 | 40 | int popcount(unsigned int x) noexcept 41 | { 42 | #ifdef _MSC_VER // MSVC 43 | return static_cast(__popcnt(x)); 44 | #else // GCC, clang 45 | return __builtin_popcount(x); 46 | #endif 47 | } 48 | 49 | } // namespace micromesh::compat 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /micromesh_displacement_compression/src/cpp_compatibility.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | // Several C++20-like standard library functions and types backported for use 12 | // in displacement_encoder and other projects. 13 | // Define NVDISP_COMPAT_USE_CPP20 to make micromesh::compat be an alias for std:: 14 | // instead. 15 | 16 | #pragma once 17 | 18 | #ifdef NVDISP_COMPAT_USE_CPP20 19 | 20 | #include 21 | #include 22 | namespace nv::displacement 23 | { 24 | namespace compat = std; 25 | } 26 | 27 | #else 28 | 29 | #include 30 | #include 31 | 32 | namespace micromesh::compat 33 | { 34 | // C++17-compatible version of std::span 35 | template 36 | class span 37 | { 38 | T* _data; 39 | size_t _size_in_elements; 40 | 41 | public: 42 | using iterator = T*; 43 | using const_iterator = const T*; 44 | 45 | span(T* start, size_t size_in_elements) 46 | : _data(start) 47 | , _size_in_elements(size_in_elements) 48 | { 49 | } 50 | 51 | template 52 | span(Container& c) 53 | { 54 | _data = c.data(); 55 | _size_in_elements = c.size(); 56 | } 57 | 58 | T* data() { return _data; } 59 | 60 | size_t size() { return _size_in_elements; } 61 | 62 | T& back() 63 | { 64 | assert(_size_in_elements > 0); 65 | return _data[_size_in_elements - 1]; 66 | } 67 | 68 | iterator begin() { return _data; } 69 | 70 | const_iterator cbegin() { return _data; } 71 | 72 | iterator end() { return _data + _size_in_elements; } 73 | 74 | const_iterator cend() { return _data + _size_in_elements; } 75 | 76 | T& operator[](size_t idx) const 77 | { 78 | assert(idx < _size_in_elements); 79 | return _data[idx]; 80 | } 81 | 82 | operator span() const { return span(_data, _size_in_elements); } 83 | }; 84 | 85 | // C++17-compatible version of std::countl_zero, which returns the number of 86 | // consecutive 0 bits in x, starting from the MSB. 87 | int countl_zero(unsigned int x) noexcept; 88 | 89 | // C++17-compatible version of std::popcount, which returns the number of 90 | // set 1 bits in x. 91 | int popcount(unsigned int x) noexcept; 92 | 93 | } // namespace micromesh::compat 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /micromesh_displacement_compression/src/displacement_block_codec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | // Internal interface for the block encoder and decoder. Ported from the 12 | // old displacement encoder. 13 | // The idea is that this exposes the interface the mesh encoder needs to be 14 | // efficient: 11-bit UNORM values in u-major layout, all API preconditions 15 | // already checked. Data transfer and conversion operations are left up to the 16 | // higher-level API functions. Ideally, these would be templated so we could 17 | // get good code generation. 18 | // This also exposes the functions that are unit-tested. 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | // Using __restrict here tells compilers that e.g. our input and output don't 25 | // alias, which might give some additional optimizations. 26 | // TODO: Test how this affects codegen/performance. 27 | #define DISPENC_RESTRICT __restrict 28 | 29 | namespace micromesh 30 | { 31 | namespace dispenc 32 | { 33 | uint16_t predict(uint16_t a, uint16_t b); 34 | 35 | // if numCorrectionBits is 0, returns 0. Otherwise, returns the integer v such that 36 | // * `(decoderWordMask & (prediction + (v << shift)))` is as close to `reference` as possible 37 | // * v is between -2^(numCorrectionBits-1) and 2^(numCorrectionBits-1)-1 38 | int16_t correct(uint16_t prediction, uint16_t reference, uint16_t shift, uint16_t numCorrectionBits); 39 | 40 | static constexpr uint32_t MAX_COMPRESSION_LEVELS = 5; 41 | 42 | enum class VertexType : uint8_t 43 | { 44 | eInterior = 0, 45 | eEdge0, 46 | eEdge1, 47 | eEdge2, 48 | eNUM_VERTEXTYPES 49 | }; 50 | static constexpr uint8_t NUM_VERTEXTYPES = (uint8_t)VertexType::eNUM_VERTEXTYPES; 51 | 52 | struct Shifts 53 | { 54 | struct Level 55 | { 56 | // Shift correction values by this amount prior to applying it as delta to prediction 57 | uint16_t vertex[NUM_VERTEXTYPES]{}; 58 | }; 59 | 60 | // levels[i] contains the shifts for subdiv level i+2; subdiv levels 0 61 | // (anchors) and 1 are always lossless, so don't need shifts 62 | Level levels[MAX_COMPRESSION_LEVELS - 1]{}; 63 | }; 64 | 65 | // Structure the encoder writes to. 66 | struct Intermediate 67 | { 68 | Shifts m_shifts; 69 | // These maps are umajor indexed. 70 | // 71 | // Decoded displacement map (i.e. what the decoder would output, although it's generated while encoding...) 72 | uint16_t* DISPENC_RESTRICT m_decoded = nullptr; 73 | // Correction terms (applied delta to predicted value from parent vertices) 74 | int16_t* DISPENC_RESTRICT m_corrections = nullptr; 75 | }; 76 | 77 | // NOTE: With the current design, for formats other than 78 | // eDispC1_r11_unorm_block, we have to go through blockEncodeAndPack directly. 79 | // This could be cleaner - my concern is about the performance impact of 80 | // packing when we discard the information for a less compressed format. 81 | void blockEncode(BlockFormatDispC1 fmtC1, const uint32_t subdivLevel, const uint16_t* DISPENC_RESTRICT reference, Intermediate& DISPENC_RESTRICT result); 82 | 83 | // Same note as blockEncode 84 | void blockPackData(BlockFormatDispC1 fmtC1, const uint32_t subdivLevel, const Intermediate& DISPENC_RESTRICT ie, void* DISPENC_RESTRICT encodedData); 85 | 86 | void blockDecode(Format family, 87 | BlockFormatDispC1 fmt, 88 | const uint32_t subdivLevel, 89 | const void* DISPENC_RESTRICT encodedData, 90 | uint16_t* DISPENC_RESTRICT decoded); 91 | 92 | } // namespace dispenc 93 | } // namespace micromesh -------------------------------------------------------------------------------- /micromesh_displacement_compression/src/displacement_configs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | #include 12 | #include 13 | #include "displacement_configs.h" 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | namespace micromesh 20 | { 21 | // CODE THAT SHOULD BE IN INTERNAL API 22 | // Compute 2 16-bit prefix XORs in a 32-bit register 23 | uint32_t prefixEor2(uint32_t x) 24 | { 25 | x ^= (x >> 1) & 0x7fff7fff; 26 | x ^= (x >> 2) & 0x3fff3fff; 27 | x ^= (x >> 4) & 0x0fff0fff; 28 | x ^= (x >> 8) & 0x00ff00ff; 29 | return x; 30 | } 31 | 32 | // Interleave 16 even bits from x with 16 odd bits from y 33 | uint32_t interleaveBits(uint32_t x, uint32_t y) 34 | { 35 | x = (x & 0xffff) | (y << 16); 36 | x = ((x >> 8) & 0x0000ff00) | ((x << 8) & 0x00ff0000) | (x & 0xff0000ff); 37 | x = ((x >> 4) & 0x00f000f0) | ((x << 4) & 0x0f000f00) | (x & 0xf00ff00f); 38 | x = ((x >> 2) & 0x0c0c0c0c) | ((x << 2) & 0x30303030) | (x & 0xc3c3c3c3); 39 | x = ((x >> 1) & 0x22222222) | ((x << 1) & 0x44444444) | (x & 0x99999999); 40 | return x; 41 | } 42 | 43 | // Compute index of a single triplet of compression coefficients from triangle's barycentric coordinates 44 | // Assumes u, v and w have only 16 valid bits in the lsbs (good for subdivision depths up to 64K segments per edge) 45 | // Triplets are ordered along the bird curve 46 | uint32_t getTripletIndex(uint32_t u, uint32_t v, uint32_t w, uint32_t level) 47 | { 48 | const uint32_t coordMask = ((1U << level) - 1); 49 | 50 | uint32_t b0 = ~(u ^ w) & coordMask; 51 | uint32_t t = (u ^ v) & b0; 52 | uint32_t c = (((u & v & w) | (~u & ~v & ~w)) & coordMask) << 16; 53 | uint32_t f = prefixEor2(t | c) ^ u; 54 | uint32_t b1 = (f & ~b0) | t; 55 | 56 | uint32_t dist = interleaveBits(b0, b1); 57 | 58 | f >>= 16; 59 | b0 <<= 1; 60 | return (dist + (b0 & ~f) - (b0 & f)) >> 3; 61 | } 62 | // END CODE THAT SHOULD BE IN INTERNAL API 63 | 64 | namespace dispenc 65 | { 66 | // Mechanism for only initializing the format table once - ideally we'd 67 | // generate this at compile-time. 68 | static bool s_configsInitialized = false; 69 | static std::mutex s_modifyingConfigs; 70 | std::array s_micromeshConfigs{}; 71 | 72 | void genMicromeshConfigTables(MicromeshConfig& microMeshConfig) 73 | { 74 | // Stamp subdivision level on base triangle 75 | const uint32_t maxSubdiv = microMeshConfig.subdiv; 76 | const uint32_t numSegments = microMeshConfig.numSegments; 77 | 78 | const uint32_t numVtxPerEdge = 1u + numSegments; 79 | const uint32_t numElems = subdivLevelGetVertexCount(maxSubdiv); 80 | 81 | // Allocate decoded displacement map (i.e. what the decoder would output, although it's generated while encoding..) 82 | std::unique_ptr decodedPtr = std::make_unique(numElems); 83 | auto decoded = decodedPtr.get(); 84 | 85 | { 86 | int32_t subdLevel = 0u; 87 | uint32_t ns = numSegments; 88 | 89 | // w, u and v anchors addresses 90 | const uint32_t anchors_addr[3] = { 91 | umajorUVtoLinear(0, 0, maxSubdiv), 92 | umajorUVtoLinear(ns, 0, maxSubdiv), 93 | umajorUVtoLinear(0, ns, maxSubdiv), 94 | }; 95 | for(uint32_t i = 0; i < 3; i++) 96 | { 97 | decoded[anchors_addr[i]] = subdLevel; 98 | } 99 | 100 | subdLevel++; // done with anchors, move to the next level.. 101 | 102 | // Just stamp the subdivision level 103 | while(ns > 1) 104 | { 105 | const uint32_t hns = ns >> 1; 106 | for(uint32_t u = 0; u < numVtxPerEdge; u += ns) 107 | { 108 | for(uint32_t v = hns; v < numVtxPerEdge - u; v += ns) 109 | { 110 | decoded[umajorUVtoLinear(u, v, maxSubdiv)] = subdLevel; 111 | decoded[umajorUVtoLinear(v, u, maxSubdiv)] = subdLevel; 112 | decoded[umajorUVtoLinear(u + hns, v, maxSubdiv)] = subdLevel; 113 | } 114 | } 115 | 116 | // Move to the next (finer) subdivision level 117 | ns = hns; 118 | subdLevel++; 119 | } 120 | } 121 | 122 | // Generate useful info about each level of subdivision 123 | 124 | struct SubdInfo 125 | { 126 | uint32_t segments; // number of segments per base face edge at this subd level 127 | uint32_t triangles; // total number of triangles at this subd level 128 | uint32_t edges; // total number of edges at this subd level 129 | uint32_t vertices; // total number of vertices at this subd level 130 | uint32_t corrections; // number of corrections needed *at* this subd level (incremental, not total) 131 | }; 132 | container::vector subdInfo; 133 | { 134 | SubdInfo info{}; 135 | info.segments = 1u; 136 | info.triangles = 1u; 137 | info.edges = 3u; 138 | info.vertices = 3u; 139 | info.corrections = 3u; 140 | subdInfo.push_back(info); 141 | for(uint32_t i = 0; i < maxSubdiv; i++) 142 | { 143 | const auto& p = subdInfo.back(); 144 | auto segments = 2 * p.segments; 145 | auto triangles = 4 * p.triangles; 146 | auto edges = 2 * p.edges + 3 * p.triangles; // each edge is split in 2, plus 3 new edges for each split triangle 147 | auto vertices = edges + p.vertices; // each edge generates a new vertex 148 | auto corrections = p.edges; 149 | subdInfo.push_back({segments, triangles, edges, vertices, corrections}); 150 | } 151 | } 152 | 153 | // Allocate mem for our table (stored in a triangular matrix) and also for a secondary table 154 | // that stores correction sizes, which is only used to later pack data. 155 | const uint32_t totalNumVertices = ((numVtxPerEdge * (1 + numVtxPerEdge) / 2)); 156 | const uint32_t tableSizeInBytes = sizeof(uint32_t) * totalNumVertices; 157 | microMeshConfig.bary2BlockAddrTable.resize(totalNumVertices); 158 | microMeshConfig.correctionSizeInBits.resize(totalNumVertices); 159 | microMeshConfig.subdLevelBitAddr.resize(1u + maxSubdiv); 160 | 161 | // Initialize per-subdivision-level bit address mini table 162 | uint32_t bitsUsedSoFar = 0u; 163 | for(uint32_t subdLevel = 0; subdLevel <= maxSubdiv; subdLevel++) 164 | { 165 | microMeshConfig.subdLevelBitAddr[subdLevel] = bitsUsedSoFar; 166 | bitsUsedSoFar += microMeshConfig.numCorrBits[subdLevel] * subdInfo[subdLevel].corrections; 167 | } 168 | auto bitAddr = microMeshConfig.subdLevelBitAddr; 169 | 170 | auto tableData = microMeshConfig.bary2BlockAddrTable.data(); 171 | auto corrSizeInBitsData = microMeshConfig.correctionSizeInBits.data(); 172 | memset((void*)tableData, 0xcdu, tableSizeInBytes); 173 | memset((void*)corrSizeInBitsData, 0xcdu, tableSizeInBytes); 174 | 175 | for(uint32_t u = 0; u < numVtxPerEdge; u++) 176 | { 177 | // We only fill the upper triangular half of table 178 | for(uint32_t v = 0; v < numVtxPerEdge - u; v++) 179 | { 180 | // TODO: These are the same now! 181 | const uint32_t addressinTexture = umajorUVtoLinear(u, v, maxSubdiv); 182 | const uint32_t addressInTable = umajorUVtoLinear(u, v, maxSubdiv); 183 | const uint32_t subdLevel = (uint32_t)decoded[addressinTexture]; 184 | const uint32_t numCorrBits = microMeshConfig.numCorrBits[subdLevel]; 185 | const uint32_t shift = maxSubdiv - subdLevel; 186 | 187 | const uint32_t uu = u >> shift; 188 | const uint32_t vv = v >> shift; 189 | 190 | 191 | const uint32_t numSubdSegments = 1u << subdLevel; 192 | const uint32_t ww = numSubdSegments - uu - vv; 193 | uint32_t addressinBlock = getTripletIndex(uu, vv, ww, subdLevel); 194 | addressinBlock *= 3; 195 | 196 | const uint32_t r_u = uu & 0x1u; 197 | const uint32_t r_v = vv & 0x1u; 198 | 199 | // The anchors of the base triangle are handled as a special case 200 | if(subdLevel == 0) 201 | { 202 | if(uu == 1u && vv == 0u) 203 | addressinBlock += 1; 204 | if(uu == 0u && vv == 1u) 205 | addressinBlock += 2; 206 | } 207 | else 208 | { 209 | if(r_u == 1 && r_v == 1) 210 | addressinBlock += 1; 211 | if(r_u == 1 && r_v == 0) 212 | addressinBlock += 2; 213 | } 214 | 215 | addressinBlock *= numCorrBits; 216 | addressinBlock += microMeshConfig.subdLevelBitAddr[subdLevel]; 217 | 218 | // Read the level of subdvision for this vertex and update table 219 | 220 | tableData[addressInTable] = addressinBlock; 221 | corrSizeInBitsData[addressInTable] = numCorrBits; 222 | 223 | // Now update the number of bits we've written so far for this subd level 224 | bitAddr[subdLevel] += numCorrBits; 225 | } 226 | } 227 | 228 | // Correctness check 229 | for(uint32_t subdLevel = 0; subdLevel < maxSubdiv; subdLevel++) 230 | { 231 | // If test is not passed then we miscounted the number of bits required to store 232 | // corrections for each subdivision level OR we did not find all the corrections 233 | // that belong to that level. 234 | assert(bitAddr[subdLevel] == microMeshConfig.subdLevelBitAddr[subdLevel + 1] && "Table is not consistent."); 235 | } 236 | } 237 | 238 | void initMicromeshConfigs() 239 | { 240 | // Don't reinitialize if we've already initialized it: 241 | if(s_configsInitialized) 242 | { 243 | return; 244 | } 245 | 246 | // Prevent multiple threads from modifying the vector at the same time 247 | std::scoped_lock lock(s_modifyingConfigs); 248 | 249 | if(s_configsInitialized) 250 | { 251 | return; // Two threads arrived at s_modifyingConfigs and we were the second 252 | } 253 | 254 | const uint32_t largeBlockSizeInBits = 1024; 255 | const uint32_t smallBlockSizeInBits = largeBlockSizeInBits / 2; 256 | 257 | // 1b/triangle 258 | MicromeshConfig& lvl5 = s_micromeshConfigs[blockFormatDispC1ToConfigIdx(BlockFormatDispC1::eR11_unorm_lvl5_pack1024)]; 259 | lvl5.subdiv = 5; 260 | lvl5.numSegments = 32u; 261 | lvl5.blockSizeInBits = largeBlockSizeInBits; 262 | lvl5.numCorrBits = {11u, 11u, 8u, 4u, 2u, 1u}; 263 | lvl5.fmt = BlockFormatDispC1::eR11_unorm_lvl5_pack1024; 264 | 265 | // 4b/triangle 266 | MicromeshConfig& lvl4 = s_micromeshConfigs[blockFormatDispC1ToConfigIdx(BlockFormatDispC1::eR11_unorm_lvl4_pack1024)]; 267 | lvl4.subdiv = 4; 268 | lvl4.numSegments = 16u; 269 | lvl4.blockSizeInBits = largeBlockSizeInBits; 270 | lvl4.numCorrBits = {11u, 11u, 11u, 10u, 5u}; 271 | lvl4.fmt = BlockFormatDispC1::eR11_unorm_lvl4_pack1024; 272 | 273 | // 8b/triangle --> special configuration for lossless encoding 274 | MicromeshConfig& lvl3 = s_micromeshConfigs[blockFormatDispC1ToConfigIdx(BlockFormatDispC1::eR11_unorm_lvl3_pack512)]; 275 | lvl3.subdiv = 3; 276 | lvl3.numSegments = 8u; 277 | lvl3.blockSizeInBits = smallBlockSizeInBits; 278 | lvl3.numCorrBits = {11u, 11u, 11u, 11u}; 279 | lvl3.fmt = BlockFormatDispC1::eR11_unorm_lvl3_pack512; 280 | 281 | for(MicromeshConfig& config : s_micromeshConfigs) 282 | { 283 | genMicromeshConfigTables(config); 284 | } 285 | 286 | s_configsInitialized = true; 287 | } 288 | 289 | } // namespace dispenc 290 | } // namespace micromesh 291 | -------------------------------------------------------------------------------- /micromesh_displacement_compression/src/displacement_configs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | // Internal interface for low-level details about block formats - such as where 12 | // the individual correction sections are, the bit widths of different levels, 13 | // and so on. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | namespace micromesh 22 | { 23 | namespace dispenc 24 | { 25 | static const uint32_t config_maxSubdLevel = 13u; 26 | static const uint32_t config_decoderWordSizeInBits = 11u; 27 | 28 | // Configuration-specific data describing the full configuration. Const during 29 | // encoding. 30 | struct MicromeshConfig 31 | { 32 | uint32_t subdiv{}; 33 | uint32_t numSegments{}; 34 | uint32_t blockSizeInBits{}; 35 | BlockFormatDispC1 fmt{}; 36 | container::vector numCorrBits; 37 | container::vector bary2BlockAddrTable; // umajor indexed 38 | container::vector correctionSizeInBits; // umajor indexed 39 | container::vector subdLevelBitAddr; // bitpos where each subdiv level starts 40 | 41 | inline bool hasFlatEncoding() const { return numSegments == 8 && blockSizeInBits == 512; } 42 | }; 43 | 44 | static constexpr uint16_t NUM_C1_BLOCK_FORMATS = 3; 45 | static_assert(uint16_t(BlockFormatDispC1::eInvalid) == 0, "Assumption on BlockFormatDispC1 layout broke!"); 46 | static_assert(uint16_t(BlockFormatDispC1::eR11_unorm_lvl5_pack1024) == 3, "Assumption on BlockFormatDispC1 layout broke!"); 47 | inline uint16_t blockFormatDispC1ToConfigIdx(const BlockFormatDispC1& fmt){ 48 | return uint16_t(fmt) - 1; 49 | } 50 | 51 | // Table of MicromeshConfig data so that we only have to generate them once 52 | extern std::array s_micromeshConfigs; 53 | 54 | void initMicromeshConfigs(); 55 | 56 | const inline MicromeshConfig& getMicromeshConfig(const BlockFormatDispC1& fmt) 57 | { 58 | initMicromeshConfigs(); 59 | return s_micromeshConfigs[blockFormatDispC1ToConfigIdx(fmt)]; 60 | } 61 | 62 | } // namespace dispenc 63 | } // namespace micromesh 64 | -------------------------------------------------------------------------------- /micromesh_displacement_compression/src/displacement_diagnostic_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | // This file includes useful functions for debugging and printing information 12 | // about internal displacement encoder structures. It's mainly used for the 13 | // tests, but it can also be included in the library to debug issues (and then 14 | // should be removed once debugging is complete). 15 | 16 | #pragma once 17 | 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | template 24 | void printBitsIfVerbose(const micromesh::container::vector data) 25 | { 26 | #ifdef DIAG_VERBOSE 27 | printf("Values (most significant byte and bit first):\n"); 28 | const int64_t tBits = int64_t(8 * sizeof(T)); 29 | for(int64_t i = int64_t(data.size()) - 1; i >= 0; i--) 30 | { 31 | const T& v = data[i]; 32 | for(int64_t bit = tBits - 1; bit >= 0; bit--) 33 | { 34 | printf("%c", (size_t(v) & (1ULL << bit)) ? '1' : '0'); 35 | } 36 | // Print index and line break every 4 Ts 37 | if(i % 4 == 0) 38 | { 39 | printf(" (%zu)\n", i * tBits); 40 | } 41 | else 42 | { 43 | printf(" "); 44 | } 45 | } 46 | #endif 47 | } 48 | 49 | void printBlockArrayIfVerbose(const uint16_t* data, const uint32_t subdivLevel, micromesh::PFN_getMicroVertexIndex getMicroVertexIndex = nullptr) 50 | { 51 | #ifdef DIAG_VERBOSE 52 | const uint32_t numSegments = 1u << subdivLevel; 53 | printf("Block values (u down, v to the right):\n"); 54 | for(uint32_t u = 0; u < numSegments + 1; u++) 55 | { 56 | for(uint32_t v = 0; v < numSegments + 1; v++) 57 | { 58 | if(u + v < numSegments + 1) 59 | { 60 | uint32_t index = 0; 61 | if(getMicroVertexIndex) 62 | { 63 | index = getMicroVertexIndex(u, v, subdivLevel, nullptr); 64 | } 65 | else 66 | { 67 | index = micromesh::umajorUVtoLinear(u, v, subdivLevel); 68 | } 69 | printf("%-4u ", data[index]); 70 | } 71 | } 72 | printf("\n"); 73 | } 74 | #endif 75 | } 76 | 77 | void printBlockArrayIfVerbose(const micromesh::container::vector data, const uint32_t subdivLevel) 78 | { 79 | assert(data.size() == micromesh::subdivLevelGetVertexCount(subdivLevel)); 80 | printBlockArrayIfVerbose(data.data(), subdivLevel); 81 | } -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | # Set the C/C++ specified in the projects as requirements 4 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 5 | set(CMAKE_C_STANDARD_REQUIRED ON) 6 | set(CMAKE_CXX_STANDARD 17) 7 | 8 | project(micromesh_displacement_remeshing VERSION 1.0.0) 9 | 10 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 11 | 12 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ) 13 | 14 | include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/vulkan.cmake) 15 | 16 | find_path(GLM_INCLUDE_DIR 17 | NAMES glm/glm.hpp 18 | HINTS ${GLM_LOCATION} $ENV{GLM_LOCATION} ${VK_SDK_PATH}/include ${VULKANSDK_INCLUDE_DIR} 19 | ) 20 | if(NOT GLM_INCLUDE_DIR) 21 | message(FATAL_ERROR "GLM not found. Aborting. Set `GLM_INCLUDE_DIR` or include `GLM` with the Vulkan SDK install") 22 | endif() 23 | 24 | if (NOT TARGET micromesh_core AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../micromesh_core) 25 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../micromesh_core ${CMAKE_BINARY_DIR}/micromesh_core) 26 | endif() 27 | 28 | 29 | if(UNIX) 30 | add_definitions(-DLINUX) 31 | endif() 32 | 33 | # XXXX we might be able to force this by setting CMAKE_GENERATOR_PLATFORM ?? 34 | if(NOT (CMAKE_SIZEOF_VOID_P EQUAL 8)) 35 | message( FATAL_ERROR "64-bit builds only : reconfigure with -A x64" ) 36 | endif() 37 | 38 | set(CMAKE_DEBUG_POSTFIX "_d") 39 | set(CMAKE_RELWITHDEBINFO_POSTFIX "_rd") 40 | 41 | # 42 | # build 43 | # 44 | 45 | set(PUBLIC_HEADER_FILES 46 | include/micromesh/micromesh_displacement_remeshing.h 47 | ) 48 | install(FILES ${PUBLIC_HEADER_FILES} DESTINATION "include") 49 | 50 | set(INTERNAL_HEADER_FILES 51 | 52 | ) 53 | 54 | _add_package_VulkanSDK() 55 | 56 | set(SOURCE_FILES 57 | src/remeshing_cpu.cpp 58 | src/remeshing_gpu.cpp 59 | src/remeshing_internal.h 60 | ) 61 | 62 | source_group("public_include" FILES ${PUBLIC_HEADER_FILES}) 63 | source_group("internal_include" FILES ${INTERNAL_HEADER_FILES}) 64 | source_group("source" FILES ${SOURCE_FILES}) 65 | 66 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" "${GLM_INCLUDE_DIR}") 67 | 68 | #---------------------------------- 69 | # Adding shader files 70 | set(SHD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/shaders) 71 | file(GLOB SHD_HDR ${SHD_DIR}/*.h) 72 | file(GLOB SHD_SRC ${SHD_DIR}/*.rchit ${SHD_DIR}/*.rmiss ${SHD_DIR}/*.frag ${SHD_DIR}/*.rahit ${SHD_DIR}/*.rgen ${SHD_DIR}/*.vert ${SHD_DIR}/*.comp ${SHD_DIR}/*.glsl) 73 | 74 | # Compiling shaders to Spir-V header 75 | compile_glsl( 76 | SOURCE_FILES ${SHD_SRC} 77 | HEADER_FILES ${SHD_HDR} 78 | DST "${CMAKE_CURRENT_SOURCE_DIR}/_autogen" 79 | VULKAN_TARGET "vulkan1.2" 80 | HEADER ON 81 | DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES} 82 | FLAGS "-I${SHD_DIR}" -g 83 | ) 84 | #target_sources(${PROJECT_NAME} PRIVATE ${SHD_SRC} ${SHD_HDR}) 85 | source_group("shaders" FILES ${SHD_SRC} ${SHD_HDR}) 86 | 87 | 88 | #---------------------------------- 89 | 90 | 91 | 92 | # static lib 93 | 94 | add_library(micromesh_displacement_remeshing STATIC ${SOURCE_FILES} ${PUBLIC_HEADER_FILES} ${INTERNAL_HEADER_FILES} ${SHD_SRC} ${SHD_HDR}) 95 | target_link_libraries(micromesh_displacement_remeshing micromesh_core) 96 | 97 | set_target_properties(micromesh_displacement_remeshing PROPERTIES FOLDER "micromesh_displacement_remeshing") 98 | 99 | target_include_directories(micromesh_displacement_remeshing PUBLIC 100 | $ $/include>) 101 | 102 | install(TARGETS micromesh_displacement_remeshing DESTINATION "lib" EXPORT "micromeshDisplacementRemeshingTargets") 103 | 104 | # tests 105 | 106 | set(MICROMESH_DISPLACEMENT_REMESHING_BUILD_TESTS OFF CACHE BOOL "Build the unit tests for micromesh_displacement_remeshing") 107 | if(MICROMESH_DISPLACEMENT_REMESHING_BUILD_TESTS) 108 | set(TEST_FILES test/test_remeshing.cpp) 109 | source_group("tests" FILES ${TEST_FILES}) 110 | add_executable(micromesh_displacement_remeshing_test ${TEST_FILES}) 111 | target_link_libraries(micromesh_displacement_remeshing_test micromesh_displacement_remeshing micromesh_core) 112 | set_target_properties(micromesh_displacement_remeshing_test PROPERTIES FOLDER "micromesh_displacement_remeshing") 113 | endif() 114 | 115 | install(EXPORT "micromeshDisplacementRemeshingTargets" FILE "micromeshDisplacementRemeshingTargets.cmake" EXPORT_LINK_INTERFACE_LIBRARIES DESTINATION "cmake") 116 | 117 | # 118 | # package target 119 | # 120 | 121 | set(CPACK_GENERATOR "ZIP") 122 | set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") 123 | set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") 124 | set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") 125 | include(CPack) 126 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/README.md: -------------------------------------------------------------------------------- 1 | # Micromesh Displacement Remeshing 2 | 3 | Optimizes an input mesh for micromesh displacement use. Outputs new (typical lower resolution) mesh with per-vertex displacement direction vectors and per-vertex direction bounds as well as per-triangle subdivision levels. 4 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/cmake/FindVulkanSDK.cmake: -------------------------------------------------------------------------------- 1 | # Try to find VulkanSDK project dll/so and headers 2 | # 3 | 4 | # outputs 5 | unset(VULKAN_LIB CACHE) 6 | unset(VULKANSDK_FOUND CACHE) 7 | unset(VULKANSDK_INCLUDE_DIR CACHE) 8 | unset(VULKANSDK_SHADERC_LIB CACHE) 9 | unset(VULKANSDK_SHADERC_DLL CACHE) 10 | unset(GLSLANGVALIDATOR) 11 | unset(GLSLC) 12 | 13 | set(VULKAN_BUILD_DEPENDENCIES OFF CACHE BOOL "Create dependies on GLSL files") 14 | 15 | # ------------------------------------------------------------------- 16 | macro ( folder_list result curdir ) 17 | FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) 18 | SET(dirlist "") 19 | foreach ( child ${children}) 20 | IF(IS_DIRECTORY ${curdir}/${child}) 21 | LIST(APPEND dirlist ${child}) 22 | ENDIF() 23 | ENDFOREACH() 24 | SET(${result} ${dirlist}) 25 | ENDMACRO() 26 | # ------------------------------------------------------------------- 27 | macro(_check_version_on_folder checkdir bestver bestvernumeric bestpath) 28 | string ( REGEX MATCH ".*([0-9]+)\\.([0-9]+)\\.([0-9]+)\\.([0-9]+)" result "${checkdir}" ) 29 | if ( "${result}" STREQUAL "${checkdir}" ) 30 | # found a path with versioning 31 | SET ( ver "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}.${CMAKE_MATCH_4}" ) 32 | SET ( vernumeric "${CMAKE_MATCH_1}${CMAKE_MATCH_2}${CMAKE_MATCH_3}${CMAKE_MATCH_4}" ) 33 | if ( ver VERSION_GREATER bestver ) 34 | SET ( bestver ${ver} ) 35 | SET ( bestvernumeric ${vernumeric} ) 36 | SET ( bestpath "${basedir}/${checkdir}" ) 37 | endif () 38 | endif() 39 | endmacro() 40 | # ------------------------------------------------------------------- 41 | macro(_find_version_path targetVersion targetPath searchList ) 42 | unset ( targetVersion ) 43 | unset ( targetPath ) 44 | SET ( bestver "0.0.0.0" ) 45 | SET ( bestpath "" ) 46 | SET ( bestvernumeric "0000" ) 47 | 48 | foreach ( basedir ${searchList} ) 49 | folder_list ( dirList ${basedir} ) 50 | foreach ( checkdir ${dirList} ) 51 | _check_version_on_folder(${checkdir} bestver bestvernumeric bestpath) 52 | endforeach () 53 | endforeach () 54 | SET ( ${targetVersion} "${bestver}" ) 55 | SET ( ${targetPath} "${bestpath}" ) 56 | endmacro() 57 | # ------------------------------------------------------------------- 58 | macro(_find_files targetVar incDir dllName dllName64 folder) 59 | unset ( targetVar ) 60 | unset ( fileList ) 61 | if(ARCH STREQUAL "x86") 62 | file(GLOB fileList "${${incDir}}/../${folder}${dllName}") 63 | list(LENGTH fileList NUMLIST) 64 | if(NUMLIST EQUAL 0) 65 | file(GLOB fileList "${${incDir}}/${folder}${dllName}") 66 | endif() 67 | else() 68 | file(GLOB fileList "${${incDir}}/../${folder}${dllName64}") 69 | list(LENGTH fileList NUMLIST) 70 | if(NUMLIST EQUAL 0) 71 | file(GLOB fileList "${${incDir}}/${folder}${dllName64}") 72 | endif() 73 | endif() 74 | list(LENGTH fileList NUMLIST) 75 | if(NUMLIST EQUAL 0) 76 | message(STATUS "MISSING: unable to find ${targetVar} files (${folder}${dllName}, ${folder}${dllName64})" ) 77 | set (${targetVar} "NOTFOUND") 78 | endif() 79 | list(APPEND ${targetVar} ${fileList} ) 80 | 81 | # message ( "File list: ${${targetVar}}" ) #-- debugging 82 | endmacro() 83 | # ------------------------------------------------------------------- 84 | # Locate VULKANSDK by version 85 | STRING(REGEX REPLACE "\\\\" "/" VULKANSDK_LOCATION "${VULKANSDK_LOCATION}") 86 | 87 | set ( SEARCH_PATHS 88 | "${VULKANSDK_LOCATION}" # this could be set to C:\VulkanSDK Best version will be taken 89 | ) 90 | 91 | if (WIN32) 92 | _find_version_path ( VULKANSDK_VERSION VULKANSDK_ROOT_DIR "${SEARCH_PATHS}" ) 93 | endif() 94 | if (UNIX) 95 | message ( STATUS "VulkanSDK search paths: ${SEARCH_PATHS}") 96 | message ( STATUS "\$VULKAN_SDK: $ENV{VULKAN_SDK}") 97 | #_find_version_path ( VULKANSDK_VERSION VULKANSDK_ROOT_DIR "${SEARCH_PATHS}" ) 98 | 99 | find_path(VULKANSDK_ROOT_DIR NAMES vulkan/vulkan.h HINTS "$ENV{VULKAN_SDK}/include") 100 | find_library(VULKAN_LIB NAMES vulkan HINTS "$ENV{VULKAN_SDK}/lib") 101 | 102 | Message(STATUS "Vulkan Include : ${VULKANSDK_ROOT_DIR}") 103 | Message(STATUS "Vulkan Library : ${VULKAN_LIB}") 104 | endif() 105 | # 106 | #------- no overridden place to look at so let's use VK_SDK_PATH 107 | # VK_SDK_PATH directly points to the dedicated version 108 | # put after the search if one wanted to override this default VK_SDK_PATH 109 | if (NOT VULKANSDK_ROOT_DIR ) 110 | STRING(REGEX REPLACE "\\\\" "/" VK_SDK_PATH "$ENV{VK_SDK_PATH}") 111 | find_path( VULKANSDK_INCLUDE_DIR vulkan/vulkan.h ${VK_SDK_PATH}/include ) 112 | if ( VULKANSDK_INCLUDE_DIR ) 113 | set (VULKANSDK_ROOT_DIR ${VK_SDK_PATH} ) 114 | SET ( bestver "0.0.0.0" ) 115 | SET ( bestpath "" ) 116 | SET ( bestvernumeric "0000" ) 117 | _check_version_on_folder(${VULKANSDK_ROOT_DIR} bestver bestvernumeric bestpath) 118 | SET ( VULKANSDK_VERSION "${bestver}" ) 119 | endif() 120 | endif() 121 | 122 | 123 | if (VULKANSDK_ROOT_DIR) 124 | #-------- Locate Vulkan and ShaderC libraries, and the glslangValidator executable. 125 | 126 | if (WIN32) 127 | _find_files( VULKAN_LIB VULKANSDK_ROOT_DIR "Lib/vulkan-1.lib" "Lib/vulkan-1.lib" "") 128 | _find_files( VULKANSDK_SHADERC_LIB VULKANSDK_ROOT_DIR "Lib/shaderc_shared.lib" "Lib/shaderc_shared.lib" "") 129 | _find_files( VULKANSDK_SHADERC_DLL VULKANSDK_ROOT_DIR "Bin/shaderc_shared.dll" "Bin/shaderc_shared.dll" "") 130 | _find_files( GLSLANGVALIDATOR VULKANSDK_ROOT_DIR "bin/glslangValidator.exe" "bin/glslangValidator.exe" "") 131 | _find_files( GLSLC VULKANSDK_ROOT_DIR "" "bin/glslc.exe" "") 132 | 133 | 134 | endif(WIN32) 135 | 136 | if (UNIX) 137 | unset(VULKAN_LIB) 138 | find_library(VULKAN_LIB NAMES vulkan HINTS "$ENV{VULKAN_SDK}/lib") 139 | get_filename_component(VULKAN_LIB_DIR ${VULKAN_LIB} DIRECTORY) 140 | find_library(VULKANSDK_SHADERC_LIB "libshaderc_combined.a" HINTS ${VULKAN_LIB_DIR}) 141 | find_file(GLSLANGVALIDATOR VULKANSDK_ROOT_DIR "glslangValidator" HINTS ${VULKANSDK_ROOT_DIR}"../bin/glslangValidator") 142 | find_file(GLSLC VULKANSDK_ROOT_DIR "glslc" HINTS ${VULKANSDK_ROOT_DIR}"../bin/glslc") 143 | 144 | # Message(STATUS "Vulkan Lib Dir : ${VULKAN_LIB_DIR}") 145 | # Message(STATUS "Vulkan Include : ${VULKANSDK_ROOT_DIR}") 146 | # Message(STATUS "Vulkan Library : ${VULKAN_LIB}") 147 | # Message(STATUS "Vulkan ShaderC Library : ${VULKANSDK_SHADERC_LIB}") 148 | 149 | # if (VULKANSDK_ROOT_DIR) 150 | # Message("Using system for vulkan sdk.") 151 | # endif() 152 | 153 | endif(UNIX) 154 | 155 | if(VULKAN_LIB) 156 | set( VULKANSDK_FOUND "YES" ) 157 | endif(VULKAN_LIB) 158 | else(VULKANSDK_ROOT_DIR) 159 | 160 | message(WARNING " 161 | Vulkan SDK not found. 162 | Most likely, this means that the environment variable VK_SDK_PATH should be set directly to the 163 | right version to use (e.g. C:\\VulkanSDK\\1.0.1.1; this contains the Vulkan SDK's Bin and Lib folders). 164 | Another option is that you can set the CMake VULKANSDK_LOCATION variable to the folder where this script should 165 | search for Vulkan SDK versions (e.g. C:\\VulkanSDK)." 166 | ) 167 | 168 | endif(VULKANSDK_ROOT_DIR) 169 | 170 | include(FindPackageHandleStandardArgs) 171 | 172 | SET(VULKAN_LIB ${VULKAN_LIB} CACHE PATH "path") 173 | message(STATUS "VULKANSDK_ROOT_DIR = ${VULKANSDK_ROOT_DIR}") 174 | if(EXISTS "${VULKANSDK_ROOT_DIR}/Include/vulkan/vulkan.h") 175 | SET(VULKANSDK_INCLUDE_DIR "${VULKANSDK_ROOT_DIR}/Include" CACHE PATH "path") 176 | else() 177 | SET(VULKANSDK_INCLUDE_DIR "${VULKANSDK_ROOT_DIR}" CACHE PATH "path") 178 | endif() 179 | SET(VULKANSDK_SHADERC_LIB ${VULKANSDK_SHADERC_LIB} CACHE PATH "path") 180 | 181 | find_package_handle_standard_args(VulkanSDK DEFAULT_MSG 182 | VULKANSDK_INCLUDE_DIR 183 | VULKAN_LIB 184 | VULKANSDK_SHADERC_LIB 185 | GLSLANGVALIDATOR 186 | ) 187 | 188 | mark_as_advanced( VULKANSDK_FOUND ) 189 | 190 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_apply_min_displacement.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | 16 | #include "remesh_apply_min_displacement.h" 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_apply_min_displacement.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | 10 | 11 | For each vertex, find and store the minimum and maximum displacement values 12 | stored in its adjacent triangles 13 | 14 | */ 15 | 16 | 17 | #ifndef __cplusplus 18 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 19 | #endif 20 | 21 | #include "remesh_common.h" 22 | 23 | #undef MAIN_NAME 24 | #define MAIN_NAME remeshApplyMinDisplacement 25 | 26 | 27 | // Find the min and max displacement for the vertex at vertexIndex so that displacement 28 | // encompasses any displacement within the bounds of the triangle at triangleIndex 29 | vec2 findMinMaxDisplacementFromTriangle(RM_DATA_ARG uint vertexIndex, uint triangleIndex) 30 | { 31 | float triMin = rtGetMinDisplacement(triangleIndex); 32 | float triMax = rtGetMaxDisplacement(triangleIndex); 33 | return vec2(triMin, triMax); 34 | } 35 | 36 | 37 | // Find the min and max displacement values stored in the 38 | // triangles adjacent to the vertex. Returns vec2(min, max) 39 | vec2 findMinMaxDisplacementInFan(RM_DATA_ARG uint vertexIndex) 40 | { 41 | uint encodedLastTriangleIndex = rvGetLastTriangle(vertexIndex); 42 | vec2 d = vec2(1e34f, -1e34f); 43 | bool isAllIgnored = true; 44 | // If this function is called the vertex must be connected to at least one triangle 45 | if(encodedLastTriangleIndex == ~0u) 46 | { 47 | RM_DATA(currentState).errorState = eRemesherErrorDebug; 48 | RM_DATA(currentState).debug.x = vertexIndex; 49 | return vec2(-1, 1); 50 | } 51 | 52 | int counter = 0; 53 | bool updated = false; 54 | // Iterate over adjacent triangles 55 | while(encodedLastTriangleIndex != ~0u) 56 | { 57 | uvec2 lastTri = decodePreviousTriangle(encodedLastTriangleIndex); 58 | uint lastTriangleIndex = lastTri.x; 59 | 60 | 61 | { 62 | vec2 triDisp = findMinMaxDisplacementFromTriangle(RM_DATA_VAL vertexIndex, lastTriangleIndex); 63 | 64 | if(abs(triDisp.x) < 1e10 && abs(triDisp.y) < 1e10) 65 | { 66 | d.x = min(triDisp.y, min(d.x, triDisp.x)); 67 | d.y = max(triDisp.x, max(d.y, triDisp.y)); 68 | updated = true; 69 | } 70 | isAllIgnored = false; 71 | } 72 | 73 | 74 | uint localVertexIndex = lastTri.y; 75 | encodedLastTriangleIndex = rtGetPreviousTriangle(lastTriangleIndex, localVertexIndex); 76 | } 77 | if(updated) 78 | { 79 | return d; 80 | } 81 | 82 | return vec2(uintBitsToFloat(~0u)); 83 | } 84 | 85 | 86 | MAIN 87 | { 88 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 89 | return; 90 | 91 | 92 | uint index = gl_GlobalInvocationID.x; 93 | if(index >= RM_DATA(scratchMetadata).uncompactedTriangleCount) 94 | return; 95 | 96 | if(!rtGetIsValid(index)) 97 | { 98 | return; 99 | } 100 | uvec3 dedupIndices = siGetDedupTriangle(index); 101 | if(!isValid(dedupIndices)) 102 | { 103 | return; 104 | } 105 | 106 | for(uint i = 0; i < 3; i++) 107 | { 108 | uint originalIndex = RM_DATA(triangles)[3 * index + i]; 109 | uint dedupIndex = dedupIndices[i]; 110 | if(dedupIndex == ~0u) 111 | { 112 | rvAtomicMinDisplacement(originalIndex, 0.f); 113 | rvAtomicMaxDisplacement(originalIndex, 0.f); 114 | continue; 115 | } 116 | vec2 minMaxDisplacement = findMinMaxDisplacementInFan(RM_DATA_VAL dedupIndex); 117 | if(minMaxDisplacement.x == uintBitsToFloat(~0u)) 118 | { 119 | rvAtomicMinDisplacement(originalIndex, 0.f); 120 | rvAtomicMaxDisplacement(originalIndex, 0.f); 121 | continue; 122 | } 123 | 124 | 125 | if(abs(minMaxDisplacement.x) < 1e10 && abs(minMaxDisplacement.y) < 1e10) 126 | { 127 | rvAtomicMinDisplacement(originalIndex, minMaxDisplacement.x); 128 | rvAtomicMaxDisplacement(originalIndex, minMaxDisplacement.y); 129 | } 130 | else 131 | { 132 | rvAtomicMinDisplacement(originalIndex, 0.f); 133 | rvAtomicMaxDisplacement(originalIndex, 0.f); 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_bindings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | #ifdef __cplusplus 12 | #pragma once 13 | #include "remesh_host_device.h" 14 | #include 15 | using namespace micromesh; 16 | #endif 17 | 18 | 19 | #ifndef __cplusplus 20 | #extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable 21 | 22 | #ifndef REMESHER_OVERRIDE_BLOCK_SIZE 23 | layout(local_size_x = REMESHER_BLOCK_SIZE, local_size_y = 1, local_size_z = 1) in; 24 | #endif 25 | 26 | layout(push_constant) uniform RemesherConstants_ 27 | { 28 | RemesherConstants constants; 29 | }; 30 | 31 | 32 | // User-provided data, modified in place (copy of enum gpu::GpuRemeshingResource) 33 | 34 | // main modified buffers 35 | // ------------------------- 36 | // must be pre-filled with appropriate data prior task begin 37 | // will be updated continuously during the process. 38 | // 4 x float per-vertex - 4th is unused 39 | layout(binding = eGpuRemeshingMeshVertexPositionsBuffer, set = 0) buffer GpuRemeshingMeshVertexPositionsBuffer 40 | { 41 | vec4 vertexPositions[]; 42 | }; 43 | 44 | // texcoordCount x 2 x float per-vertex 45 | layout(binding = eGpuRemeshingMeshVertexTexcoordsBuffer, set = 0) buffer GpuRemeshingMeshVertexTexcoordsBuffer 46 | { 47 | vec2 vertexTexCoords[]; 48 | }; 49 | 50 | // 2 x uint per-vertex 51 | layout(binding = eGpuRemeshingMeshVertexHashBuffer, set = 0) buffer GpuRemeshingMeshVertexHashBuffer 52 | { 53 | uvec2 vertexHash[]; 54 | }; 55 | 56 | 57 | // 3 x uint per-triangle 58 | layout(binding = eGpuRemeshingMeshTrianglesBuffer, set = 0) buffer GpuRemeshingMeshTrianglesBuffer 59 | { 60 | uint triangles[]; 61 | }; 62 | 63 | 64 | // 1 x uint per-triangle (e.g. per-triangle component/material assignments etc.) 65 | // (optional `GpuRemeshing_config::useTriangleUserIDs`) 66 | layout(binding = eGpuRemeshingMeshTriangleUserIDsBuffer, set = 0) buffer GpuRemeshingMeshTriangleUserIDsBuffer 67 | { 68 | uint trianglesUserID[]; 69 | }; 70 | 71 | 72 | // 1 x float16 per-vertex (optional `GpuRemeshing_config::useVertexCurvature`) 73 | // Addressing using f16vec2 for alignment, need care when accessing x or y component (even or odd index) 74 | layout(binding = eGpuRemeshingMeshVertexImportanceBuffer, set = 0) buffer GpuRemeshingMeshVertexImportanceBuffer 75 | { 76 | f16vec2 vertexImportances[]; 77 | }; 78 | 79 | // output buffers 80 | // ------------------------- 81 | // 82 | // 1 x uint { uint16 subdivlevel, uint16 edgeflags} per-triangle 83 | // (optional `OpRemeshing_settings::generateDisplacementInfo`, only in eDecimate mode) 84 | layout(binding = eGpuRemeshingMeshTriangleSubdivisionInfoBuffer, set = 0) buffer GpuRemeshingMeshTriangleSubdivisionInfoBuffer 85 | { 86 | uint triangleSubdivisionInfo[]; 87 | }; 88 | 89 | // 4 x float16 per-vertex - 4th is unused 90 | // (optional `OpRemeshing_settings::generateDisplacementInfo`, only in eDecimate mode) 91 | layout(binding = eGpuRemeshingMeshVertexDirectionsBuffer, set = 0) buffer GpuRemeshingMeshVertexDirectionsBuffer 92 | { 93 | f16vec4 vertexDirections[]; 94 | }; 95 | 96 | 97 | // 2 x float per-vertex 98 | // (optional `OpRemeshing_settings::generateDisplacementInfo`, only in eDecimate mode) 99 | layout(binding = eGpuRemeshingMeshVertexDirectionBoundsBuffer, set = 0) buffer GpuRemeshingMeshVertexDirectionBoundsBuffer 100 | { 101 | vec2 vertexDirectionBounds[]; 102 | }; 103 | layout(binding = eGpuRemeshingMeshVertexDirectionBoundsBuffer, set = 0) buffer GpuRemeshingMeshVertexDirectionBoundsBufferI 104 | { 105 | uvec2 vertexDirectionBoundsU[]; 106 | }; 107 | 108 | 109 | // intermediate buffers used during process 110 | // ---------------------------------------- 111 | // 3 x uint per-vertex as below 112 | // RemeshingVertexMergeInfo { 113 | // uint32_t vertexIndexA; 114 | // uint32_t vertexIndexB; 115 | // float blendAtoB; 116 | // } 117 | layout(binding = eGpuRemeshingMeshVertexMergeBuffer, set = 0) buffer GpuRemeshingMeshVertexMergeBuffer 118 | { 119 | uint vertexMerges[]; 120 | }; 121 | 122 | 123 | // 1 x uint per-vertex 124 | layout(binding = eGpuRemeshingDebugVertexBuffer, set = 0) buffer GpuRemeshingDebugVertexBuffer 125 | { 126 | uint vertexDebug[]; 127 | }; 128 | 129 | // 1 x uint per-triangle 130 | layout(binding = eGpuRemeshingDebugTriangleBuffer, set = 0) buffer GpuRemeshingDebugTriangleBuffer 131 | { 132 | uint triangleDebug[]; 133 | }; 134 | 135 | 136 | // 1 RemeshingCurrentState struct, used for feedback 137 | layout(binding = eGpuRemeshingCurrentStateBuffer, set = 0) buffer GpuRemeshingCurrentStateBuffer 138 | { 139 | RemeshingCurrentState currentState; 140 | }; 141 | 142 | 143 | // Scratch buffers, opaque to the user (see remesher::ScratchBuffers enum) 144 | layout(binding = eScratchIndexBuffer, set = 0) buffer ScratchIndexBuffer 145 | { 146 | uint scratchIndices[]; 147 | }; 148 | 149 | // Scratch buffers, opaque to the user (see remesher::ScratchBuffers enum) 150 | layout(binding = eScratchIndexBuffer, set = 0) buffer ScratchIndexBuffer128 151 | { 152 | uvec4 scratchIndices128[]; 153 | }; 154 | 155 | 156 | layout(binding = eScratchTriangles, set = 0) buffer ScratchTriangles 157 | { 158 | uint scratchTriangles[]; 159 | }; 160 | 161 | 162 | layout(binding = eScratchMetadata, set = 0) buffer ScratchMetadata 163 | { 164 | RemesherMetadata scratchMetadata; 165 | }; 166 | 167 | 168 | layout(binding = eScratchHashMap, set = 0) buffer ScratchHashMap 169 | { 170 | uint scratchHashMap[]; 171 | }; 172 | 173 | layout(binding = eScratchHashMap, set = 0) buffer ScratchHashMap128 174 | { 175 | uvec4 scratchHashMap128[]; 176 | }; 177 | 178 | 179 | layout(binding = eScratchEdgeList, set = 0) buffer ScratchEdgeList 180 | { 181 | uint scratchEdges[]; 182 | }; 183 | 184 | 185 | layout(binding = eScratchVertices, set = 0) buffer ScratchVertices 186 | { 187 | uint scratchVertices[]; 188 | }; 189 | 190 | layout(binding = eScratchVertices, set = 0) buffer ScratchVerticesF 191 | { 192 | float scratchVerticesF[]; 193 | }; 194 | 195 | 196 | layout(binding = eScratchTrianglesDesc, set = 0) buffer ScratchTrianglesDesc 197 | { 198 | uint64_t scratchTriangleDescs[]; 199 | }; 200 | 201 | 202 | layout(binding = eScratchVertexAliases, set = 0) buffer ScratchVertexAliases 203 | { 204 | uint scratchVertexAliases[]; 205 | }; 206 | 207 | layout(binding = eScratchVertexOriginalPos, set = 0) buffer ScratchVertexOriginalPos 208 | { 209 | vec4 scratchVertexOriginalPos[]; 210 | }; 211 | 212 | layout(binding = eScratchActiveVertices, set = 0) buffer ScratchActiveVerticesBuffer 213 | { 214 | uint scratchActiveVertices[]; 215 | }; 216 | 217 | 218 | #else 219 | // CPU bindings - unused since CPU fallback is not currently supported 220 | struct RemesherData 221 | { 222 | const uint* inputIndices; 223 | const uint* inputVertices; 224 | uint* outputIndices; 225 | uvec2* tempIndices; 226 | uint* outputVertices; 227 | RemesherMetadata outputMetadata; 228 | std::atomic_uint* edgesHash; 229 | std::atomic_uint* edgesList; 230 | std::atomic_uint* triangles; 231 | std::atomic_uint64_t* trianglesDesc; 232 | std::atomic_uint* vertices; 233 | 234 | int* verticesI = (int*)vertices; 235 | uint* tempVertices; 236 | 237 | uint* vertexAliases; 238 | float* originalVertexPos; 239 | std::atomic_int* micromeshInfo; 240 | std::atomic_int* micromeshInfoBackup; 241 | float* micromeshDispDir; 242 | 243 | 244 | RemesherConstants constants; 245 | }; 246 | #endif 247 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_clear_edge_list.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_clear_edge_list.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_clear_edge_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | 11 | Clear the edge costs from the list 12 | 13 | */ 14 | 15 | 16 | #undef MAIN_NAME 17 | #define MAIN_NAME remeshClearEdgeList 18 | 19 | 20 | #include "remesh_common.h" 21 | 22 | MAIN 23 | { 24 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 25 | return; 26 | 27 | uint index = uint(gl_GlobalInvocationID.x); 28 | if(index >= RM_CONSTANTS.edgeListSize) 29 | return; 30 | 31 | reSetCost(index, 0.f); 32 | } 33 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_clear_hash_map.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | #version 450 12 | #extension GL_GOOGLE_include_directive : enable 13 | 14 | #include "remesh_clear_hash_map.h" 15 | 16 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_clear_hash_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | 10 | Clear the hash map using 128-bit operations for efficiency 11 | 12 | */ 13 | 14 | 15 | #undef MAIN_NAME 16 | #define MAIN_NAME remeshClearHashMap 17 | 18 | 19 | #include "remesh_common.h" 20 | 21 | #define BATCH_SIZE 1 22 | 23 | MAIN 24 | { 25 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 26 | return; 27 | 28 | uint index = uint(gl_GlobalInvocationID.x); 29 | uint uintCount = RM_CONSTANTS.hashMapSize * 2; 30 | uint uvec4Count = uintCount / 4; 31 | 32 | uint batchCount = uvec4Count / BATCH_SIZE; 33 | 34 | for(uint i = 0; i < BATCH_SIZE; i++) 35 | { 36 | if((index + i) >= uvec4Count) 37 | return; 38 | 39 | RM_DATA(scratchHashMap128)[index * BATCH_SIZE + i] = uvec4(0); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_clear_micromesh_data.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_clear_micromesh_data.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_clear_micromesh_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | 10 | Clear the micromesh-related displacement bounds per vertex and per triangle 11 | 12 | */ 13 | 14 | 15 | #undef MAIN_NAME 16 | #define MAIN_NAME remeshClearMicromeshData 17 | 18 | #include "remesh_common.h" 19 | 20 | 21 | MAIN 22 | { 23 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 24 | return; 25 | 26 | uint index = uint(gl_GlobalInvocationID.x); 27 | 28 | if(index >= RM_CONSTANTS.indexCount / 3) 29 | return; 30 | 31 | rtResetDisplacementBounds(index); 32 | 33 | for(uint i = 0; i < 3; i++) 34 | { 35 | uint vIndex = RM_DATA(triangles)[3 * index + i]; 36 | rvResetMinMaxDisplacement(vIndex); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_collapse_flag.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | #extension GL_EXT_shader_explicit_arithmetic_types_int32 : enable 15 | 16 | #include "remesh_collapse_flag.h" 17 | 18 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_collapse_flag.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * 11 | * For each collapsed edge, flag the deduplicated vertices for collapse 12 | */ 13 | 14 | 15 | #undef MAIN_NAME 16 | #define MAIN_NAME remeshCollapseFlag 17 | 18 | #include "remesh_common.h" 19 | 20 | 21 | uint unpackEdgeId(uint64_t edgeDesc) 22 | { 23 | u32vec2 e = unpack32(edgeDesc); 24 | return e.x; 25 | } 26 | 27 | 28 | // Unpack the minimum edge cost descriptor of the triangle at triIndex, and check whether 29 | // it corresponds to edgeIndex 30 | bool isMinEdge(RM_DATA_ARG uint triIndex, uint edgeIndex) 31 | { 32 | uint minEdge = unpackEdgeId(RM_DATA(scratchTriangleDescs)[triIndex]); 33 | if(minEdge != ~0u) 34 | return minEdge == computeEdgeId(reGetVertices(edgeIndex)); 35 | return true; 36 | } 37 | 38 | 39 | // Check whether the edge at edgeIndex is the one with lowest cost stored in its adjacent triangles 40 | bool isCheapestInConnectedTriangles(RM_DATA_ARG uint vertex, float cost, uint edgeIndex) 41 | { 42 | uint encodedLastTriangleIndex = rvGetLastTriangle(vertex); 43 | 44 | while(encodedLastTriangleIndex != ~0u) 45 | { 46 | uvec2 lastTri = decodePreviousTriangle(encodedLastTriangleIndex); 47 | uint lastTriangleIndex = lastTri.x; 48 | if(hasEdge(lastTriangleIndex, edgeIndex) && !isMinEdge(RM_DATA_VAL lastTriangleIndex, edgeIndex)) 49 | return false; 50 | uint localVertexIndex = lastTri.y; 51 | encodedLastTriangleIndex = rtGetPreviousTriangle(lastTriangleIndex, localVertexIndex); 52 | } 53 | return true; 54 | } 55 | 56 | bool isCheapest(RM_DATA_ARG uint edgeIndex) 57 | { 58 | // Check whether this edge has the lowest cost in its connected triangles 59 | return isCheapestInConnectedTriangles(RM_DATA_VAL reGetVertices(edgeIndex).x, reGetCost(edgeIndex), edgeIndex); 60 | } 61 | 62 | 63 | MAIN 64 | { 65 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 66 | return; 67 | 68 | uint index = uint(gl_GlobalInvocationID.x); 69 | if(index >= RM_DATA(scratchMetadata).edgeCount) 70 | return; 71 | 72 | 73 | uvec2 edgeVertices = reGetVertices(index); 74 | if(edgeVertices.x == ~0u || edgeVertices.y == ~0u) 75 | return; 76 | 77 | bool isNonManifold = false; 78 | 79 | if(!isNonManifold) 80 | { 81 | // The error threshold for decimation is provided by the user through constants. For relaxation 82 | // the cost of an edge is the change of anisotropy in its neighborhood after shortening, the change 83 | // being normalized around 1 (= no change). 84 | float errorThreshold = (RM_CONSTANTS.remeshingMode == eDecimate) ? RM_CONSTANTS.errorThreshold : 1.f; 85 | 86 | if(reGetCost(index) > errorThreshold) 87 | return; 88 | 89 | // Check the validity of the collapse operation 90 | bvec2 isFlaggedVertex = bvec2(false); 91 | bvec2 isDoubleMarked = bvec2(false); 92 | bvec2 isIntersectionVertex = bvec2(false); 93 | for(uint i = 0; i < 2; i++) 94 | { 95 | uint flags = rvGetFlags(edgeVertices[i]); 96 | bool isFlagged = hasFlag(flags, RM_V_MARKED); 97 | if(isFlagged) 98 | { 99 | isFlaggedVertex[i] = true; 100 | if(hasFlag(flags, RM_V_DOUBLE_MARKED)) 101 | isDoubleMarked[i] = true; 102 | isIntersectionVertex[i] = hasFlag(flags, RM_V_FIXED); 103 | } 104 | } 105 | bool isBlockedEdge; 106 | isBlockedEdge = (isFlaggedVertex[0] != isFlaggedVertex[1]) || (isIntersectionVertex[0] || isIntersectionVertex[1]) 107 | || (isDoubleMarked[0] && isDoubleMarked[1]); 108 | 109 | 110 | if(isBlockedEdge) 111 | return; 112 | } 113 | 114 | 115 | // If the edge is the one with the lowest cost of its neighborhood, flag the deduplicated vertices for merging 116 | if(isNonManifold || isCheapest(RM_DATA_VAL index)) 117 | { 118 | rvSetDedupMerged(min(edgeVertices.x, edgeVertices.y), max(edgeVertices.x, edgeVertices.y)); 119 | } 120 | } -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_collapse_propagate.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_collapse_propagate.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_collapse_propagate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * Propagate the vertex merge orders flagged on deduplicated vertices onto 11 | * the original vertices 12 | * 13 | */ 14 | 15 | 16 | #undef MAIN_NAME 17 | #define MAIN_NAME remeshCollapsePropagate 18 | 19 | #include "remesh_common.h" 20 | 21 | // Find whether one of the triangle edges has been flagged for merge 22 | uint propagateMerge(RM_DATA_ARG uvec3 dedupIndices, uvec3 originalIndices) 23 | { 24 | // Iterate over the 3 deduplicated vertices 25 | for(uint base = 0; base < 3; base++) 26 | { 27 | // Find the potential merge target of the deduplicated vertex 28 | uint mergeTarget = rvGetDedupMerged(dedupIndices[base]); 29 | 30 | if(mergeTarget != ~0u) 31 | { 32 | // Check whether one of the other two dedup vertices correspond 33 | // to the merge target. If yes, mark the corresponding original 34 | // vertices for merge 35 | for(uint i = 1; i < 3; i++) 36 | { 37 | uint candidate = (base + i) % 3; 38 | if(mergeTarget == dedupIndices[candidate]) 39 | { 40 | uint srcIndex = min(originalIndices[base], originalIndices[candidate]); 41 | uint dstIndex = max(originalIndices[base], originalIndices[candidate]); 42 | rvSetMergingWith(srcIndex, dstIndex); 43 | rvSetMergingWith(dstIndex, ~0u); 44 | return candidate; 45 | } 46 | } 47 | } 48 | } 49 | return ~0u; 50 | } 51 | 52 | 53 | MAIN 54 | { 55 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 56 | return; 57 | 58 | uint index = uint(gl_GlobalInvocationID.x); 59 | 60 | if(index >= RM_DATA(scratchMetadata).uncompactedTriangleCount) 61 | return; 62 | 63 | if(!rtGetIsValid(index)) 64 | return; 65 | 66 | 67 | uvec3 originalIndices = 68 | uvec3(RM_DATA(triangles)[3 * index + 0], RM_DATA(triangles)[3 * index + 1], RM_DATA(triangles)[3 * index + 2]); 69 | 70 | uvec3 dedupIndices = siGetDedupTriangle(index); 71 | 72 | if(originalIndices != dedupIndices) 73 | { 74 | // Propagate the flags from deduplicated vertices onto the original ones 75 | rvAtomicSetFlags(originalIndices[0], rvGetFlags(dedupIndices[0])); 76 | rvAtomicSetFlags(originalIndices[1], rvGetFlags(dedupIndices[1])); 77 | rvAtomicSetFlags(originalIndices[2], rvGetFlags(dedupIndices[2])); 78 | } 79 | // Propagate merge information if relevant 80 | propagateMerge(dedupIndices, originalIndices); 81 | } -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_collapse_resolve.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_collapse_resolve.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_collapse_resolve.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * Once vertices have been marked for merging, issue merge orders for the 11 | * external merge kernel 12 | * 13 | */ 14 | 15 | #undef MAIN_NAME 16 | #define MAIN_NAME remeshCollapseResolve 17 | 18 | #include "remesh_common.h" 19 | 20 | 21 | MAIN 22 | { 23 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 24 | return; 25 | uint index = getActiveVertex(gl_GlobalInvocationID.x); 26 | if(index == ~0u) 27 | return; 28 | 29 | 30 | if(hasFlag(rvGetFlags(index), RM_V_ORPHAN)) 31 | return; 32 | 33 | RM_DATA(vertexDebug)[index] = rvGetFlags(index); 34 | 35 | // Return if that vertex is not involved in a merging operation 36 | if(rvGetMergingWith(index) == ~0u) 37 | return; 38 | 39 | RM_DATA(vertexDebug)[rvGetMergingWith(index)] = rvGetFlags(index); 40 | 41 | if(RM_CONSTANTS.iterationIndex > 1) 42 | { 43 | // Block volume preservation at seams to avoid watertightness issues 44 | mergeOutputVertices(index, rvGetMergingWith(index), 45 | hasFlag(rvGetFlags(index), RM_V_MARKED) && !hasFlag(rvGetFlags(index), RM_V_EDGE)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | #ifdef __cplusplus 12 | #pragma once 13 | #endif 14 | #include "remesh_host_device.h" 15 | 16 | #ifndef __cplusplus 17 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 18 | #extension GL_EXT_ray_query : require 19 | #extension GL_EXT_shader_atomic_float : enable 20 | #endif 21 | #include "remesh_bindings.h" 22 | 23 | 24 | #define REMESHER_ACCESSORS_ALL 25 | #define REMESHER_INTERNAL 26 | #include "remesh_accessors.h" 27 | 28 | 29 | #define M_PI 3.1415926535897932384626433832795 30 | 31 | 32 | uint encodePreviousTriangle(uint triangleIndex, uint localVertexRef) 33 | { 34 | const uint mask = 0x3; 35 | return ((triangleIndex & ~(mask << 30)) | ((localVertexRef & mask) << 30)); 36 | } 37 | 38 | uvec2 decodePreviousTriangle(uint previousTriangle) 39 | { 40 | const uint mask = 0x3; 41 | return uvec2((previousTriangle & ~(mask << 30)), previousTriangle >> 30); 42 | } 43 | 44 | #define getActiveVertex(arg0_) getActiveVertexImpl(RM_DATA_VAL arg0_) 45 | uint getActiveVertexImpl(RM_DATA_ARG uint threadIndex) 46 | { 47 | if(RM_DATA(scratchMetadata).activeVertices == 0) 48 | { 49 | if(threadIndex >= RM_CONSTANTS.vertexCount) 50 | return ~0u; 51 | return threadIndex; 52 | } 53 | 54 | if(threadIndex >= RM_DATA(scratchMetadata).activeVertices) 55 | return ~0u; 56 | return RM_DATA(scratchActiveVertices)[threadIndex]; 57 | } 58 | 59 | #define hasEdge(arg0_, arg1_) hasEdgeImpl(RM_DATA_VAL arg0_, arg1_) 60 | bool hasEdgeImpl(RM_DATA_ARG uint triIndex, uint edgeIndex) 61 | { 62 | for(uint i = 0; i < 3; i++) 63 | if(rtGetEdgeIndex(triIndex, i) == edgeIndex) 64 | return true; 65 | return false; 66 | } 67 | 68 | uint subdivLeveGetSegmentCount(uint subdivLevel) 69 | { 70 | return (1u << subdivLevel); 71 | } 72 | 73 | uint subdivLeveGetTriangleCount(uint subdivLevel) 74 | { 75 | return (1u << (subdivLevel * 2)); 76 | } 77 | 78 | uint subdivLevelGetVertexCount(uint subdivLevel) 79 | { 80 | uint vertsPerEdgeCount = subdivLeveGetSegmentCount(subdivLevel) + 1; 81 | return (vertsPerEdgeCount * (vertsPerEdgeCount + 1)) / 2; 82 | } 83 | 84 | 85 | float mixCurvatures(float c1, float c2) 86 | { 87 | float t = 0.f; 88 | if(c1 == 0.f && c2 != 0.f) 89 | t = c2; 90 | if(c1 != 0.f && c2 == 0.f) 91 | t = c1; 92 | if(c1 != 0.f && c2 != 0.f) 93 | t = max(c1, c2); 94 | 95 | return t; 96 | } 97 | 98 | 99 | #define cvGetOutputPosition(arg0_) cvGetOutputPositionImpl(RM_DATA_VAL arg0_) 100 | vec3 cvGetOutputPositionImpl(RM_DATA_ARG uint index) 101 | { 102 | return RM_DATA(vertexPositions)[index].xyz; 103 | } 104 | 105 | 106 | #define cvGetOutputTexCoord(arg0_) cvGetOutputTexCoordImpl(RM_DATA_VAL arg0_) 107 | vec2 cvGetOutputTexCoordImpl(RM_DATA_ARG uint index) 108 | { 109 | vec2 tex = RM_DATA(vertexTexCoords)[RM_CONSTANTS.texcoordCount * index + RM_CONSTANTS.texcoordIndex]; 110 | return tex; 111 | } 112 | 113 | #define cvGetVertexDirection(arg0_) cvGetVertexDirectionImpl(RM_DATA_VAL arg0_) 114 | vec3 cvGetVertexDirectionImpl(RM_DATA_ARG uint index) 115 | { 116 | return vec3(RM_DATA(vertexDirections)[index].xyz); 117 | } 118 | 119 | 120 | #define normalizeVertexDirection(arg0_) normalizeVertexDirectionImpl(RM_DATA_VAL arg0_) 121 | void normalizeVertexDirectionImpl(RM_DATA_ARG uint index) 122 | { 123 | f16vec3 d = RM_DATA(vertexDirections)[index].xyz; 124 | RM_DATA(vertexDirections)[index].xyz = normalize(RM_DATA(vertexDirections)[index].xyz); 125 | } 126 | 127 | #define copyVertexDirection(arg0_, arg1_) copyVertexDirectionImpl(RM_DATA_VAL arg0_, arg1_) 128 | void copyVertexDirectionImpl(RM_DATA_ARG uint dstIndex, uint srcIndex) 129 | { 130 | RM_DATA(vertexDirections)[dstIndex] = RM_DATA(vertexDirections)[srcIndex]; 131 | } 132 | 133 | 134 | #define isValid(arg0_) isValidImpl(RM_DATA_VAL arg0_) 135 | bool isValidImpl(RM_DATA_ARG uvec3 triIndices) 136 | { 137 | return !(triIndices.x == triIndices.y || triIndices.x == triIndices.z || triIndices.y == triIndices.z); 138 | } 139 | 140 | #define getOutputVertex(arg0_) getOutputVertexImpl(RM_DATA_VAL arg0_) 141 | vec3 getOutputVertexImpl(RM_DATA_ARG uint index) 142 | { 143 | return cvGetOutputPositionImpl(RM_DATA_VAL index); 144 | } 145 | 146 | 147 | #define getOriginalVertex(arg0_) getOriginalVertexImpl(RM_DATA_VAL arg0_) 148 | vec3 getOriginalVertexImpl(RM_DATA_ARG uint index) 149 | { 150 | return RM_DATA(scratchVertexOriginalPos)[index].xyz; 151 | } 152 | 153 | #define setOriginalVertex(arg0_, arg1_) setOriginalVertexImpl(RM_DATA_VAL arg0_, arg1_) 154 | void setOriginalVertexImpl(RM_DATA_ARG uint index, vec3 pos) 155 | { 156 | RM_DATA(scratchVertexOriginalPos)[index].xyz = pos; 157 | } 158 | 159 | #define getOriginalMaxEdgeLength(arg0_) getOriginalMaxEdgeLengthImpl(RM_DATA_VAL arg0_) 160 | float getOriginalMaxEdgeLengthImpl(RM_DATA_ARG uint index) 161 | { 162 | return RM_DATA(scratchVertexOriginalPos)[index].w; 163 | } 164 | 165 | #define setOriginalMaxEdgeLength(arg0_, arg1_) setOriginalMaxEdgeLengthImpl(RM_DATA_VAL arg0_, arg1_) 166 | void setOriginalMaxEdgeLengthImpl(RM_DATA_ARG uint index, float maxEdgeLength) 167 | { 168 | RM_DATA(scratchVertexOriginalPos)[index].w = maxEdgeLength; 169 | } 170 | 171 | 172 | #define getOutputPosNormal(arg0_, arg1_, arg2_) getOutputPosNormalImpl(RM_DATA_VAL arg0_, arg1_, arg2_) 173 | void getOutputPosNormalImpl(RM_DATA_ARG uint index, REF(vec3) pos, REF(vec3) normal) 174 | { 175 | pos = cvGetOutputPositionImpl(RM_DATA_VAL index); 176 | normal = cvGetVertexDirectionImpl(RM_DATA_VAL index); 177 | } 178 | 179 | #define getOutputNormal(arg0_) getOutputNormalImpl(RM_DATA_VAL arg0_) 180 | vec3 getOutputNormalImpl(RM_DATA_ARG uint index) 181 | { 182 | return cvGetVertexDirectionImpl(RM_DATA_VAL index); 183 | } 184 | 185 | 186 | #define mergeOutputVertices(arg0_, arg1_, arg2_) mergeOutputVerticesImpl(RM_DATA_VAL arg0_, arg1_, arg2_) 187 | void mergeOutputVerticesImpl(RM_DATA_ARG uint v0, uint v1, bool blockVolumePreservation) 188 | { 189 | uint mergeSlot = atomicAdd(RM_DATA(currentState).mergeCount, 1); 190 | 191 | float w = 0.5f; 192 | 193 | if(blockVolumePreservation) 194 | w = -w; 195 | 196 | RM_DATA(vertexMerges)[3 * mergeSlot + 0] = v0; 197 | RM_DATA(vertexMerges)[3 * mergeSlot + 1] = v1; 198 | RM_DATA(vertexMerges)[3 * mergeSlot + 2] = floatBitsToUint(w); 199 | } 200 | 201 | 202 | uint wangHash(uint seed) 203 | { 204 | seed = (seed ^ 61) ^ (seed >> 16); 205 | seed *= 9; 206 | seed = seed ^ (seed >> 4); 207 | seed *= 0x27d4eb2d; 208 | seed = seed ^ (seed >> 15); 209 | return seed; 210 | } 211 | 212 | uint xorshift32(uint x64) 213 | { 214 | x64 ^= x64 << 13; 215 | x64 ^= x64 >> 7; 216 | x64 ^= x64 << 17; 217 | return x64; 218 | } 219 | 220 | 221 | #define hashVertexIndex(arg0_) hashVertexIndexImpl(RM_DATA_VAL arg0_) 222 | uint hashVertexIndexImpl(RM_DATA_ARG vec3 v) 223 | { 224 | const uint offset = 0; 225 | uint h; 226 | if(RM_CONSTANTS.deduplicationThreshold == 0.f) 227 | { 228 | h = wangHash(offset + floatBitsToUint(v.x)); 229 | h = wangHash(offset + h + floatBitsToUint(v.y)); 230 | h = wangHash(offset + h + floatBitsToUint(v.z)); 231 | } 232 | else 233 | { 234 | v = floor(v / RM_CONSTANTS.deduplicationThreshold); 235 | h = wangHash(offset + uint(v.x)); 236 | h = wangHash(offset + h + uint(v.y)); 237 | h = wangHash(offset + h + uint(v.z)); 238 | } 239 | return h % RM_CONSTANTS.hashMapSize; 240 | } 241 | 242 | #define hashVertexChecksum(arg0_) hashVertexChecksumImpl(RM_DATA_VAL arg0_) 243 | uint hashVertexChecksumImpl(RM_DATA_ARG vec3 v) 244 | { 245 | const uint offset = 0; 246 | uint h; 247 | if(RM_CONSTANTS.deduplicationThreshold == 0.f) 248 | { 249 | h = xorshift32(offset + floatBitsToUint(v.x)); 250 | h = xorshift32(offset + h + floatBitsToUint(v.y)); 251 | h = xorshift32(offset + h + floatBitsToUint(v.z)); 252 | } 253 | else 254 | { 255 | v = floor(v / RM_CONSTANTS.deduplicationThreshold); 256 | h = xorshift32(offset + uint(v.x)); 257 | h = xorshift32(offset + h + uint(v.y)); 258 | h = xorshift32(offset + h + uint(v.z)); 259 | } 260 | return h % RM_CONSTANTS.hashMapSize; 261 | } 262 | 263 | #define rehashIndex(arg0_) rehashIndexImpl(RM_DATA_VAL arg0_) 264 | uint rehashIndexImpl(RM_DATA_ARG uint h) 265 | { 266 | uint newH = wangHash(h) % RM_CONSTANTS.hashMapSize; 267 | if(h == newH) 268 | return (h + 1) % RM_CONSTANTS.hashMapSize; 269 | return newH; 270 | } 271 | 272 | #define rehashEdgeIndex(arg0_, arg1_) rehashEdgeIndexImpl(RM_DATA_VAL arg0_, arg1_) 273 | uint rehashEdgeIndexImpl(RM_DATA_ARG uint h, uvec2 edge) 274 | { 275 | uint newH = wangHash(h + edge.x + edge.y) % RM_CONSTANTS.hashMapSize; 276 | if(h == newH) 277 | return (h + edge.x + edge.y) % RM_CONSTANTS.hashMapSize; 278 | return newH; 279 | } 280 | 281 | #define hashVertexAttributesIndex(arg0_) hashVertexAttributesIndexImpl(RM_DATA_VAL arg0_) 282 | uint hashVertexAttributesIndexImpl(RM_DATA_ARG uint index) 283 | { 284 | return RM_DATA(vertexHash)[index].x % RM_CONSTANTS.hashMapSize; 285 | } 286 | 287 | #define hashVertexAttributesChecksum(arg0_) hashVertexAttributesChecksumImpl(RM_DATA_VAL arg0_) 288 | uint hashVertexAttributesChecksumImpl(RM_DATA_ARG uint index) 289 | { 290 | return max(1u, RM_DATA(vertexHash)[index].y); 291 | } 292 | 293 | #define hashFullVertexIndex(arg0_) hashFullVertexIndexImpl(RM_DATA_VAL arg0_) 294 | uint hashFullVertexIndexImpl(RM_DATA_ARG uint index) 295 | { 296 | uint h = RM_DATA(vertexHash)[index].x; 297 | return h % RM_CONSTANTS.hashMapSize; 298 | } 299 | 300 | #define hashFullVertexChecksum(arg0_) hashFullVertexChecksumImpl(RM_DATA_VAL arg0_) 301 | uint hashFullVertexChecksumImpl(RM_DATA_ARG uint index) 302 | { 303 | uint h = RM_DATA(vertexHash)[index].y; 304 | return max(1u, h); 305 | } 306 | 307 | uint hashEdgeChecksum(uvec2 e) 308 | { 309 | if(e.x < e.y) 310 | e = uvec2(e.x, e.y); 311 | else 312 | e = uvec2(e.y, e.x); 313 | 314 | uint h = xorshift32(e.x * 13543 + e.y * 7987 + 545); 315 | return max(1u, h); 316 | } 317 | 318 | #define hashEdgeIndex(arg0_) hashEdgeIndexImpl(RM_DATA_VAL arg0_) 319 | uint hashEdgeIndexImpl(RM_DATA_ARG uvec2 e) 320 | { 321 | if(e.x < e.y) 322 | e = uvec2(e.x, e.y); 323 | else 324 | e = uvec2(e.y, e.x); 325 | 326 | uint h = wangHash(e.x * 7525 + e.y * 213 + 78897); 327 | return h % RM_CONSTANTS.hashMapSize; 328 | } 329 | 330 | 331 | bool hasFlag(uint mask, uint flag) 332 | { 333 | return (mask & flag) == flag; 334 | } 335 | 336 | #define computeEdgeId(arg0_) computeEdgeIdImpl(RM_DATA_VAL arg0_) 337 | uint computeEdgeIdImpl(RM_DATA_ARG uvec2 vertices) 338 | { 339 | precise vec3 v0 = getOutputVertex(vertices.x); 340 | precise vec3 v1 = getOutputVertex(vertices.y); 341 | 342 | uint hv0 = hashVertexChecksum(v0); 343 | uint hv1 = hashVertexChecksum(v1); 344 | 345 | 346 | uint edgeId = hashEdgeChecksum(uvec2(hv0, hv1)); 347 | return edgeId; 348 | } -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_compact_indices.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | #extension GL_EXT_shader_explicit_arithmetic_types_int8 : enable 15 | 16 | #include "remesh_compact_indices.h" 17 | 18 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_compact_indices.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * 11 | * Compact the index buffer after edge collapse 12 | * 13 | */ 14 | 15 | 16 | #undef MAIN_NAME 17 | #define MAIN_NAME remeshCompactIndices 18 | 19 | #define REMESHER_OVERRIDE_BLOCK_SIZE 20 | #include "remesh_common.h" 21 | 22 | // A large block size strongly benefits performance (tested on RTX3090Ti) 23 | layout(local_size_x = 1024, local_size_y = 1, local_size_z = 1) in; 24 | 25 | // The compaction uses an auxiliary buffer. Instead of allocating a buffer for that 26 | // usage we reuse the hash map used for vertex/edge deduplication 27 | #define compactionAuxData RM_DATA(scratchHashMap) 28 | 29 | // Process 4 triangles per thread for performance 30 | #define COMPACTION_ENTRIES_PER_THREAD 4 31 | 32 | // Check whether the triangle at index is valid or degenerate 33 | bool checkValue(uint index) 34 | { 35 | // Check for duplicate indices 36 | uvec3 indices; 37 | 38 | for(uint i = 0; i < 3; i++) 39 | { 40 | indices[i] = RM_DATA(triangles)[3 * index + i]; 41 | } 42 | if(!isValid(indices)) 43 | return false; 44 | 45 | // Check for duplicate coordinates 46 | vec3 pos[3]; 47 | for(uint i = 0; i < 3; i++) 48 | { 49 | pos[i] = getOutputVertex(indices[i]); 50 | } 51 | 52 | if(pos[0] == pos[1] || pos[0] == pos[2] || pos[1] == pos[2]) 53 | return false; 54 | return true; 55 | } 56 | 57 | // Update the index values after compacting the vertex buffer 58 | // For this we use the contents of the last vertex merging orders, 59 | // where the index r of the vertex replacing the one at vertex i is 60 | // r = vertexMerges[3 * i + 0] 61 | void updateIndices(uint index) 62 | { 63 | bool isInvalid = false; 64 | for(uint i = 0; i < 3; i++) 65 | { 66 | uint vertexIndex = RM_DATA(triangles)[3 * index + i]; 67 | 68 | if(vertexIndex >= RM_DATA(currentState).mergeCount) 69 | { 70 | RM_DATA(currentState).errorState = eRemesherErrorDebug; 71 | return; 72 | } 73 | // Find the replacement of the current vertex 74 | uint replacement = vertexMerges[3 * vertexIndex + 0]; 75 | 76 | if(vertexIndex >= RM_DATA(scratchMetadata).uncompactedVertexCount) 77 | { 78 | isInvalid = true; 79 | } 80 | 81 | // If the vertex has indeed been moved by the vertex buffer compaction, 82 | // update the index stored in the index buffer for that vertex 83 | if(replacement != ~0u) 84 | { 85 | if(isInvalid || replacement >= RM_DATA(currentState).vertexCount || vertexIndex <= replacement) 86 | { 87 | isInvalid = true; 88 | RM_DATA(currentState).errorState = eRemesherErrorDebug; 89 | return; 90 | } 91 | RM_DATA(triangles)[3 * index + i] = replacement; 92 | } 93 | else 94 | { 95 | if(vertexIndex >= RM_DATA(currentState).vertexCount) 96 | { 97 | RM_DATA(currentState).errorState = eRemesherErrorDebug; 98 | } 99 | } 100 | } 101 | } 102 | // The compaction auxiliary data stores a flag indicating whether the corresponding 103 | // entry at index is valid or not. This gains performance by avoiding reading again 104 | // the contents of the input buffer, while the aux data is read/written in any case 105 | bool checkValueFlag(uint index) 106 | { 107 | return (compactionAuxData[index] >> 31) == 1; 108 | } 109 | 110 | // Copy the triangle data from src to dst, including its per-triangle 111 | // subdivision info and collapse counter 112 | void copyData(uint dst, uint src, bool invalidate) 113 | { 114 | for(uint i = 0; i < 3; i++) 115 | { 116 | RM_DATA(triangles)[dst * 3 + i] = RM_DATA(triangles)[src * 3 + i]; 117 | if(invalidate) 118 | RM_DATA(triangles)[src * 3 + i] = 0; 119 | } 120 | rmmCopy(dst, src); 121 | rtSetAggregatedCounter(dst, rtGetAggregatedCounter(src)); 122 | } 123 | 124 | MAIN 125 | { 126 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 127 | return; 128 | 129 | // First pass, count the number of valid entries and store the validity flags 130 | if(RM_CONSTANTS.compactionPass == 0) 131 | { 132 | uint index = uint(gl_GlobalInvocationID.x) * COMPACTION_ENTRIES_PER_THREAD; 133 | uint validEntries = 0; 134 | 135 | for(uint i = 0; i < COMPACTION_ENTRIES_PER_THREAD; i++) 136 | { 137 | if(index + i >= RM_DATA(scratchMetadata).uncompactedTriangleCount) 138 | break; 139 | // We update the indices only when the vertex buffer has just been compacted, 140 | // at the end of the decimation process 141 | if(RM_CONSTANTS.isFinalCompaction == 1) 142 | updateIndices(index + i); 143 | 144 | bool isValid = checkValue(index + i); 145 | if(isValid) 146 | { 147 | validEntries++; 148 | } 149 | // Store the entry validity flag 150 | compactionAuxData[index + i] = isValid ? (1 << 31) : 0; 151 | } 152 | atomicAdd(RM_DATA(scratchMetadata).indexCompactionValidEntries, validEntries); 153 | return; 154 | } 155 | 156 | // Second pass, enqueue the required number of free slots (i.e. corresponding to invalid 157 | // entries) by adding their indices in the auxiliary buffer 158 | if(RM_CONSTANTS.compactionPass == 1) 159 | { 160 | uint index = uint(gl_GlobalInvocationID.x) * COMPACTION_ENTRIES_PER_THREAD; 161 | 162 | uint8_t invalidEntries[COMPACTION_ENTRIES_PER_THREAD]; 163 | uint invalidEntryCount = 0; 164 | 165 | for(uint i = 0; i < COMPACTION_ENTRIES_PER_THREAD; i++) 166 | { 167 | if(index + i >= RM_DATA(scratchMetadata).indexCompactionValidEntries) 168 | break; 169 | 170 | bool isValid = checkValueFlag(index + i); 171 | if(!isValid) 172 | { 173 | uint slot = invalidEntryCount++; 174 | invalidEntries[slot] = uint8_t(i); 175 | } 176 | } 177 | uint begin = atomicAdd(RM_DATA(scratchMetadata).indexCompactionCurrentInvalidEntry, invalidEntryCount); 178 | for(uint i = 0; i < invalidEntryCount; i++) 179 | { 180 | compactionAuxData[begin + i] |= index + invalidEntries[i]; 181 | } 182 | return; 183 | } 184 | 185 | // Final pass, for each valid entry with an index beyond the final number of valid entries, 186 | // we reserve a free slot and copy the triangle data into it. 187 | if(RM_CONSTANTS.compactionPass == 2) 188 | { 189 | uint validEntries = RM_DATA(scratchMetadata).indexCompactionValidEntries; 190 | 191 | uint index = uint(gl_GlobalInvocationID.x) * COMPACTION_ENTRIES_PER_THREAD + validEntries; 192 | for(uint i = 0; i < COMPACTION_ENTRIES_PER_THREAD; i++) 193 | { 194 | if(index + i >= RM_DATA(scratchMetadata).uncompactedTriangleCount) 195 | break; 196 | 197 | bool isValid = checkValueFlag(index + i); 198 | 199 | if(isValid) 200 | { 201 | uint auxEntryId = atomicAdd(RM_DATA(scratchMetadata).indexCompactionCurrentValidEntry, 1); 202 | uint slot = compactionAuxData[auxEntryId]; 203 | slot = slot & (~(1 << 31)); 204 | copyData(slot, index + i, true); 205 | } 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_compact_vertices.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | #extension GL_EXT_shader_explicit_arithmetic_types_int8 : enable 15 | 16 | #include "remesh_compact_vertices.h" 17 | 18 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_compact_vertices.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #undef MAIN_NAME 13 | #define MAIN_NAME remeshCompactVertices 14 | 15 | #define REMESHER_OVERRIDE_BLOCK_SIZE 16 | #include "remesh_common.h" 17 | 18 | // A large block size strongly benefits performance (tested on RTX3090Ti) 19 | layout(local_size_x = 1024, local_size_y = 1, local_size_z = 1) in; 20 | 21 | // The compaction uses an auxiliary buffer. Instead of allocating a buffer for that 22 | // usage we reuse the hash map used for vertex/edge deduplication 23 | #define compactionAuxData RM_DATA(scratchHashMap) 24 | 25 | // Process 4 triangles per thread for performance 26 | #define COMPACTION_ENTRIES_PER_THREAD 4 27 | 28 | // Check whether the vertex at index is an orphan. In that case 29 | // it is not needed by the final decimated mesh, and can be 30 | // safely overwritten 31 | bool checkValue(uint index) 32 | { 33 | return !(hasFlag(rvGetFlags(index), RM_V_ORPHAN)); 34 | } 35 | 36 | // The compaction auxiliary data stores a flag indicating whether the corresponding 37 | // entry at index is valid or not. This gains performance by avoiding reading again 38 | // the contents of the input buffer, while the aux data is read/written in any case 39 | bool checkValueFlag(uint index) 40 | { 41 | return (compactionAuxData[index] >> 31) == 1; 42 | } 43 | 44 | // Issue a copy request to the external application, using the 45 | // special weight of 1 to force a copy instead of a merge 46 | void copyData(uint dst, uint src, bool invalidate) 47 | { 48 | RM_DATA(vertexMerges)[3 * src + 0] = dst; 49 | RM_DATA(vertexMerges)[3 * src + 1] = src; 50 | RM_DATA(vertexMerges)[3 * src + 2] = floatBitsToUint(1.f); 51 | 52 | RM_DATA(vertexDebug)[dst] = RM_DATA(vertexDebug)[src]; 53 | 54 | // Sanity check FIXME to remove 55 | if(dst != ~0u && src < dst) 56 | { 57 | RM_DATA(currentState).errorState = eRemesherErrorDebug; 58 | RM_DATA(currentState).debug.x = 2; 59 | return; 60 | } 61 | } 62 | 63 | 64 | uint vertexCount() 65 | { 66 | return RM_DATA(scratchMetadata).uncompactedVertexCount; 67 | } 68 | 69 | MAIN 70 | { 71 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 72 | return; 73 | 74 | // First pass, count the number of valid entries and store the validity flags 75 | if(RM_CONSTANTS.compactionPass == 0) 76 | { 77 | uint index = uint(gl_GlobalInvocationID.x) * COMPACTION_ENTRIES_PER_THREAD; 78 | 79 | uint validEntries = 0; 80 | 81 | for(uint i = 0; i < COMPACTION_ENTRIES_PER_THREAD; i++) 82 | { 83 | if(index + i >= vertexCount()) 84 | break; 85 | bool isValid = checkValue(index + i); 86 | if(isValid) 87 | { 88 | validEntries++; 89 | } 90 | compactionAuxData[index + i] = (isValid ? (1 << 31) : 0); 91 | } 92 | atomicAdd(RM_DATA(scratchMetadata).vertexCompactionValidEntries, validEntries); 93 | return; 94 | } 95 | 96 | // Second pass, enqueue the required number of free slots (i.e. corresponding to invalid 97 | // entries) by adding their indices in the auxiliary buffer 98 | if(RM_CONSTANTS.compactionPass == 1) 99 | { 100 | uint index = uint(gl_GlobalInvocationID.x) * COMPACTION_ENTRIES_PER_THREAD; 101 | 102 | uint8_t invalidEntries[COMPACTION_ENTRIES_PER_THREAD]; 103 | uint invalidEntryCount = 0; 104 | 105 | for(uint i = 0; i < COMPACTION_ENTRIES_PER_THREAD; i++) 106 | { 107 | if(index + i >= RM_DATA(scratchMetadata).vertexCompactionValidEntries) 108 | break; 109 | 110 | bool isValid = checkValueFlag(index + i); 111 | if(!isValid) 112 | { 113 | uint slot = invalidEntryCount++; 114 | invalidEntries[slot] = uint8_t(i); 115 | } 116 | // Make invalid copy request for the vertices before the cut line 117 | copyData(~0u, index + i, false); 118 | } 119 | uint begin = atomicAdd(RM_DATA(scratchMetadata).vertexCompactionCurrentInvalidEntry, invalidEntryCount); 120 | for(uint i = 0; i < invalidEntryCount; i++) 121 | { 122 | compactionAuxData[begin + i] |= index + uint(invalidEntries[i]); 123 | } 124 | return; 125 | } 126 | 127 | // Final pass, for each valid entry with an index beyond the final number of valid entries, 128 | // we reserve a free slot and copy the vertex data into it. 129 | if(RM_CONSTANTS.compactionPass == 2) 130 | { 131 | uint validEntries = RM_DATA(scratchMetadata).vertexCompactionValidEntries; 132 | 133 | uint index = uint(gl_GlobalInvocationID.x) * COMPACTION_ENTRIES_PER_THREAD + validEntries; 134 | 135 | // We set the merge count to the total vertex count, so the merging kernel will consider 136 | // all vertices. The ones with an invalid merge index ~0u will be ignored, and the others 137 | // will trigger the necessary copies 138 | if(gl_GlobalInvocationID.x == 0) 139 | { 140 | RM_DATA(currentState).mergeCount = vertexCount(); 141 | } 142 | for(uint i = 0; i < COMPACTION_ENTRIES_PER_THREAD; i++) 143 | { 144 | if(index + i >= vertexCount()) 145 | break; 146 | 147 | bool isValid = checkValueFlag(index + i); 148 | 149 | if(isValid && (index + i < vertexCount())) 150 | { 151 | uint auxEntryId = atomicAdd(RM_DATA(scratchMetadata).vertexCompactionCurrentValidEntry, 1); 152 | uint slot = compactionAuxData[auxEntryId]; 153 | slot = slot & (~(1 << 31)); 154 | copyData(slot, index + i, true); 155 | } 156 | else 157 | { 158 | copyData(~0u, index + i, true); 159 | } 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_deduplicate.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * 11 | * Deduplicate the input vertices based on their location only. This first pass 12 | * adds each vertex into the hash map and stores the resulting hash index 13 | * 14 | */ 15 | 16 | 17 | #undef MAIN_NAME 18 | #define MAIN_NAME remeshDeduplicate 19 | 20 | #include "remesh_common.h" 21 | 22 | 23 | MAIN 24 | { 25 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 26 | return; 27 | 28 | uint index = getActiveVertex(gl_GlobalInvocationID.x); 29 | if(index == ~0u) 30 | return; 31 | 32 | // Unused vertices are not considered to for better hash map performance 33 | if(hasFlag(rvGetFlags(index), RM_V_ORPHAN)) 34 | return; 35 | if(hasFlag(rvGetFlags(index), RM_V_UNKNOWN)) 36 | { 37 | rvAtomicAddFlag(index, RM_V_ORPHAN); 38 | return; 39 | } 40 | 41 | 42 | vec3 v = getOutputVertex(index); 43 | 44 | uint h = hashVertexIndex(v); 45 | const uint checksum = hashVertexChecksum(v); 46 | bool found = false; 47 | for(uint j = 0; j < 100; j++) 48 | { 49 | uint r = rhAtomicCompSwapChecksum(h, 0, checksum); 50 | 51 | if(r == 0) // If empty, this vertex is new, add it to the list 52 | { 53 | rhSetStoredIndex(h, index); 54 | found = true; 55 | break; 56 | } 57 | if(r != checksum) // Collision, rehash and restart 58 | { 59 | h = rehashIndex(h); 60 | } 61 | else // Vertex already exists, stop searching 62 | { 63 | found = true; 64 | break; 65 | } 66 | } 67 | if(found) 68 | { 69 | rhAtomicIncRefCounter(h); 70 | } 71 | else 72 | h = RM_H_NOT_FOUND; 73 | rvSetHashIndex(index, h); 74 | } 75 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate_base.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_deduplicate_base.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * 11 | * Deduplicate the input vertices based on their full attribute set, identified 12 | *.by their user-defined hash key 13 | * This kernel adds each vertex into the hash map and stores the resulting hash index 14 | * 15 | */ 16 | 17 | 18 | #undef MAIN_NAME 19 | #define MAIN_NAME remeshDeduplicateBase 20 | 21 | #include "remesh_common.h" 22 | 23 | 24 | MAIN 25 | { 26 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 27 | return; 28 | 29 | if(gl_GlobalInvocationID.x == 0) 30 | RM_DATA(currentState).vertexCount = RM_DATA(scratchMetadata).activeVertices; 31 | 32 | uint index = getActiveVertex(gl_GlobalInvocationID.x); 33 | if(index == ~0u) 34 | return; 35 | 36 | 37 | if(hasFlag(rvGetFlags(index), RM_V_ORPHAN)) 38 | return; 39 | 40 | 41 | uint h = hashFullVertexIndex(index); 42 | 43 | const uint checksum = hashFullVertexChecksum(index); 44 | bool found = false; 45 | for(uint j = 0; j < 100; j++) 46 | { 47 | uint r = rhAtomicCompSwapChecksum(h, 0, checksum); 48 | 49 | if(r == 0) // If empty, this vertex is new, add it to the list 50 | { 51 | found = true; 52 | break; 53 | } 54 | if(r != checksum) // Collision, rehash and restart 55 | { 56 | h = rehashIndex(h); 57 | } 58 | else // Vertex already exists, stop searching 59 | { 60 | found = true; 61 | break; 62 | } 63 | } 64 | if(!found) 65 | h = RM_H_NOT_FOUND; 66 | 67 | // We need a vertex of the mesh that will represent 68 | // all its duplicates. 69 | // We store the index of the vertex in the hash map 70 | // only if it is effectively used in the current state 71 | // of the mesh 72 | if(RM_DATA(scratchVertexAliases)[index] == ~0u) 73 | rhSetStoredIndex(h, index); 74 | 75 | rvSetHashIndex(index, h); 76 | } 77 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate_finalize.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_deduplicate_finalize.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate_finalize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * 11 | * Second pass of position-based deduplication: for each vertex fetch its 12 | * representative unique vertex in the hash map. We also flag the vertices 13 | * located on attribute discontinuities 14 | * 15 | */ 16 | 17 | 18 | #undef MAIN_NAME 19 | #define MAIN_NAME remeshDeduplicateFinalize 20 | 21 | #include "remesh_common.h" 22 | 23 | 24 | MAIN 25 | { 26 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 27 | return; 28 | 29 | uint index = uint(gl_GlobalInvocationID.x); 30 | if(index >= RM_DATA(scratchMetadata).uncompactedTriangleCount) 31 | return; 32 | 33 | if(!rtGetIsValid(index)) 34 | return; 35 | 36 | uvec3 indices; 37 | uint markedVertices = 0; 38 | for(uint i = 0; i < 3; i++) 39 | { 40 | uint h = rvGetHashIndex(RM_DATA(triangles)[3 * index + i]); 41 | if(h == RM_H_NOT_FOUND) 42 | { 43 | rtSetIsValid(index, false); 44 | RM_DATA(currentState).errorState = eRemesherErrorVertexHashNotFound; 45 | return; 46 | } 47 | uint storedIndex = rhGetStoredIndex(h); 48 | siSetDedupIndex(3 * index + i, storedIndex); 49 | 50 | indices[i] = storedIndex; 51 | 52 | if(hasFlag(rvGetFlags(storedIndex), RM_V_ORPHAN)) 53 | { 54 | RM_DATA(currentState).errorState = eRemesherErrorDebug; 55 | RM_DATA(currentState).debug.x = 3; 56 | } 57 | 58 | // If the same position has been added more than twice to the hash map it means 59 | // the vertex is located at the crossing of multiple discontinuities. 60 | // This vertex must be kept as-if, and is therefore marked as fixed. 61 | uint hRefCounter = rhGetRefCounter(h); 62 | if(hRefCounter > 2) 63 | { 64 | rvAtomicAddFlag(storedIndex, RM_V_MARKED | RM_V_FIXED); 65 | markedVertices++; 66 | } 67 | 68 | // If the same position has been added twice to the hash map 69 | // this location is on an attribute discontinuity. For decimation 70 | // we mark the vertex as being on a discontinuity. For relaxation 71 | // we mark it as fixed to be sure to preserve the exact UV boundaries 72 | if(hRefCounter == 2) 73 | { 74 | //uint attribHash = rvGetAttribsHash(RM_DATA(triangles)[3 * index + i]); 75 | { 76 | rvAtomicAddFlag(storedIndex, RM_CONSTANTS.remeshingMode == eDecimate ? RM_V_MARKED : (RM_V_MARKED | RM_V_FIXED)); 77 | markedVertices++; 78 | } 79 | } 80 | } 81 | // If all vertices have been marked as being on a discontinuity the triangle defines 82 | // an intersection of discontinuity lines. In this case we may have two adjacent vertices 83 | // marked at being on a discontinuity, but in effect belong to two separate discontinuities. 84 | // We mark all 3 vertices as DOUBLE_MARKED to pay special attention to that case in later steps. 85 | if(markedVertices == 3) 86 | { 87 | for(uint i = 0; i < 3; i++) 88 | { 89 | rvAtomicAddFlag(indices[i], RM_V_DOUBLE_MARKED); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate_finalize_base.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_deduplicate_finalize_base.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate_finalize_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * 11 | * Second pass of full vertex deduplication: for each vertex fetch its 12 | * representative unique vertex in the hash map. 13 | * 14 | */ 15 | 16 | 17 | #undef MAIN_NAME 18 | #define MAIN_NAME remeshDeduplicateFinalizeBase 19 | 20 | #include "remesh_common.h" 21 | 22 | 23 | MAIN 24 | { 25 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 26 | return; 27 | 28 | uint index = uint(gl_GlobalInvocationID.x); 29 | if(index >= RM_CONSTANTS.indexCount / 3) 30 | return; 31 | 32 | uvec3 indices = uvec3(0); 33 | bvec3 replaced; 34 | // Rebuild the indices of the triangle from the hash map contents 35 | for(uint i = 0; i < 3; i++) 36 | { 37 | uint vertexIndex = RM_DATA(triangles)[3 * index + i]; 38 | uint h = rvGetHashIndex(vertexIndex); 39 | 40 | if(h == RM_H_NOT_FOUND) 41 | { 42 | rtSetIsValid(index, false); 43 | RM_DATA(currentState).errorState = eRemesherErrorVertexHashNotFound; 44 | return; 45 | } 46 | indices[i] = rhGetStoredIndex(h); 47 | replaced[i] = (indices[i] != vertexIndex); 48 | if(h != ~0u) 49 | atomicMax(RM_DATA(scratchMetadata).uncompactedVertexCount, indices[i] + 1); 50 | else 51 | { 52 | RM_DATA(currentState).errorState = eRemesherErrorDebug; 53 | return; 54 | } 55 | } 56 | 57 | // If the triangle is degenerate, explicitly set 58 | // all indices to 0 59 | if(!isValid(indices)) 60 | { 61 | rtSetIsValid(index, false); 62 | for(uint i = 0; i < 3; i++) 63 | { 64 | RM_DATA(triangles)[3 * index + i] = 0; 65 | } 66 | return; 67 | } 68 | 69 | 70 | for(uint i = 0; i < 3; i++) 71 | { 72 | if(indices[i] == ~0u) 73 | { 74 | RM_DATA(currentState).errorState = eRemesherErrorDebug; 75 | return; 76 | } 77 | if(replaced[i]) 78 | RM_DATA(triangles)[3 * index + i] = indices[i]; 79 | rvAtomicRemoveFlag(indices[i], RM_V_ORPHAN | RM_V_UNKNOWN); 80 | } 81 | 82 | rtSetIsValid(index, true); 83 | 84 | atomicAdd(RM_DATA(currentState).triangleCount, 1); 85 | atomicMax(RM_DATA(scratchMetadata).uncompactedTriangleCount, index + 1); 86 | 87 | for(uint i = 0; i < 3; i++) 88 | { 89 | rtSetPreviousTriangle(index, i, 0); 90 | rtSetEdgeIndex(index, i, 0); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate_save_aliases_base.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_deduplicate_save_aliases_base.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_deduplicate_save_aliases_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * 11 | * Keep track of the vertex merging history: when two vertices are merged the 12 | * discarded vertex keeps the index of the preserved vertex at its index in 13 | * scratchVertexAliases 14 | * 15 | */ 16 | 17 | 18 | #undef MAIN_NAME 19 | #define MAIN_NAME remeshDeduplicateSaveAliasesBase 20 | 21 | #include "remesh_common.h" 22 | 23 | 24 | MAIN 25 | { 26 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 27 | return; 28 | 29 | uint index = getActiveVertex(gl_GlobalInvocationID.x); 30 | if(index == ~0u) 31 | return; 32 | 33 | 34 | if(hasFlag(rvGetFlags(index), RM_V_ORPHAN)) 35 | return; 36 | 37 | uint h = rvGetHashIndex(index); 38 | if(h == RM_H_NOT_FOUND) 39 | { 40 | RM_DATA(currentState).errorState = eRemesherErrorVertexHashNotFound; 41 | return; 42 | } 43 | uint dedupIndex = rhGetStoredIndex(h); 44 | if(dedupIndex == ~0u) 45 | { 46 | return; 47 | } 48 | // If the vertex has been discarded in the last merge, store the index of the 49 | // vertex surviving the merge 50 | if(dedupIndex != index) 51 | { 52 | if(RM_DATA(scratchVertexAliases)[index] == ~0u) 53 | RM_DATA(scratchVertexAliases)[index] = dedupIndex; 54 | else 55 | { 56 | // Do nothing, keep the existing alias for bookkeeping 57 | } 58 | } 59 | else 60 | { 61 | // Make sure the selected vertex is currently used in the mesh 62 | // FIXME: redundant test (see construction in deduplicate_base) 63 | if(RM_DATA(scratchVertexAliases)[index] != ~0u) 64 | RM_DATA(currentState).errorState = eRemesherErrorDebug; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_edge_cost_distribute.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | #extension GL_EXT_shader_explicit_arithmetic_types_int32 : enable 15 | #extension GL_EXT_shader_atomic_int64 : enable 16 | 17 | 18 | #include "remesh_edge_cost_distribute.h" 19 | 20 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_edge_list.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_edge_list.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_edge_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * First pass of the edge list builder: for each edge we add it to the hash map 11 | * if it has a chance of becoming a collapse candidate 12 | * 13 | */ 14 | 15 | 16 | #undef MAIN_NAME 17 | #define MAIN_NAME remeshEdgeList 18 | 19 | #include "remesh_common.h" 20 | 21 | 22 | uvec2 getEdge(uint i, uvec3 indices) 23 | { 24 | switch(i) 25 | { 26 | case 0: 27 | return indices.xy; 28 | case 1: 29 | return indices.xz; 30 | case 2: 31 | return indices.zy; 32 | } 33 | } 34 | 35 | 36 | MAIN 37 | { 38 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 39 | return; 40 | 41 | uint index = uint(gl_GlobalInvocationID.x); 42 | 43 | if(index >= RM_DATA(scratchMetadata).uncompactedTriangleCount) 44 | return; 45 | 46 | if(!rtGetIsValid(index)) 47 | return; 48 | 49 | 50 | uvec3 indices = siGetDedupTriangle(index); 51 | 52 | bvec3 hasNewEdge = bvec3(false); 53 | uvec3 hashIndices = uvec3(RM_H_NOT_SET); 54 | uint addedEdges = 0; 55 | for(uint i = 0; i < 3; i++) 56 | { 57 | uvec2 edge = getEdge(i, indices); 58 | uint h = hashEdgeIndex(edge); 59 | const uint checksum = hashEdgeChecksum(edge); 60 | bool found = false; 61 | for(uint j = 0; j < 1000; j++) 62 | { 63 | uint r = rhAtomicCompSwapChecksum(h, 0, checksum); 64 | 65 | if(r == 0) // If empty, this edge is new, add it to the list 66 | { 67 | hasNewEdge[i] = true; 68 | 69 | addedEdges++; 70 | found = true; 71 | break; 72 | } 73 | if(r != checksum) // Collision, rehash and restart 74 | { 75 | h = rehashIndex(h); 76 | } 77 | else // Edge already exists, stop searching 78 | { 79 | found = true; 80 | break; 81 | } 82 | } 83 | 84 | if(found) 85 | { 86 | rhAtomicIncRefCounter(h); 87 | hashIndices[i] = h; 88 | } 89 | else 90 | { 91 | hashIndices[i] = RM_H_NOT_FOUND; 92 | RM_DATA(currentState).errorState = eRemesherErrorEdgeHashNotFound; 93 | return; 94 | } 95 | } 96 | 97 | for(uint i = 0; i < 3; i++) 98 | siSetHashIndex(3 * index + i, hashIndices[i]); 99 | 100 | 101 | if(addedEdges > 0) 102 | { 103 | uint edgeIndex = atomicAdd(RM_DATA(scratchMetadata).edgeCount, addedEdges); 104 | 105 | if(edgeIndex >= RM_CONSTANTS.edgeListSize) 106 | { 107 | RM_DATA(currentState).errorState = eRemesherErrorOutOfEdgeStorage; 108 | return; 109 | } 110 | uint currentEdge = 0; 111 | for(uint i = 0; i < 3; i++) 112 | { 113 | if(hasNewEdge[i]) 114 | { 115 | uvec2 edge = getEdge(i, indices); 116 | reSetVertices(edgeIndex + currentEdge, edge); 117 | rhSetStoredIndex(hashIndices[i], edgeIndex + currentEdge); 118 | currentEdge++; 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_edge_list_finalize.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | #extension GL_EXT_shader_atomic_float:enable 15 | 16 | #include "remesh_edge_list_finalize.h" 17 | 18 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_edge_list_finalize.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * Finalize the edge list by assigning the unique edge indices to the triangles 11 | * Also uses the reference counter of the edges to further determine their status 12 | * 13 | */ 14 | 15 | 16 | #undef MAIN_NAME 17 | #define MAIN_NAME remeshEdgeListFinalize 18 | 19 | #include "remesh_common.h" 20 | 21 | // Mark the vertices on the mesh edge as being on a discontinuity 22 | void markBorderTriangleEdges(RM_DATA_ARG uvec2 edgeIndices, uvec3 triangleIndices) 23 | { 24 | // Find the vertex that is not on the edge 25 | uint nonEdgeVertex; 26 | for(uint i = 0; i < 3; i++) 27 | { 28 | if(triangleIndices[i] != edgeIndices.x && triangleIndices[i] != edgeIndices.y) 29 | { 30 | nonEdgeVertex = triangleIndices[i]; 31 | break; 32 | } 33 | } 34 | // For decimation the edge vertices are marked as being on a discontinuity, 35 | // which will still allow for a collapse along the edge. For relaxation the 36 | // edge vertices are fixed 37 | uint borderFlags = RM_V_MARKED | RM_V_EDGE; 38 | 39 | // If the vertex not lying on the edge is on a discontinuity the edge 40 | // vertices are then at the intersection of the attribute discontinuity and 41 | // the mesh edge. The vertices are then marked as fixed 42 | if(hasFlag(rvGetFlags(nonEdgeVertex), RM_V_MARKED)) 43 | { 44 | borderFlags |= RM_V_FIXED; 45 | } 46 | rvAtomicAddFlag(edgeIndices.x, borderFlags); 47 | rvAtomicAddFlag(edgeIndices.y, borderFlags); 48 | } 49 | 50 | 51 | // Compute the area covered by the triangle in UV space 52 | float getUVArea(RM_DATA_ARG uint triIndex) 53 | { 54 | uvec3 indices; 55 | vec2 texCoord[3]; 56 | for(uint i = 0; i < 3; i++) 57 | { 58 | indices[i] = RM_DATA(triangles)[3 * triIndex + i]; 59 | texCoord[i] = cvGetOutputTexCoord(indices[i]); 60 | } 61 | 62 | return 0.5f 63 | * abs(texCoord[0].x * (texCoord[1].y - texCoord[2].y) + texCoord[1].x * (texCoord[2].y - texCoord[0].y) 64 | + texCoord[2].x * (texCoord[0].y - texCoord[1].y)); 65 | } 66 | 67 | 68 | MAIN 69 | { 70 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 71 | return; 72 | 73 | uint index = uint(gl_GlobalInvocationID.x); 74 | 75 | if(index >= RM_DATA(scratchMetadata).uncompactedTriangleCount) 76 | return; 77 | 78 | if(!rtGetIsValid(index)) 79 | return; 80 | uvec3 indices = siGetDedupTriangle(index); 81 | 82 | uvec2 edges[3]; 83 | edges[0] = uvec2(indices[0], indices[1]); 84 | edges[1] = uvec2(indices[0], indices[2]); 85 | edges[2] = uvec2(indices[2], indices[1]); 86 | 87 | for(uint i = 0; i < 3; i++) 88 | { 89 | edges[i] = uvec2(min(edges[i].x, edges[i].y), max(edges[i].x, edges[i].y)); 90 | } 91 | 92 | 93 | uvec3 edgeIndices = uvec3(~0u); 94 | 95 | for(uint i = 0; i < 3; i++) 96 | { 97 | uint h = siGetHashIndex(3 * index + i); 98 | if(h == RM_H_NOT_SET) 99 | { 100 | continue; 101 | } 102 | edgeIndices[i] = rhGetStoredIndex(h); 103 | 104 | { 105 | // If the decimation has a limit on how many original vertices are represented within a single 106 | // simplified triangle, store the maximum original vertex counter of the adjacent triangles 107 | // in the edge cost. The cost itself will be deduced in the edge cost propagation kernel 108 | if(RM_CONSTANTS.clampedSubdLevel != ~0u) 109 | reAtomicMaxCost(edgeIndices[i], float(rtGetAggregatedCounter(index))); 110 | // If a target displacement map resolution is provided, we compute the number of texels covered 111 | // by the resulting triangle, and store the maximum texel count in the edge cost for later use 112 | if(RM_CONSTANTS.dispMapResolution.x > 0 && RM_CONSTANTS.dispMapResolution.y > 0) 113 | { 114 | float uvArea = getUVArea(RM_DATA_VAL index); 115 | float texelCount = uvArea * (RM_CONSTANTS.dispMapResolution.x * RM_CONSTANTS.dispMapResolution.y); 116 | if(RM_CONSTANTS.clampedSubdLevel != ~0u) 117 | reAtomicMaxCost(edgeIndices[i], texelCount); 118 | } 119 | } 120 | 121 | // If an edge is referenced only once it lies on the edge of the mesh. We then mark the corresponding vertices 122 | // as being on a discontinuity 123 | if(rhGetRefCounter(h) == 1) 124 | { 125 | markBorderTriangleEdges(RM_DATA_VAL edges[i], indices); 126 | } 127 | if(rhGetRefCounter(h) > 2) 128 | { 129 | rvAtomicAddFlag(edges[i].x, RM_V_DEBUG); 130 | rvAtomicAddFlag(edges[i].y, RM_V_DEBUG); 131 | } 132 | } 133 | 134 | rtSetEdgeIndices(index, edgeIndices); 135 | 136 | rtResetAggregatedCounter(index); 137 | } 138 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_generate_subdivision_info.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | #version 450 12 | #extension GL_GOOGLE_include_directive : enable 13 | 14 | #include "remesh_generate_subdivision_info.h" 15 | 16 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_generate_subdivision_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * 11 | * Generate displacement micromesh-related subdivision level based on 12 | * the number of original vertices represented by each simplified triangle 13 | * 14 | */ 15 | 16 | 17 | #undef MAIN_NAME 18 | #define MAIN_NAME remeshGenerateSubdivisionInfo 19 | 20 | #include "remesh_common.h" 21 | 22 | // Compute the subdivision level corresponding to a given vertex count 23 | uint subdivisionLevel(uint vertexCount) 24 | { 25 | uint targetCount = vertexCount; 26 | uint l = 1; 27 | while(true) 28 | { 29 | if(targetCount < subdivLevelGetVertexCount(l)) 30 | return l; 31 | l++; 32 | } 33 | } 34 | 35 | // For a given triangle and edge, find the other triangle adjacent to that edge 36 | uint findOtherTriangle(RM_DATA_ARG uint triIndex, uint edgeIndex) 37 | { 38 | uint vertexIndex = reGetVertices(edgeIndex).x; 39 | 40 | uint encodedLastTriangleIndex = rvGetLastTriangle(vertexIndex); 41 | while(encodedLastTriangleIndex != ~0u) 42 | { 43 | uvec2 lastTri = decodePreviousTriangle(encodedLastTriangleIndex); 44 | uint lastTriangleIndex = lastTri.x; 45 | if(lastTriangleIndex != triIndex) 46 | { 47 | uvec3 triEdges = rtGetEdgeIndices(lastTriangleIndex); 48 | for(uint i = 0; i < 3; i++) 49 | { 50 | if(triEdges[i] == edgeIndex && rtGetIsValid(lastTriangleIndex)) 51 | return lastTriangleIndex; 52 | } 53 | } 54 | uint localVertexIndex = lastTri.y; 55 | encodedLastTriangleIndex = rtGetPreviousTriangle(lastTriangleIndex, localVertexIndex); 56 | } 57 | return ~0u; 58 | } 59 | 60 | // Find the other triangles adjacent to the edges of the triangle at triIndex 61 | uvec3 findNeighbors(RM_DATA_ARG uint triIndex) 62 | { 63 | uvec3 edges = rtGetEdgeIndices(triIndex); 64 | uvec3 res = uvec3(~0u); 65 | for(uint i = 0; i < 3; i++) 66 | { 67 | uint edgeIndex = edges[i]; 68 | res[i] = findOtherTriangle(RM_DATA_VAL triIndex, edgeIndex); 69 | } 70 | 71 | return res; 72 | } 73 | 74 | // Find the maximum subdivision level of the immediate neighbors of the triangle at index 75 | uint findMaxNeighborSubd(RM_DATA_ARG uint index) 76 | { 77 | uvec3 neighbors = findNeighbors(RM_DATA_VAL index); 78 | uint subd = 0; 79 | for(uint i = 0; i < 3; i++) 80 | { 81 | if(neighbors[i] != ~0u) 82 | subd = max(subd, rmmGetCurrentSubdivisionLevel(neighbors[i])); 83 | } 84 | return subd; 85 | } 86 | 87 | // The edges of the remesher are ordered with vertices (0,1), (0,2), (1,2) but 88 | // the meshops::DeviceMesh expects edge flags ordered (0,1), (1,2), (0,2) 89 | uint reorderEdgeFlags(uint flags) 90 | { 91 | uint res; 92 | res = (flags & 0x1) | ((flags & 0x2) << 1) | ((flags & 0x4) >> 1); 93 | return res; 94 | } 95 | 96 | // Compute the edge flags depending on the subd level of the neighbors 97 | uint computeEdgeDecimationFlags(RM_DATA_ARG uint triIndex) 98 | { 99 | uint level = rmmGetCurrentSubdivisionLevel(triIndex); 100 | if(level == 0) 101 | return 0; 102 | uvec3 neighbors = findNeighbors(RM_DATA_VAL triIndex); 103 | uint res = 0; 104 | for(uint i = 0; i < 3; i++) 105 | { 106 | if(neighbors[i] == ~0u) 107 | continue; 108 | uint l = rmmGetCurrentSubdivisionLevel(neighbors[i]); 109 | 110 | if(l < level) 111 | res |= (1 << i); 112 | } 113 | return reorderEdgeFlags(res); 114 | } 115 | 116 | MAIN 117 | { 118 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 119 | return; 120 | 121 | uint index = uint(gl_GlobalInvocationID.x); 122 | 123 | if(RM_CONSTANTS.iterationIndex > 12) 124 | { 125 | RM_DATA(currentState).errorState = eRemesherErrorInvalidConstantValue; 126 | return; 127 | } 128 | 129 | 130 | if(RM_CONSTANTS.iterationIndex < 12) 131 | { 132 | if(index >= RM_DATA(scratchMetadata).uncompactedTriangleCount) 133 | return; 134 | 135 | if(!rtGetIsValid(index)) 136 | { 137 | if(RM_CONSTANTS.iterationIndex == 0) 138 | { 139 | rmmSetTargetSubdivisionLevel(index, 0); 140 | rmmSetCurrentSubdivisionLevel(index, 0); 141 | } 142 | return; 143 | } 144 | 145 | 146 | // First iteration, initialize the subd level per triangle based on the number of 147 | // representative vertices 148 | // FIXME: count the displacement map texels as well 149 | if(RM_CONSTANTS.iterationIndex == 0) 150 | { 151 | uint subd = min(RM_CONSTANTS.clampedSubdLevel, subdivisionLevel(rtGetAggregatedCounter(index))); 152 | rmmSetTargetSubdivisionLevel(index, subd); 153 | rmmSetCurrentSubdivisionLevel(index, 0); 154 | return; 155 | } 156 | 157 | // Final iteration, set the decimation flags for the edges of the triangles neighboring 158 | // triangles with lower subd level 159 | if(RM_CONSTANTS.iterationIndex == 11) 160 | { 161 | rmmSetDecimationFlags(index, computeEdgeDecimationFlags(RM_DATA_VAL index)); 162 | rmmCleanup(index); 163 | 164 | return; 165 | } 166 | 167 | // Get the current subd level, the maximum subd level of the neighbors, and potentially 168 | // raise the subd level to have a max difference of 1 with the neighbors 169 | uint currentSubd = rmmGetCurrentSubdivisionLevel(index); 170 | uint targetSubd = findMaxNeighborSubd(RM_DATA_VAL index); 171 | 172 | if(targetSubd > (currentSubd + 1)) 173 | { 174 | rmmSetTargetSubdivisionLevel(index, targetSubd - 1); 175 | } 176 | else 177 | { 178 | rmmSetTargetSubdivisionLevel(index, rmmGetCurrentSubdivisionLevel(index)); 179 | } 180 | } 181 | else // Iteration 12, reencode the min/max displacement bounds into actual (min, max-min) floats 182 | { 183 | if(index >= RM_CONSTANTS.vertexCount) 184 | return; 185 | 186 | rvFinalizeMinMaxDisplacement(index); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_host_device.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #ifdef __cplusplus 13 | #pragma once 14 | #include "glm/glm.hpp" 15 | 16 | #define MAIN void MAIN_NAME(const uvec3& gl_GlobalInvocationID, RemesherData* rmData) 17 | #define RM_DATA_ARG RemesherData *rmData, 18 | #define RM_DATA(x_) rmData->x_ 19 | #define RM_DATA_VAL rmData, 20 | #define RM_CONSTANTS RM_DATA(constants) 21 | #define TEXTURE(t, c) vec4(0.f) 22 | 23 | namespace micromesh 24 | { 25 | #else 26 | #define MAIN void main() 27 | #define RM_DATA_ARG 28 | #define RM_DATA(x_) x_ 29 | #define RM_DATA_VAL 30 | #define RM_CONSTANTS constants 31 | #define TEXTURE(t, c) texture(t, c) 32 | 33 | #endif 34 | 35 | #ifndef REMESHER_HOST_DEVICE_H 36 | #define REMESHER_HOST_DEVICE_H 37 | 38 | #define REMESHER_BLOCK_SIZE 256 39 | 40 | #define REMESHER_TANGENT_INDEX 4 41 | 42 | // clang-format off 43 | #ifdef __cplusplus // GLSL Type 44 | using uint = uint32_t; 45 | using uvec2 = glm::uvec2; 46 | using uvec3 = glm::uvec3; 47 | using ivec2 = glm::ivec2; 48 | using mat4 = glm::mat4; 49 | #endif 50 | 51 | 52 | #ifdef __cplusplus 53 | #define REF(t_) t_ & 54 | #else 55 | #define REF(t_) inout t_ 56 | #endif 57 | 58 | 59 | #define RM_H_NOT_FOUND ~0u 60 | #define RM_H_NOT_SET ((~0u)-1) 61 | 62 | #define RM_V_MARKED (0x1 << 0) 63 | #define RM_V_ORPHAN (0x1 << 1) 64 | #define RM_V_FIXED (0x1 << 2) 65 | #define RM_V_COPIED (0x1 << 3) 66 | #define RM_V_DOUBLE_MARKED (0x1 << 4) 67 | #define RM_V_EDGE (0x1 << 5) 68 | #define RM_V_UNKNOWN (0x1 << 6) 69 | #define RM_V_DEBUG (0x1 << 7) 70 | 71 | #ifdef __cplusplus 72 | enum RemesherMode 73 | { 74 | #else 75 | const uint 76 | #endif 77 | eDecimate = 0, 78 | eOptimizeForDisplacement = 2, 79 | eGenerateMicromeshInfo = 3 80 | #ifdef __cplusplus 81 | }; 82 | #else 83 | ; 84 | #endif 85 | 86 | 87 | #ifdef __cplusplus 88 | // typedef to have the needed sizeof 89 | // With optimized displacement direction storage 90 | // Disabled for now 91 | typedef struct { uint v[5]; } RemesherVertex; 92 | #else 93 | #define RemesherVertex uint 94 | #endif 95 | 96 | 97 | #ifdef __cplusplus 98 | // typedef to have the needed sizeof 99 | typedef struct { uint v[3]; } RemesherEdge; 100 | #else 101 | #define RemesherEdge uint 102 | #endif 103 | 104 | #ifdef __cplusplus 105 | // typedef to have the needed sizeof 106 | typedef struct { uint v[3]; } RemesherHashEntry; 107 | #else 108 | #define RemesherHashEntry uint 109 | #endif 110 | struct RemesherConstants 111 | { 112 | ivec2 dispMapResolution; 113 | 114 | uint vertexCount; 115 | uint indexCount; 116 | uint hashMapSize; 117 | uint edgeListSize; 118 | float errorThreshold; 119 | float deduplicationThreshold; 120 | 121 | uint compactionPass; 122 | float curvatureImportance; 123 | uint remeshingMode; 124 | 125 | uint iterationIndex; 126 | 127 | uint clampedSubdLevel; 128 | 129 | uint backupPositions; 130 | 131 | uint activeVertices; 132 | 133 | uint isFinalCompaction; 134 | 135 | uint maxValence; 136 | float maxImportance; 137 | 138 | uint texcoordCount; 139 | uint texcoordIndex; 140 | 141 | float directionBoundsFactor; 142 | 143 | }; 144 | 145 | 146 | 147 | #ifdef __cplusplus 148 | typedef struct { uint v[9]; } RemesherTriangle; 149 | #else 150 | #define RemesherTriangle uint 151 | #endif 152 | 153 | 154 | #define RM_MICROMESH_DISP_BOUNDS_DATA_SIZE 2 155 | #define RM_MICROMESH_DISP_DIR_DATA_SIZE 3 156 | #ifdef __cplusplus 157 | // typedef to have the needed sizeof 158 | typedef struct { int v[RM_MICROMESH_DISP_DIR_DATA_SIZE]; } RemesherMicromeshDisplacementDir; 159 | #else 160 | #define RemesherMicromeshDisplacementDir float 161 | #endif 162 | 163 | 164 | #ifdef __cplusplus 165 | // typedef to have the needed sizeof 166 | typedef struct { 167 | uint16_t decimationFlags; 168 | uint16_t subdLevel; 169 | float minDisplacement; 170 | float maxDisplacement; 171 | } RemesherMicromeshInfo; 172 | #else 173 | #define RemesherMicromeshInfo uint 174 | #endif 175 | 176 | #ifndef __cplusplus 177 | // MUST be an exact replica of micromesh::RemesherErrorState in micromesh/micromesh_displacement_remeshing.h 178 | #define eRemesherErrorNone 0x0 179 | #define eRemesherErrorVertexHashNotFound 0x1 180 | #define eRemesherErrorEdgeHashNotFound 0x2 181 | #define eRemesherErrorDebug 0x3 182 | #define eRemesherErrorOutOfEdgeStorage 0x5 183 | #define eRemesherErrorNoTriangleFound 0x6 184 | #define eRemesherErrorNoVertexHistoryFound 0x7 185 | #define eRemesherErrorInvalidConstantValue 0x8 186 | #endif 187 | 188 | struct RemesherMetadata 189 | { 190 | 191 | uint collapsedEdgesCount; 192 | 193 | uint edgeCount; 194 | 195 | uint vertexCompactionValidEntries; 196 | uint vertexCompactionCurrentInvalidEntry; 197 | uint vertexCompactionCurrentValidEntry; 198 | 199 | uint indexCompactionValidEntries; 200 | uint indexCompactionCurrentInvalidEntry; 201 | uint indexCompactionCurrentValidEntry; 202 | 203 | 204 | uint uncompactedTriangleCount; 205 | uint uncompactedVertexCount; 206 | 207 | uint activeVertices; 208 | 209 | }; 210 | 211 | // Otherwise, this struct is defined in micromesh_displacement_remeshing.h 212 | #ifndef __cplusplus 213 | // Copy of the struct defined in micromesh_displacement_remeshing.h 214 | struct RemeshingCurrentState 215 | { 216 | uint triangleCount; 217 | uint vertexCount; 218 | uint errorState; 219 | uint mergeCount; 220 | uvec4 debug; 221 | }; 222 | #endif 223 | 224 | #ifdef __cplusplus 225 | enum RemesherBindings 226 | { 227 | #else 228 | const uint 229 | #endif 230 | // User-provided data, modified in place (copy of enum gpu::GpuRemeshingResource) 231 | 232 | // main modified buffers 233 | // ------------------------- 234 | // must be pre-filled with appropriate data prior task begin 235 | // will be updated continuously during the process. 236 | // 3 x float per-vertex 237 | eGpuRemeshingMeshVertexPositionsBuffer=0, 238 | // 2 x float per-vertex 239 | eGpuRemeshingMeshVertexTexcoordsBuffer=1, 240 | // 2 x uint per-vertex 241 | eGpuRemeshingMeshVertexHashBuffer=2, 242 | // 3 x uint per-triangle 243 | eGpuRemeshingMeshTrianglesBuffer=3, 244 | // 1 x uint per-triangle (e.g. per-triangle component/material assignments etc.) 245 | // (optional `GpuRemeshing_config::useTriangleUserIDs`) 246 | eGpuRemeshingMeshTriangleUserIDsBuffer=4, 247 | 248 | // 1 x float per-vertex (optional `GpuRemeshing_config::useVertexCurvature`) 249 | eGpuRemeshingMeshVertexImportanceBuffer=5, 250 | 251 | // output buffers 252 | // ------------------------- 253 | // 254 | // 1 x uint { uint16 subdivlevel, uint16 edgeflags} per-triangle 255 | // (optional `OpRemeshing_settings::generateDisplacementInfo`, only in eDecimate mode) 256 | eGpuRemeshingMeshTriangleSubdivisionInfoBuffer=6, 257 | // 3 x float per-vertex 258 | // (optional `OpRemeshing_settings::generateDisplacementInfo`, only in eDecimate mode) 259 | eGpuRemeshingMeshVertexDirectionsBuffer=7, 260 | // 2 x float per-vertex 261 | // (optional `OpRemeshing_settings::generateDisplacementInfo`, only in eDecimate mode) 262 | eGpuRemeshingMeshVertexDirectionBoundsBuffer=8, 263 | 264 | // intermediate buffers used during process 265 | // ---------------------------------------- 266 | // 3 x uint per-vertex as below 267 | // RemeshingVertexMergeInfo { 268 | // uint32_t vertexIndexA; 269 | // uint32_t vertexIndexB; 270 | // float blendAtoB; 271 | // } 272 | eGpuRemeshingMeshVertexMergeBuffer=9, 273 | 274 | // 1 x uint per-vertex 275 | eGpuRemeshingDebugVertexBuffer=10, 276 | // 1 x uint per-triangle 277 | eGpuRemeshingDebugTriangleBuffer=11, 278 | 279 | // 1 RemeshingCurrentState struct, used for feedback 280 | eGpuRemeshingCurrentStateBuffer=12, 281 | 282 | 283 | // Scratch buffers, opaque to the user (see remesher::ScratchBuffers enum) 284 | eScratchIndexBuffer = 13, 285 | eScratchTriangles = 14, 286 | eScratchMetadata = 15, 287 | eScratchHashMap = 16, 288 | eScratchEdgeList = 17, 289 | eScratchVertices = 18, 290 | eScratchTrianglesDesc = 19, 291 | eScratchVertexAliases = 20, 292 | eScratchVertexOriginalPos = 21, 293 | eScratchActiveVertices = 23 294 | #ifdef __cplusplus 295 | , eBindingCount 296 | }; 297 | #else 298 | ; 299 | #endif 300 | 301 | #ifdef __cplusplus 302 | } // namespace micromesh 303 | #endif 304 | 305 | 306 | #endif // REMESHER_HOST_DEVICE_H -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_init_quadrics.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_init_quadrics.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_init_quadrics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * Initialize per-vertex metadata 11 | * 12 | */ 13 | 14 | 15 | #undef MAIN_NAME 16 | #define MAIN_NAME remeshInitQuadrics 17 | 18 | #include "remesh_common.h" 19 | 20 | MAIN 21 | { 22 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 23 | return; 24 | 25 | uint index = uint(gl_GlobalInvocationID.x); 26 | if(index >= RM_CONSTANTS.vertexCount) 27 | return; 28 | 29 | 30 | if(hasFlag(rvGetFlags(index), RM_V_ORPHAN)) 31 | return; 32 | 33 | // Enqueue the vertex in the list of active vertices 34 | uint activeIndex = atomicAdd(RM_DATA(scratchMetadata).activeVertices, 1); 35 | RM_DATA(scratchActiveVertices)[activeIndex] = index; 36 | 37 | // If the vertex is not already known as being orphan mark it as unknown. Its actual status will 38 | // be determined by the subsequent deduplication step 39 | if(!hasFlag(rvGetFlags(index), RM_V_ORPHAN)) 40 | rvAtomicSetFlags(index, RM_V_UNKNOWN); 41 | 42 | 43 | rvSetLastTriangle(index, ~0u); 44 | rvSetMergingWith(index, ~0u); 45 | rvSetDedupMerged(index, ~0u); 46 | rvSetAttribsHash(index, 0); 47 | rvSetHashIndex(index, RM_H_NOT_FOUND); 48 | 49 | // On the first iteration, save the location of the original vertices 50 | // for later use when estimating the min/max displacement per triangle 51 | if(RM_CONSTANTS.backupPositions == 1) 52 | { 53 | setOriginalVertex(index, getOutputVertex(index)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_link_high_low_vertices.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | 15 | #include "remesh_link_high_low_vertices.h" 16 | 17 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_link_high_low_vertices.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * 11 | * Associate the original vertices to the resulting simplified vertices 12 | * and triangles 13 | * 14 | */ 15 | 16 | 17 | #undef MAIN_NAME 18 | #define MAIN_NAME remeshLinkHighLowVertices 19 | 20 | #include "remesh_common.h" 21 | 22 | 23 | vec3 getBaryCoordDirect(vec3 verts[3], float roots, vec3 d[3], vec3 pos) 24 | { 25 | vec3 v0 = verts[0] + roots * d[0]; 26 | vec3 u = verts[1] + roots * d[1] - v0; 27 | vec3 v = verts[2] + roots * d[2] - v0; 28 | vec3 n = cross(u, v); 29 | vec3 w = pos - v0; 30 | 31 | float n2Inv = 1.f / dot(n, n); 32 | 33 | vec3 baryCoord; 34 | baryCoord.z = (dot(cross(u, w), n) * n2Inv); 35 | baryCoord.y = (dot(cross(w, v), n) * n2Inv); 36 | baryCoord.x = 1.f - baryCoord.y - baryCoord.z; 37 | return baryCoord; 38 | } 39 | 40 | 41 | // Cubic equation solver, providing only real roots 42 | // Based on Tschirnhaus-Vieta approach 43 | // https://math.stackexchange.com/questions/1908861/using-trig-identity-to-solve-a-cubic-equation 44 | vec3 cubicSolveReal(float a, float b, float c, float d) 45 | { 46 | const float notFound = FLT_MAX; 47 | 48 | if(d == 0.f) 49 | return vec3(0.f, notFound, notFound); 50 | // Handle non-cubic equations 51 | if(a == 0.f) 52 | { 53 | if(b == 0.f) 54 | { 55 | if(c == 0.f) 56 | { 57 | return vec3(notFound); 58 | } 59 | // Linear 60 | return vec3(-d / c, notFound, notFound); 61 | } 62 | else 63 | { 64 | // Quadratic 65 | float delta = c * c - 4.f * b * d; 66 | if(delta < 0.f) 67 | return vec3(notFound); 68 | delta = sqrt(delta); 69 | return vec3((-c - delta) / (2.f * a), (-c + delta) / (2.f * a), notFound); 70 | } 71 | } 72 | 73 | b /= a; 74 | c /= a; 75 | d /= a; 76 | 77 | float disc, q, r, dum1, s, t, term1, r13; 78 | q = (3.f * c - (b * b)) / 9.f; 79 | r = -(27.f * d) + b * (9.f * c - 2.f * (b * b)); 80 | r /= 54.f; 81 | disc = q * q * q + r * r; 82 | 83 | term1 = (b / 3.f); 84 | if(disc > 0.f) 85 | { // one root real, two are complex 86 | float sqrtDisc = sqrt(disc); 87 | s = r + sqrtDisc; 88 | s = ((s < 0.f) ? -pow(-s, (1.f / 3.f)) : pow(s, (1.f / 3.f))); 89 | t = r - sqrtDisc; 90 | t = ((t < 0.f) ? -pow(-t, (1.f / 3.f)) : pow(t, (1.f / 3.f))); 91 | return vec3(-term1 + s + t, notFound, notFound); 92 | } 93 | 94 | // The remaining options are all real 95 | if(disc == 0.f) 96 | { // All roots real, at least two are equal. 97 | r13 = ((r < 0.f) ? -pow(-r, (1.f / 3.f)) : pow(r, (1.f / 3.f))); 98 | return vec3(-term1 + 2.f * r13, -(r13 + term1), notFound); 99 | } 100 | // Only option left is that all roots are real and unequal (to get here, q < 0) 101 | q = -q; 102 | dum1 = q * q * q; 103 | dum1 = acos(r / sqrt(dum1)); 104 | r13 = 2.f * sqrt(q); 105 | vec3 res; 106 | res.x = -term1 + r13 * cos(dum1 / 3.f); 107 | res.y = -term1 + r13 * cos((dum1 + 2.f * M_PI) / 3.f); 108 | res.z = -term1 + r13 * cos((dum1 + 4.f * M_PI) / 3.f); 109 | return res; 110 | } 111 | 112 | float det(vec3 v0, vec3 v1, vec3 v2) 113 | { 114 | return v0[0] * (v1[1] * v2[2] - v1[2] * v2[1]) - v0[1] * (v1[0] * v2[2] - v1[2] * v2[0]) 115 | + v0[2] * (v1[0] * v2[1] - v1[1] * v2[0]); 116 | } 117 | 118 | // Find a (real-valued) parameter t defining a plane within the prismoid {p, d} that contains point q 119 | // Algorithm by Andrea Maggiordomo, U. Milan, 2022 120 | // FIXME: link to publication when available 121 | vec3 findT(vec3 v[3], vec3 dir[3], vec3 q) 122 | { 123 | vec3 f1 = dir[1] - dir[0]; 124 | vec3 f2 = dir[2] - dir[0]; 125 | 126 | vec3 p = v[0] - q; 127 | vec3 e1 = v[1] - v[0]; 128 | vec3 e2 = v[2] - v[0]; 129 | 130 | float a = det(dir[0], f1, f2); 131 | float b = det(dir[0], f1, e2) + det(dir[0], e1, f2) + det(p, f1, f2); 132 | float c = det(p, e1, f2) + det(p, f1, e2) + det(dir[0], e1, e2); 133 | float d = det(p, e1, e2); 134 | 135 | return cubicSolveReal(a, b, c, d); 136 | } 137 | 138 | // Return the element of v with the smallest absolute value 139 | float minAbs(vec3 v) 140 | { 141 | if(abs(v[0]) < abs(v[1]) && abs(v[0]) < abs(v[2])) 142 | return v[0]; 143 | if(abs(v[1]) < abs(v[2])) 144 | return v[1]; 145 | return v[2]; 146 | } 147 | 148 | 149 | float getDisplacement(vec3 v[3], vec3 d[3], vec3 q, out vec3 bary) 150 | { 151 | vec3 roots = findT(v, d, q); 152 | 153 | vec3 validRoots = vec3(FLT_MAX); 154 | uint validRootCount = 0; 155 | 156 | for(uint i = 0; i < 3; i++) 157 | { 158 | if(roots[i] == FLT_MAX) 159 | continue; 160 | 161 | bary = getBaryCoordDirect(v, roots[i], d, q); 162 | if(bary == clamp(bary, vec3(0.f), vec3(1.f))) 163 | { 164 | // Identify the roots yielding a point within the prismoid 165 | validRoots[validRootCount++] = roots[i]; 166 | } 167 | } 168 | // Return the valid root that results in the minimum absolute displacement 169 | if(validRootCount > 0) 170 | return minAbs(validRoots); 171 | 172 | return uintBitsToFloat(~0u); 173 | } 174 | 175 | vec2 computeDisplacement(RM_DATA_ARG uint triIndex, vec3 position, out vec3 bary) 176 | { 177 | vec3 triVerts[3]; 178 | vec3 triNormals[3]; 179 | uvec3 dedupTriangle = siGetDedupTriangle(triIndex); 180 | for(uint i = 0; i < 3; i++) 181 | { 182 | getOutputPosNormal(dedupTriangle[i], triVerts[i], triNormals[i]); 183 | // If the decimated vertex has the same position as the original vertex, 184 | // the displacement is null 185 | if(triVerts[i] == position) 186 | return vec2(0.f, 0.f); 187 | } 188 | 189 | float analyticalDisp = getDisplacement(triVerts, triNormals, position, bary); 190 | 191 | return vec2(analyticalDisp); 192 | } 193 | 194 | bool isSignificantDisplacement(uint triangle, float disp) 195 | { 196 | return true; 197 | vec3 verts[3]; 198 | uvec3 dedupTriangle = siGetDedupTriangle(triangle); 199 | for(uint i = 0; i < 3; i++) 200 | { 201 | verts[i] = getOutputVertex(dedupTriangle[i]); 202 | } 203 | vec3 l; 204 | for(uint i = 0; i < 3; i++) 205 | { 206 | l[i] = length(verts[i] - verts[(i + 1) % 3]); 207 | } 208 | float minL = min(l[0], min(l[1], l[2])); 209 | return (abs(disp) > 2.f * minL / 100.f); 210 | } 211 | 212 | void propagateToAdjacentTriangles(RM_DATA_ARG uint vertexIndex, vec3 position, uint originalIndex) 213 | { 214 | uint encodedLastTriangleIndex = rvGetLastTriangle(vertexIndex); 215 | 216 | uint bestTriangle = ~0u; 217 | float bestScore = 1e34f; 218 | vec2 bestDisp; 219 | vec3 bestBary; 220 | 221 | float originalMaxEdgeLength = getOriginalMaxEdgeLength(originalIndex); 222 | 223 | while(encodedLastTriangleIndex != ~0u) 224 | { 225 | uvec2 lastTri = decodePreviousTriangle(encodedLastTriangleIndex); 226 | uint lastTriangleIndex = lastTri.x; 227 | vec3 bary; 228 | vec2 disp = computeDisplacement(RM_DATA_VAL lastTriangleIndex, position, bary); 229 | 230 | if(floatBitsToUint(disp.x) != ~0u) 231 | { 232 | // Extend the computed displacement by the maximum length of the edges 233 | // adjacent to the original vertex. This allows the bounds estimate to 234 | // encompass not only the original vertices, but also the surface of the 235 | // original triangles that may lie across the boundaries of the decimated 236 | // triangles 237 | disp += vec2(-originalMaxEdgeLength, originalMaxEdgeLength); 238 | float score = abs(disp.x); 239 | if(score < bestScore) 240 | { 241 | bestScore = score; 242 | bestDisp = disp; 243 | bestTriangle = lastTriangleIndex; 244 | bestBary = bary; 245 | } 246 | } 247 | uint localVertexIndex = lastTri.y; 248 | encodedLastTriangleIndex = rtGetPreviousTriangle(lastTriangleIndex, localVertexIndex); 249 | } 250 | 251 | if(bestTriangle != ~0u) 252 | { 253 | if(isSignificantDisplacement(bestTriangle, bestDisp.x)) 254 | rtAtomicAddAggregatedCounter(bestTriangle, 1); 255 | rtAtomicMinMaxDisplacement(bestTriangle, vec2(bestDisp)); 256 | } 257 | } 258 | 259 | float sqLength(vec3 v) 260 | { 261 | return dot(v, v); 262 | } 263 | 264 | float computeSqMaxEdgeLengthTriangle(uint triangleIndex) 265 | { 266 | uvec3 indices = siGetDedupTriangle(triangleIndex); 267 | vec3 v[3]; 268 | for(uint i = 0; i < 3; i++) 269 | { 270 | v[i] = getOriginalVertex(indices[i]); 271 | } 272 | 273 | float d0 = sqLength(v[1] - v[0]); 274 | float d1 = sqLength(v[2] - v[0]); 275 | float d2 = sqLength(v[1] - v[2]); 276 | 277 | return max(d0, max(d1, d2)); 278 | } 279 | 280 | float computeMaxOriginalEdgeLength(uint index) 281 | { 282 | uint encodedLastTriangleIndex = rvGetLastTriangle(index); 283 | 284 | float maxEdgeLength = 0.f; 285 | 286 | while(encodedLastTriangleIndex != ~0u) 287 | { 288 | uvec2 lastTri = decodePreviousTriangle(encodedLastTriangleIndex); 289 | uint lastTriangleIndex = lastTri.x; 290 | 291 | maxEdgeLength = max(maxEdgeLength, computeSqMaxEdgeLengthTriangle(lastTriangleIndex)); 292 | 293 | 294 | uint localVertexIndex = lastTri.y; 295 | encodedLastTriangleIndex = rtGetPreviousTriangle(lastTriangleIndex, localVertexIndex); 296 | } 297 | return sqrt(maxEdgeLength); 298 | } 299 | 300 | MAIN 301 | { 302 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 303 | return; 304 | 305 | uint index = uint(gl_GlobalInvocationID.x); 306 | if(index >= RM_CONSTANTS.vertexCount) 307 | return; 308 | 309 | vec3 originalPosition = getOriginalVertex(index); 310 | 311 | if(RM_CONSTANTS.backupPositions == 1) 312 | { 313 | setOriginalMaxEdgeLength(index, computeMaxOriginalEdgeLength(index)); 314 | } 315 | 316 | uint currentIndex = index; 317 | bool isActive = (RM_DATA(scratchVertexAliases)[currentIndex] == ~0u); 318 | 319 | while(RM_DATA(scratchVertexAliases)[currentIndex] != ~0u) 320 | { 321 | currentIndex = RM_DATA(scratchVertexAliases)[currentIndex]; 322 | } 323 | if(!isActive) 324 | { 325 | // Flatten the collapse history 326 | RM_DATA(scratchVertexAliases)[index] = currentIndex; 327 | } 328 | else 329 | { 330 | return; 331 | } 332 | if(currentIndex == ~0u) 333 | { 334 | RM_DATA(currentState).errorState = eRemesherErrorNoTriangleFound; 335 | return; 336 | } 337 | // Uncomment for external display of the original vertices linked to the decimated vertex 338 | //vertexDebug[index] = currentIndex; 339 | propagateToAdjacentTriangles(RM_DATA_VAL currentIndex, originalPosition, index); 340 | } 341 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_quadrics.comp.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | 12 | #version 450 13 | #extension GL_GOOGLE_include_directive : enable 14 | #extension GL_EXT_shader_atomic_float : enable 15 | 16 | #include "remesh_quadrics.h" 17 | 18 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/shaders/remesh_quadrics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | * 10 | * Set base values on the vertices. If QSLIM-type methods would be used, 11 | * the quadrics initialization would go here 12 | */ 13 | 14 | #undef MAIN_NAME 15 | #define MAIN_NAME remeshQuadrics 16 | 17 | 18 | #include "remesh_common.h" 19 | 20 | MAIN 21 | { 22 | if(RM_DATA(currentState).errorState != eRemesherErrorNone) 23 | return; 24 | 25 | uint index = uint(gl_GlobalInvocationID.x); 26 | if(index >= RM_DATA(scratchMetadata).uncompactedTriangleCount) 27 | return; 28 | 29 | if(!rtGetIsValid(index)) 30 | { 31 | return; 32 | } 33 | uvec3 indices = siGetDedupTriangle(index); 34 | 35 | RM_DATA(scratchTriangleDescs)[index] = ~uint64_t(0); 36 | rtSetEdgeIndices(index, uvec3(~0u)); 37 | 38 | for(uint i = 0; i < 3; i++) 39 | { 40 | rtSetPreviousTriangle(index, i, rvAtomicExchLastTriangle(indices[i], encodePreviousTriangle(index, i))); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/src/remeshing_cpu.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * NVIDIA CORPORATION and its licensors retain all intellectual property 5 | * and proprietary rights in and to this software, related documentation 6 | * and any modifications thereto. Any use, reproduction, disclosure or 7 | * distribution of this software and related documentation without an express 8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 9 | */ 10 | 11 | #include 12 | 13 | namespace micromesh 14 | { 15 | MICROMESH_API uint32_t MICROMESH_CALL micromeshOpRemeshingGetScratchCount(OpContext ctx, const OpRemeshing_settings* settings) 16 | { 17 | return 0; 18 | } 19 | 20 | MICROMESH_API Result MICROMESH_CALL micromeshOpRemeshingBegin(OpContext ctx, 21 | const OpRemeshing_settings* settings, 22 | const OpRemeshing_input* input, 23 | OpRemeshing_output* output) 24 | { 25 | return Result::eFailure; 26 | } 27 | 28 | MICROMESH_API Result MICROMESH_CALL micromeshOpRemeshingEnd(OpContext ctx, const OpRemeshing_input* input, OpRemeshing_output* output) 29 | { 30 | return Result::eFailure; 31 | } 32 | } // namespace micromesh -------------------------------------------------------------------------------- /micromesh_displacement_remeshing/src/remeshing_internal.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. 4 | * 5 | * NVIDIA CORPORATION and its licensors retain all intellectual property 6 | * and proprietary rights in and to this software, related documentation 7 | * and any modifications thereto. Any use, reproduction, disclosure or 8 | * distribution of this software and related documentation without an express 9 | * license agreement from NVIDIA CORPORATION is strictly prohibited. 10 | */ 11 | 12 | // Internal interface for the block encoder and decoder. Ported from the 13 | // old displacement encoder. 14 | // The idea is that this exposes the interface the mesh encoder needs to be 15 | // efficient: 11-bit UNORM values in u-major layout, all API preconditions 16 | // already checked. Data transfer and conversion operations are left up to the 17 | // higher-level API functions. Ideally, these would be templated so we could 18 | // get good code generation. 19 | // This also exposes the functions that are unit-tested. 20 | 21 | #pragma once 22 | #include "vulkan/vulkan_core.h" 23 | #include "micromesh/micromesh_displacement_remeshing.h" 24 | #include "shaders/remesh_host_device.h" 25 | #include "shaders/remesh_bindings.h" 26 | #include 27 | #include 28 | 29 | namespace micromesh 30 | { 31 | namespace remesher 32 | { 33 | enum ScratchBuffers 34 | { 35 | eScratchIndexBuffer, 36 | eScratchTriangles, 37 | eScratchMetadata, 38 | eScratchHashMap, 39 | eScratchEdgeList, 40 | eScratchVertices, 41 | eScratchTrianglesDesc, 42 | eScratchVertexAliases, 43 | eScratchOriginalPos, 44 | eScratchTriangleSubdivisionInfoBackupBuffer, 45 | eScratchActiveVertices, 46 | eScratchBufferCount 47 | }; 48 | 49 | 50 | enum Pipelines 51 | { 52 | eInitializeQuadrics, 53 | eComputePerVertexQuadrics, 54 | eBuildEdgeList, 55 | eFinalizeEdgeList, 56 | eCollapseFlag, 57 | eCollapsePropagate, 58 | eCollapseResolve, 59 | eCompactIndices, 60 | eCompactVertices, 61 | eDeduplicate, 62 | eDeduplicateFinalize, 63 | eEdgeCostDistribute, 64 | eDeduplicateBase, 65 | eDeduplicateBaseFinalize, 66 | eClearHashMap, 67 | eClearEdgeList, 68 | eLinkHighLowVertices, 69 | eDeduplicateBaseSaveAliases, 70 | eApplyMinDisplacement, 71 | eGenerateSubdivisionInfo, 72 | eClearMicromeshData, 73 | ePipelineCount 74 | }; 75 | 76 | enum ReadbackBuffers 77 | { 78 | eReadbackMetadata = 0, 79 | eReadbackCurrentState = 1, 80 | eReadbackCount 81 | }; 82 | 83 | enum PipelineLayouts 84 | { 85 | eInternalPipelines, 86 | ePipelineLayoutCount 87 | }; 88 | 89 | enum DecimationState 90 | { 91 | eDecimation, 92 | eVertexOptimization, 93 | eMicromeshGeneration, 94 | eFinalCompaction, 95 | eFinalReadback 96 | }; 97 | 98 | } // namespace remesher 99 | 100 | namespace gpu 101 | { 102 | struct GpuRemeshing_s 103 | { 104 | GpuRemeshing_config config; 105 | std::array descriptorRanges; 106 | std::array pipelineInfo; 107 | std::array pipelineNames; 108 | 109 | std::array userDescriptorRanges; 110 | std::array userPipelineInfo; 111 | 112 | 113 | RemesherConstants constants; 114 | OpRemeshing_settings settings; 115 | uint32_t currentIndexCount; 116 | }; 117 | 118 | struct GpuRemeshingTask_s 119 | { 120 | uint32_t iterationIndex; 121 | uint32_t lastTriangleCount; 122 | uint32_t stableSince; 123 | bool decimationStarted; 124 | remesher::DecimationState decimationState; 125 | }; 126 | 127 | } // namespace gpu 128 | 129 | 130 | } // namespace micromesh --------------------------------------------------------------------------------