├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── data ├── mesh │ └── teapot_smooth.obj ├── screenshot.jpg └── texture │ ├── directx.png │ ├── metal.png │ ├── opengl.png │ └── vulkan.png └── src ├── .clang-format ├── CMakeLists.txt ├── main.cpp └── shader ├── decal_project_fs.glsl ├── depth_fs.glsl ├── depth_vs.glsl ├── fullscreen_triangle_vs.glsl ├── mesh_fs.glsl ├── mesh_vs.glsl ├── texture_init_fs.glsl ├── uv_space_vs.glsl └── visualize_albedo_fs.glsl /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | 13 | # Compiled Dynamic libraries 14 | *.so 15 | *.dylib 16 | *.dll 17 | 18 | # Fortran module files 19 | *.mod 20 | *.smod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | 33 | external/ 34 | external/* 35 | external/dwSampleFramwork 36 | bin/ 37 | bin/* 38 | build/ 39 | build/* 40 | lib/ 41 | lib/* 42 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/embree"] 2 | path = external/embree 3 | url = https://github.com/embree/embree.git 4 | [submodule "external/dwSampleFramework"] 5 | path = external/dwSampleFramework 6 | url = https://github.com/diharaw/dwSampleFramework.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8 FATAL_ERROR) 2 | 3 | project("TextureSpaceDecals") 4 | 5 | IF(APPLE) 6 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14") 7 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") 8 | ENDIF() 9 | 10 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib") 11 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib") 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) 13 | 14 | add_subdirectory(external/embree) 15 | add_subdirectory(external/dwSampleFramework) 16 | 17 | set(EMBREE_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/external/embree/include/embree3") 18 | 19 | include_directories("${DW_SAMPLE_FRAMEWORK_INCLUDES}" 20 | "${EMBREE_INCLUDE_DIRS}") 21 | 22 | add_subdirectory(src) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dihara Wijetunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Texture Space Decals 2 | 3 | An OpenGL sample application demonstrating a method for baking decals to textures. Suitable for character customisation and other scenarios that require persistent decals. 4 | 5 | ![TextureSpaceDecals](data/screenshot.jpg) 6 | 7 | ## Dependencies 8 | * [dwSampleFramework](https://github.com/diharaw/dwSampleFramework) 9 | * [embree](https://https://github.com/embree/embree) 10 | 11 | ## License 12 | ``` 13 | Copyright (c) 2019 Dihara Wijetunga 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 16 | associated documentation files (the "Software"), to deal in the Software without restriction, 17 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 19 | subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in all copies or substantial 22 | portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 25 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 26 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 27 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 28 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | ``` 30 | -------------------------------------------------------------------------------- /data/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/texture-space-decals/d69f66d2c42b38e48d6e08c4325160901c72087f/data/screenshot.jpg -------------------------------------------------------------------------------- /data/texture/directx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/texture-space-decals/d69f66d2c42b38e48d6e08c4325160901c72087f/data/texture/directx.png -------------------------------------------------------------------------------- /data/texture/metal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/texture-space-decals/d69f66d2c42b38e48d6e08c4325160901c72087f/data/texture/metal.png -------------------------------------------------------------------------------- /data/texture/opengl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/texture-space-decals/d69f66d2c42b38e48d6e08c4325160901c72087f/data/texture/opengl.png -------------------------------------------------------------------------------- /data/texture/vulkan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/texture-space-decals/d69f66d2c42b38e48d6e08c4325160901c72087f/data/texture/vulkan.png -------------------------------------------------------------------------------- /src/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: WebKit 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveAssignments: 'true' 5 | AlignConsecutiveDeclarations: 'true' 6 | AlignEscapedNewlines: Left 7 | AlignOperands: 'false' 8 | AlignTrailingComments: 'true' 9 | AllowAllParametersOfDeclarationOnNextLine: 'true' 10 | AllowShortBlocksOnASingleLine: 'true' 11 | AllowShortCaseLabelsOnASingleLine: 'true' 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: 'true' 14 | AllowShortLoopsOnASingleLine: 'true' 15 | AlwaysBreakAfterReturnType: None 16 | AlwaysBreakBeforeMultilineStrings: 'false' 17 | AlwaysBreakTemplateDeclarations: 'true' 18 | BinPackArguments: 'false' 19 | BinPackParameters: 'false' 20 | BreakBeforeBraces: Allman 21 | BreakBeforeInheritanceComma: 'false' 22 | BreakBeforeTernaryOperators: 'false' 23 | BreakConstructorInitializers: AfterColon 24 | BreakStringLiterals: 'true' 25 | CompactNamespaces: 'true' 26 | ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' 27 | Cpp11BracedListStyle: 'false' 28 | FixNamespaceComments: 'true' 29 | IncludeBlocks: Regroup 30 | IndentCaseLabels: 'true' 31 | IndentPPDirectives: AfterHash 32 | IndentWrappedFunctionNames: 'true' 33 | KeepEmptyLinesAtTheStartOfBlocks: 'false' 34 | Language: Cpp 35 | NamespaceIndentation: None 36 | PointerAlignment: Left 37 | ReflowComments: 'true' 38 | SortIncludes: 'false' 39 | SortUsingDeclarations: 'true' 40 | SpaceAfterCStyleCast: 'false' 41 | SpaceBeforeAssignmentOperators: 'true' 42 | SpaceBeforeParens: ControlStatements 43 | SpaceInEmptyParentheses: 'false' 44 | SpacesInAngles: 'false' 45 | SpacesInCStyleCastParentheses: 'false' 46 | SpacesInContainerLiterals: 'true' 47 | SpacesInParentheses: 'false' 48 | SpacesInSquareBrackets: 'false' 49 | 50 | ... 51 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8 FATAL_ERROR) 2 | 3 | find_program(CLANG_FORMAT_EXE NAMES "clang-format" DOC "Path to clang-format executable") 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | 8 | set(TSD_SOURCES ${PROJECT_SOURCE_DIR}/src/main.cpp) 9 | 10 | file(GLOB_RECURSE SHADER_SOURCES ${PROJECT_SOURCE_DIR}/src/*.glsl) 11 | 12 | if(APPLE) 13 | add_executable(TextureSpaceDecals MACOSX_BUNDLE ${TSD_SOURCES} ${SHADER_SOURCES} ${ASSET_SOURCES}) 14 | set(MACOSX_BUNDLE_BUNDLE_NAME "Texture Space Decals") 15 | set_source_files_properties(${SHADER_SOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/shader) 16 | set_source_files_properties(${ASSET_SOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) 17 | else() 18 | add_executable(TextureSpaceDecals ${TSD_SOURCES}) 19 | endif() 20 | 21 | target_link_libraries(TextureSpaceDecals dwSampleFramework) 22 | target_link_libraries(TextureSpaceDecals embree) 23 | 24 | if (NOT APPLE) 25 | add_custom_command(TARGET TextureSpaceDecals POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/src/shader $/shader) 26 | add_custom_command(TARGET TextureSpaceDecals POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/mesh $/mesh) 27 | add_custom_command(TARGET TextureSpaceDecals POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/texture $/texture) 28 | endif() 29 | 30 | if(CLANG_FORMAT_EXE) 31 | add_custom_target(TextureSpaceDecals-clang-format COMMAND ${CLANG_FORMAT_EXE} -i -style=file ${TSD_SOURCES} ${SHADER_SOURCES}) 32 | endif() 33 | 34 | set_property(TARGET TextureSpaceDecals PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin/$(Configuration)") -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #define _USE_MATH_DEFINES 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define CAMERA_FAR_PLANE 1000.0f 20 | #define PROJECTOR_BACK_OFF_DISTANCE 10.0f; 21 | #define ALBEDO_TEXTURE_SIZE 4096 22 | #define DEPTH_TEXTURE_SIZE 512 23 | 24 | struct GlobalUniforms 25 | { 26 | DW_ALIGNED(16) 27 | glm::mat4 view_proj; 28 | DW_ALIGNED(16) 29 | glm::mat4 light_view_proj; 30 | DW_ALIGNED(16) 31 | glm::vec4 cam_pos; 32 | }; 33 | 34 | class TextureSpaceDecals : public dw::Application 35 | { 36 | protected: 37 | // ----------------------------------------------------------------------------------------------------------------------------------- 38 | 39 | bool init(int argc, const char* argv[]) override 40 | { 41 | // Create GPU resources. 42 | if (!create_shaders()) 43 | return false; 44 | 45 | if (!create_uniform_buffer()) 46 | return false; 47 | 48 | // Load scene. 49 | if (!load_scene()) 50 | return false; 51 | 52 | if (!load_decals()) 53 | return false; 54 | 55 | if (!initialize_embree()) 56 | return false; 57 | 58 | create_framebuffers(); 59 | 60 | // Create camera. 61 | create_camera(); 62 | 63 | m_transform = glm::mat4(1.0f); 64 | 65 | init_texture(); 66 | 67 | return true; 68 | } 69 | 70 | // ----------------------------------------------------------------------------------------------------------------------------------- 71 | 72 | void update(double delta) override 73 | { 74 | // Update camera. 75 | update_camera(); 76 | 77 | update_global_uniforms(m_global_uniforms); 78 | 79 | if (m_debug_gui) 80 | ui(); 81 | 82 | if (m_requires_update) 83 | { 84 | m_requires_update = false; 85 | render_depth_map(); 86 | apply_decals(); 87 | m_albedo_texture->generate_mipmaps(); 88 | } 89 | 90 | render_lit_scene(); 91 | 92 | if (m_visualize_albedo_map) 93 | visualize_albedo_map(); 94 | 95 | if (m_hit_distance != INFINITY) 96 | { 97 | if (m_visualize_hit_point) 98 | m_debug_draw.sphere(2.0f, m_hit_pos, glm::vec3(1.0f, 0.0f, 0.0f)); 99 | 100 | if (m_visualize_projection_frustum) 101 | m_debug_draw.frustum(m_global_uniforms.light_view_proj, glm::vec3(0.0f, 1.0f, 0.0f)); 102 | 103 | if (m_visualize_hit_point || m_visualize_projection_frustum) 104 | m_debug_draw.render(nullptr, m_width, m_height, m_global_uniforms.view_proj); 105 | } 106 | } 107 | 108 | // ----------------------------------------------------------------------------------------------------------------------------------- 109 | 110 | void shutdown() override 111 | { 112 | rtcReleaseGeometry(m_embree_triangle_mesh); 113 | rtcReleaseScene(m_embree_scene); 114 | rtcReleaseDevice(m_embree_device); 115 | 116 | dw::Mesh::unload(m_mesh); 117 | } 118 | 119 | // ----------------------------------------------------------------------------------------------------------------------------------- 120 | 121 | void window_resized(int width, int height) override 122 | { 123 | // Override window resized method to update camera projection. 124 | m_main_camera->update_projection(60.0f, 0.1f, CAMERA_FAR_PLANE, float(m_width) / float(m_height)); 125 | 126 | create_framebuffers(); 127 | } 128 | 129 | // ----------------------------------------------------------------------------------------------------------------------------------- 130 | 131 | void key_pressed(int code) override 132 | { 133 | // Handle forward movement. 134 | if (code == GLFW_KEY_W) 135 | m_heading_speed = m_camera_speed; 136 | else if (code == GLFW_KEY_S) 137 | m_heading_speed = -m_camera_speed; 138 | 139 | // Handle sideways movement. 140 | if (code == GLFW_KEY_A) 141 | m_sideways_speed = -m_camera_speed; 142 | else if (code == GLFW_KEY_D) 143 | m_sideways_speed = m_camera_speed; 144 | 145 | if (code == GLFW_KEY_SPACE) 146 | m_mouse_look = true; 147 | 148 | if (code == GLFW_KEY_G) 149 | m_debug_gui = !m_debug_gui; 150 | } 151 | 152 | // ----------------------------------------------------------------------------------------------------------------------------------- 153 | 154 | void key_released(int code) override 155 | { 156 | // Handle forward movement. 157 | if (code == GLFW_KEY_W || code == GLFW_KEY_S) 158 | m_heading_speed = 0.0f; 159 | 160 | // Handle sideways movement. 161 | if (code == GLFW_KEY_A || code == GLFW_KEY_D) 162 | m_sideways_speed = 0.0f; 163 | 164 | if (code == GLFW_KEY_SPACE) 165 | m_mouse_look = false; 166 | } 167 | 168 | // ----------------------------------------------------------------------------------------------------------------------------------- 169 | 170 | void mouse_pressed(int code) override 171 | { 172 | if (code == GLFW_MOUSE_BUTTON_LEFT) 173 | { 174 | double xpos, ypos; 175 | glfwGetCursorPos(m_window, &xpos, &ypos); 176 | 177 | glm::vec4 ndc_pos = glm::vec4((2.0f * float(xpos)) / float(m_width) - 1.0f, 1.0 - (2.0f * float(ypos)) / float(m_height), -1.0f, 1.0f); 178 | glm::vec4 view_coords = glm::inverse(m_main_camera->m_projection) * ndc_pos; 179 | glm::vec4 world_coords = glm::inverse(m_main_camera->m_view) * glm::vec4(view_coords.x, view_coords.y, -1.0f, 0.0f); 180 | 181 | glm::vec3 ray_dir = glm::normalize(glm::vec3(world_coords)); 182 | 183 | RTCRayHit rayhit; 184 | 185 | rayhit.ray.dir_x = ray_dir.x; 186 | rayhit.ray.dir_y = ray_dir.y; 187 | rayhit.ray.dir_z = ray_dir.z; 188 | 189 | rayhit.ray.org_x = m_main_camera->m_position.x; 190 | rayhit.ray.org_y = m_main_camera->m_position.y; 191 | rayhit.ray.org_z = m_main_camera->m_position.z; 192 | 193 | rayhit.ray.tnear = 0; 194 | rayhit.ray.tfar = INFINITY; 195 | rayhit.ray.mask = 0; 196 | rayhit.ray.flags = 0; 197 | rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID; 198 | rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID; 199 | 200 | rtcIntersect1(m_embree_scene, &m_embree_intersect_context, &rayhit); 201 | 202 | if (rayhit.ray.tfar != INFINITY) 203 | { 204 | m_hit_pos = m_main_camera->m_position + ray_dir * rayhit.ray.tfar; 205 | m_hit_normal = glm::vec3(rayhit.hit.Ng_x, rayhit.hit.Ng_y, rayhit.hit.Ng_z); 206 | m_hit_distance = rayhit.ray.tfar; 207 | 208 | m_projector_pos = m_hit_pos + m_hit_normal * PROJECTOR_BACK_OFF_DISTANCE; 209 | m_projector_dir = -m_hit_normal; 210 | 211 | m_requires_update = true; 212 | 213 | if (m_randomize_decals) 214 | { 215 | std::random_device rd; 216 | std::mt19937 gen(rd()); 217 | std::uniform_real_distribution scale_dis(5.0, 20.0); 218 | std::uniform_real_distribution rotation_dis(-90.0, 90.0); 219 | std::uniform_int_distribution<> index_dis(0, 3); 220 | 221 | m_selected_decal = index_dis(gen); 222 | m_projector_size = scale_dis(gen); 223 | m_projector_rotation = rotation_dis(gen); 224 | } 225 | } 226 | else 227 | rayhit.ray.tfar = INFINITY; 228 | } 229 | 230 | // Enable mouse look. 231 | if (code == GLFW_MOUSE_BUTTON_RIGHT) 232 | m_mouse_look = true; 233 | } 234 | 235 | // ----------------------------------------------------------------------------------------------------------------------------------- 236 | 237 | void mouse_released(int code) override 238 | { 239 | // Disable mouse look. 240 | if (code == GLFW_MOUSE_BUTTON_RIGHT) 241 | m_mouse_look = false; 242 | } 243 | 244 | // ----------------------------------------------------------------------------------------------------------------------------------- 245 | 246 | protected: 247 | // ----------------------------------------------------------------------------------------------------------------------------------- 248 | 249 | dw::AppSettings intial_app_settings() override 250 | { 251 | dw::AppSettings settings; 252 | 253 | settings.resizable = true; 254 | settings.maximized = false; 255 | settings.refresh_rate = 60; 256 | settings.major_ver = 4; 257 | settings.width = 1920; 258 | settings.height = 1080; 259 | settings.title = "Texture Space Decals (c) 2019 Dihara Wijetunga"; 260 | 261 | return settings; 262 | } 263 | 264 | // ----------------------------------------------------------------------------------------------------------------------------------- 265 | 266 | private: 267 | // ----------------------------------------------------------------------------------------------------------------------------------- 268 | 269 | void init_texture() 270 | { 271 | if (m_enable_conservative_raster) 272 | { 273 | if (GLAD_GL_NV_conservative_raster) 274 | glEnable(GL_CONSERVATIVE_RASTERIZATION_NV); 275 | else if (GLAD_GL_INTEL_conservative_rasterization) 276 | glEnable(GL_INTEL_conservative_rasterization); 277 | } 278 | 279 | glDisable(GL_DEPTH_TEST); 280 | glDisable(GL_BLEND); 281 | 282 | glDisable(GL_CULL_FACE); 283 | 284 | m_albedo_fbo->bind(); 285 | 286 | glViewport(0, 0, ALBEDO_TEXTURE_SIZE, ALBEDO_TEXTURE_SIZE); 287 | 288 | glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 289 | glClear(GL_COLOR_BUFFER_BIT); 290 | 291 | // Bind shader program. 292 | m_texture_init_program->use(); 293 | 294 | // Bind uniform buffers. 295 | m_global_ubo->bind_base(0); 296 | 297 | m_texture_init_program->set_uniform("u_Model", m_transform); 298 | 299 | // Bind vertex array. 300 | m_mesh->mesh_vertex_array()->bind(); 301 | 302 | dw::SubMesh* submeshes = m_mesh->sub_meshes(); 303 | 304 | for (uint32_t i = 0; i < m_mesh->sub_mesh_count(); i++) 305 | { 306 | dw::SubMesh& submesh = submeshes[i]; 307 | 308 | // Issue draw call. 309 | glDrawElementsBaseVertex(GL_TRIANGLES, submesh.index_count, GL_UNSIGNED_INT, (void*)(sizeof(unsigned int) * submesh.base_index), submesh.base_vertex); 310 | } 311 | 312 | if (m_enable_conservative_raster) 313 | { 314 | if (GLAD_GL_NV_conservative_raster) 315 | glDisable(GL_CONSERVATIVE_RASTERIZATION_NV); 316 | else if (GLAD_GL_INTEL_conservative_rasterization) 317 | glDisable(GL_INTEL_conservative_rasterization); 318 | } 319 | 320 | m_albedo_texture->generate_mipmaps(); 321 | } 322 | 323 | // ----------------------------------------------------------------------------------------------------------------------------------- 324 | 325 | void apply_decals() 326 | { 327 | if (m_enable_conservative_raster) 328 | { 329 | if (GLAD_GL_NV_conservative_raster) 330 | glEnable(GL_CONSERVATIVE_RASTERIZATION_NV); 331 | else if (GLAD_GL_INTEL_conservative_rasterization) 332 | glEnable(GL_INTEL_conservative_rasterization); 333 | } 334 | 335 | glDisable(GL_DEPTH_TEST); 336 | glEnable(GL_BLEND); 337 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 338 | 339 | glDisable(GL_CULL_FACE); 340 | 341 | m_albedo_fbo->bind(); 342 | 343 | glViewport(0, 0, ALBEDO_TEXTURE_SIZE, ALBEDO_TEXTURE_SIZE); 344 | 345 | // Bind shader program. 346 | m_decal_program->use(); 347 | 348 | // Bind uniform buffers. 349 | m_global_ubo->bind_base(0); 350 | 351 | m_decal_program->set_uniform("u_Model", m_transform); 352 | 353 | // Bind vertex array. 354 | m_mesh->mesh_vertex_array()->bind(); 355 | 356 | dw::SubMesh* submeshes = m_mesh->sub_meshes(); 357 | 358 | for (uint32_t i = 0; i < m_mesh->sub_mesh_count(); i++) 359 | { 360 | dw::SubMesh& submesh = submeshes[i]; 361 | 362 | if (m_decal_program->set_uniform("s_Decal", 0)) 363 | m_decal_textures[m_selected_decal]->bind(0); 364 | 365 | if (m_decal_program->set_uniform("s_Depth", 1)) 366 | m_depth_texture->bind(1); 367 | 368 | // Issue draw call. 369 | glDrawElementsBaseVertex(GL_TRIANGLES, submesh.index_count, GL_UNSIGNED_INT, (void*)(sizeof(unsigned int) * submesh.base_index), submesh.base_vertex); 370 | } 371 | 372 | glDisable(GL_BLEND); 373 | 374 | if (m_enable_conservative_raster) 375 | { 376 | if (GLAD_GL_NV_conservative_raster) 377 | glDisable(GL_CONSERVATIVE_RASTERIZATION_NV); 378 | else if (GLAD_GL_INTEL_conservative_rasterization) 379 | glDisable(GL_INTEL_conservative_rasterization); 380 | } 381 | } 382 | 383 | // ----------------------------------------------------------------------------------------------------------------------------------- 384 | 385 | void render_depth_map() 386 | { 387 | render_scene(m_depth_fbo.get(), m_depth_program, 0, 0, DEPTH_TEXTURE_SIZE, DEPTH_TEXTURE_SIZE, GL_BACK); 388 | } 389 | 390 | // ----------------------------------------------------------------------------------------------------------------------------------- 391 | 392 | void render_lit_scene() 393 | { 394 | render_scene(nullptr, m_mesh_program, 0, 0, m_width, m_height, GL_BACK); 395 | } 396 | 397 | // ----------------------------------------------------------------------------------------------------------------------------------- 398 | 399 | void visualize_albedo_map() 400 | { 401 | glDisable(GL_DEPTH_TEST); 402 | glDisable(GL_CULL_FACE); 403 | glDisable(GL_BLEND); 404 | 405 | glViewport(0, 0, 512, 512); 406 | 407 | // Bind shader program. 408 | m_visualize_program->use(); 409 | 410 | if (m_visualize_program->set_uniform("s_Texture", 0)) 411 | m_albedo_texture->bind(0); 412 | 413 | // Render fullscreen triangle 414 | glDrawArrays(GL_TRIANGLES, 0, 3); 415 | } 416 | 417 | // ----------------------------------------------------------------------------------------------------------------------------------- 418 | 419 | bool create_shaders() 420 | { 421 | { 422 | // Create general shaders 423 | m_uv_space_vs = std::unique_ptr(dw::Shader::create_from_file(GL_VERTEX_SHADER, "shader/uv_space_vs.glsl")); 424 | m_texture_init_fs = std::unique_ptr(dw::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/texture_init_fs.glsl")); 425 | m_decal_project_fs = std::unique_ptr(dw::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/decal_project_fs.glsl")); 426 | m_mesh_vs = std::unique_ptr(dw::Shader::create_from_file(GL_VERTEX_SHADER, "shader/mesh_vs.glsl")); 427 | m_mesh_fs = std::unique_ptr(dw::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/mesh_fs.glsl")); 428 | m_triangle_vs = std::unique_ptr(dw::Shader::create_from_file(GL_VERTEX_SHADER, "shader/fullscreen_triangle_vs.glsl")); 429 | m_visualize_fs = std::unique_ptr(dw::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/visualize_albedo_fs.glsl")); 430 | m_depth_vs = std::unique_ptr(dw::Shader::create_from_file(GL_VERTEX_SHADER, "shader/depth_vs.glsl")); 431 | m_depth_fs = std::unique_ptr(dw::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/depth_fs.glsl")); 432 | 433 | { 434 | if (!m_uv_space_vs || !m_decal_project_fs) 435 | { 436 | DW_LOG_FATAL("Failed to create Shaders"); 437 | return false; 438 | } 439 | 440 | // Create general shader program 441 | dw::Shader* shaders[] = { m_uv_space_vs.get(), m_decal_project_fs.get() }; 442 | m_decal_program = std::make_unique(2, shaders); 443 | 444 | if (!m_decal_program) 445 | { 446 | DW_LOG_FATAL("Failed to create Shader Program"); 447 | return false; 448 | } 449 | 450 | m_decal_program->uniform_block_binding("GlobalUniforms", 0); 451 | } 452 | 453 | { 454 | if (!m_uv_space_vs || !m_texture_init_fs) 455 | { 456 | DW_LOG_FATAL("Failed to create Shaders"); 457 | return false; 458 | } 459 | 460 | // Create general shader program 461 | dw::Shader* shaders[] = { m_uv_space_vs.get(), m_texture_init_fs.get() }; 462 | m_texture_init_program = std::make_unique(2, shaders); 463 | 464 | if (!m_texture_init_program) 465 | { 466 | DW_LOG_FATAL("Failed to create Shader Program"); 467 | return false; 468 | } 469 | 470 | m_texture_init_program->uniform_block_binding("GlobalUniforms", 0); 471 | } 472 | 473 | { 474 | if (!m_depth_vs || !m_depth_fs) 475 | { 476 | DW_LOG_FATAL("Failed to create Shaders"); 477 | return false; 478 | } 479 | 480 | // Create general shader program 481 | dw::Shader* shaders[] = { m_depth_vs.get(), m_depth_fs.get() }; 482 | m_depth_program = std::make_unique(2, shaders); 483 | 484 | if (!m_texture_init_program) 485 | { 486 | DW_LOG_FATAL("Failed to create Shader Program"); 487 | return false; 488 | } 489 | 490 | m_depth_program->uniform_block_binding("GlobalUniforms", 0); 491 | } 492 | 493 | { 494 | if (!m_mesh_vs || !m_mesh_fs) 495 | { 496 | DW_LOG_FATAL("Failed to create Shaders"); 497 | return false; 498 | } 499 | 500 | // Create general shader program 501 | dw::Shader* shaders[] = { m_mesh_vs.get(), m_mesh_fs.get() }; 502 | m_mesh_program = std::make_unique(2, shaders); 503 | 504 | if (!m_mesh_program) 505 | { 506 | DW_LOG_FATAL("Failed to create Shader Program"); 507 | return false; 508 | } 509 | 510 | m_mesh_program->uniform_block_binding("GlobalUniforms", 0); 511 | } 512 | 513 | { 514 | if (!m_triangle_vs || !m_visualize_fs) 515 | { 516 | DW_LOG_FATAL("Failed to create Shaders"); 517 | return false; 518 | } 519 | 520 | // Create general shader program 521 | dw::Shader* shaders[] = { m_triangle_vs.get(), m_visualize_fs.get() }; 522 | m_visualize_program = std::make_unique(2, shaders); 523 | 524 | if (!m_visualize_program) 525 | { 526 | DW_LOG_FATAL("Failed to create Shader Program"); 527 | return false; 528 | } 529 | 530 | m_visualize_program->uniform_block_binding("GlobalUniforms", 0); 531 | } 532 | } 533 | 534 | return true; 535 | } 536 | 537 | // ----------------------------------------------------------------------------------------------------------------------------------- 538 | 539 | void create_framebuffers() 540 | { 541 | m_albedo_texture = std::make_unique(ALBEDO_TEXTURE_SIZE, ALBEDO_TEXTURE_SIZE, 1, 1, 1, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE); 542 | 543 | m_albedo_texture->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 544 | m_albedo_texture->set_min_filter(GL_LINEAR_MIPMAP_LINEAR); 545 | m_albedo_texture->set_mag_filter(GL_LINEAR); 546 | 547 | m_albedo_fbo = std::make_unique(); 548 | 549 | m_albedo_fbo->attach_render_target(0, m_albedo_texture.get(), 0, 0); 550 | 551 | m_depth_texture = std::make_unique(DEPTH_TEXTURE_SIZE, DEPTH_TEXTURE_SIZE, 1, 1, 1, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_HALF_FLOAT); 552 | 553 | m_depth_texture->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 554 | 555 | m_depth_fbo = std::make_unique(); 556 | 557 | m_depth_fbo->attach_depth_stencil_target(m_depth_texture.get(), 0, 0); 558 | } 559 | 560 | // ----------------------------------------------------------------------------------------------------------------------------------- 561 | 562 | bool create_uniform_buffer() 563 | { 564 | // Create uniform buffer for global data 565 | m_global_ubo = std::make_unique(GL_DYNAMIC_DRAW, sizeof(GlobalUniforms)); 566 | 567 | return true; 568 | } 569 | 570 | // ----------------------------------------------------------------------------------------------------------------------------------- 571 | 572 | void ui() 573 | { 574 | if (!m_randomize_decals) 575 | { 576 | ImGui::DragFloat("Decal Rotation", &m_projector_rotation, 1.0f, -180.0f, 180.0f); 577 | ImGui::DragFloat("Decal Size", &m_projector_size, 1.0f, 0.1f, 20.0f); 578 | 579 | const char* listbox_items[] = { "OpenGL", "Vulkan", "DirectX", "Metal" }; 580 | ImGui::ListBox("Selected Decal", &m_selected_decal, listbox_items, IM_ARRAYSIZE(listbox_items), 4); 581 | } 582 | 583 | ImGui::Checkbox("Randomize Decals", &m_randomize_decals); 584 | ImGui::Checkbox("Visualize Projector Frustum", &m_visualize_projection_frustum); 585 | ImGui::Checkbox("Visualize Hit Point", &m_visualize_hit_point); 586 | ImGui::Checkbox("Visualize Albedo Map", &m_visualize_albedo_map); 587 | ImGui::Checkbox("Conservative Rasterization", &m_enable_conservative_raster); 588 | 589 | if (ImGui::Button("Clear Texture")) 590 | init_texture(); 591 | 592 | if (!GLAD_GL_NV_conservative_raster && !GLAD_GL_INTEL_conservative_rasterization) 593 | { 594 | ImGui::Separator(); 595 | ImGui::Text("Note: Conservative Rasterization not supported on this GPU."); 596 | } 597 | } 598 | 599 | // ----------------------------------------------------------------------------------------------------------------------------------- 600 | 601 | bool load_scene() 602 | { 603 | m_mesh = dw::Mesh::load("mesh/teapot_smooth.obj"); 604 | 605 | if (!m_mesh) 606 | { 607 | DW_LOG_FATAL("Failed to load mesh!"); 608 | return false; 609 | } 610 | 611 | return true; 612 | } 613 | 614 | // ----------------------------------------------------------------------------------------------------------------------------------- 615 | 616 | bool load_decals() 617 | { 618 | m_decal_textures.resize(4); 619 | m_decal_textures[0] = std::unique_ptr(dw::Texture2D::create_from_files("texture/opengl.png", true)); 620 | m_decal_textures[0]->set_min_filter(GL_LINEAR_MIPMAP_LINEAR); 621 | m_decal_textures[0]->set_mag_filter(GL_LINEAR); 622 | 623 | m_decal_textures[1] = std::unique_ptr(dw::Texture2D::create_from_files("texture/vulkan.png", true)); 624 | m_decal_textures[1]->set_min_filter(GL_LINEAR_MIPMAP_LINEAR); 625 | m_decal_textures[1]->set_mag_filter(GL_LINEAR); 626 | 627 | m_decal_textures[2] = std::unique_ptr(dw::Texture2D::create_from_files("texture/directx.png", true)); 628 | m_decal_textures[2]->set_min_filter(GL_LINEAR_MIPMAP_LINEAR); 629 | m_decal_textures[2]->set_mag_filter(GL_LINEAR); 630 | 631 | m_decal_textures[3] = std::unique_ptr(dw::Texture2D::create_from_files("texture/metal.png", true)); 632 | m_decal_textures[3]->set_min_filter(GL_LINEAR_MIPMAP_LINEAR); 633 | m_decal_textures[3]->set_mag_filter(GL_LINEAR); 634 | 635 | return true; 636 | } 637 | 638 | // ----------------------------------------------------------------------------------------------------------------------------------- 639 | 640 | bool initialize_embree() 641 | { 642 | m_embree_device = rtcNewDevice(nullptr); 643 | 644 | RTCError embree_error = rtcGetDeviceError(m_embree_device); 645 | 646 | if (embree_error == RTC_ERROR_UNSUPPORTED_CPU) 647 | throw std::runtime_error("Your CPU does not meet the minimum requirements for embree"); 648 | else if (embree_error != RTC_ERROR_NONE) 649 | throw std::runtime_error("Failed to initialize embree!"); 650 | 651 | m_embree_scene = rtcNewScene(m_embree_device); 652 | 653 | m_embree_triangle_mesh = rtcNewGeometry(m_embree_device, RTC_GEOMETRY_TYPE_TRIANGLE); 654 | 655 | std::vector vertices(m_mesh->vertex_count()); 656 | std::vector indices(m_mesh->index_count()); 657 | uint32_t idx = 0; 658 | dw::Vertex* vertex_ptr = m_mesh->vertices(); 659 | uint32_t* index_ptr = m_mesh->indices(); 660 | 661 | for (int i = 0; i < m_mesh->vertex_count(); i++) 662 | vertices[i] = vertex_ptr[i].position; 663 | 664 | for (int i = 0; i < m_mesh->sub_mesh_count(); i++) 665 | { 666 | dw::SubMesh& submesh = m_mesh->sub_meshes()[i]; 667 | 668 | for (int j = submesh.base_index; j < (submesh.base_index + submesh.index_count); j++) 669 | indices[idx++] = submesh.base_vertex + index_ptr[j]; 670 | } 671 | 672 | void* data = rtcSetNewGeometryBuffer(m_embree_triangle_mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(glm::vec3), m_mesh->vertex_count()); 673 | memcpy(data, vertices.data(), vertices.size() * sizeof(glm::vec3)); 674 | 675 | data = rtcSetNewGeometryBuffer(m_embree_triangle_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, 3 * sizeof(uint32_t), m_mesh->index_count() / 3); 676 | memcpy(data, indices.data(), indices.size() * sizeof(uint32_t)); 677 | 678 | rtcCommitGeometry(m_embree_triangle_mesh); 679 | rtcAttachGeometry(m_embree_scene, m_embree_triangle_mesh); 680 | rtcCommitScene(m_embree_scene); 681 | 682 | rtcInitIntersectContext(&m_embree_intersect_context); 683 | 684 | return true; 685 | } 686 | 687 | // ----------------------------------------------------------------------------------------------------------------------------------- 688 | 689 | void create_camera() 690 | { 691 | m_main_camera = std::make_unique(60.0f, 0.1f, CAMERA_FAR_PLANE, float(m_width) / float(m_height), glm::vec3(150.0f, 20.0f, 0.0f), glm::vec3(-1.0f, 0.0, 0.0f)); 692 | m_main_camera->set_rotatation_delta(glm::vec3(0.0f, -90.0f, 0.0f)); 693 | m_main_camera->update(); 694 | } 695 | 696 | // ----------------------------------------------------------------------------------------------------------------------------------- 697 | 698 | void render_mesh(dw::Mesh* mesh, glm::mat4 model, std::unique_ptr& program) 699 | { 700 | program->set_uniform("u_Model", model); 701 | 702 | // Bind vertex array. 703 | mesh->mesh_vertex_array()->bind(); 704 | 705 | dw::SubMesh* submeshes = mesh->sub_meshes(); 706 | 707 | for (uint32_t i = 0; i < mesh->sub_mesh_count(); i++) 708 | { 709 | dw::SubMesh& submesh = submeshes[i]; 710 | 711 | if (program->set_uniform("s_Texture", 0)) 712 | m_albedo_texture->bind(0); 713 | 714 | // Issue draw call. 715 | glDrawElementsBaseVertex(GL_TRIANGLES, submesh.index_count, GL_UNSIGNED_INT, (void*)(sizeof(unsigned int) * submesh.base_index), submesh.base_vertex); 716 | } 717 | } 718 | 719 | // ----------------------------------------------------------------------------------------------------------------------------------- 720 | 721 | void render_scene(dw::Framebuffer* fbo, std::unique_ptr& program, int x, int y, int w, int h, GLenum cull_face, bool clear = true) 722 | { 723 | glEnable(GL_DEPTH_TEST); 724 | glDisable(GL_BLEND); 725 | 726 | if (cull_face == GL_NONE) 727 | glDisable(GL_CULL_FACE); 728 | else 729 | { 730 | glEnable(GL_CULL_FACE); 731 | glCullFace(cull_face); 732 | } 733 | 734 | if (fbo) 735 | fbo->bind(); 736 | else 737 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 738 | 739 | glViewport(x, y, w, h); 740 | 741 | if (clear) 742 | { 743 | glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 744 | glClearDepth(1.0); 745 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 746 | } 747 | 748 | // Bind shader program. 749 | program->use(); 750 | 751 | // Bind uniform buffers. 752 | m_global_ubo->bind_base(0); 753 | 754 | // Draw scene. 755 | render_mesh(m_mesh, m_transform, program); 756 | } 757 | 758 | // ----------------------------------------------------------------------------------------------------------------------------------- 759 | 760 | void update_global_uniforms(const GlobalUniforms& global) 761 | { 762 | void* ptr = m_global_ubo->map(GL_WRITE_ONLY); 763 | memcpy(ptr, &global, sizeof(GlobalUniforms)); 764 | m_global_ubo->unmap(); 765 | } 766 | 767 | // ----------------------------------------------------------------------------------------------------------------------------------- 768 | 769 | void update_transforms(dw::Camera* camera) 770 | { 771 | // Update camera matrices. 772 | m_global_uniforms.view_proj = camera->m_projection * camera->m_view; 773 | m_global_uniforms.cam_pos = glm::vec4(camera->m_position, 0.0f); 774 | 775 | glm::mat4 rotate = glm::mat4(1.0f); 776 | 777 | rotate = glm::rotate(rotate, glm::radians(m_projector_rotation), m_projector_dir); 778 | 779 | glm::vec4 rotated_axis = rotate * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f); 780 | 781 | float ratio = float(m_decal_textures[m_selected_decal]->height()) / float(m_decal_textures[m_selected_decal]->width()); 782 | float proportionate_height = m_projector_size * ratio; 783 | 784 | m_projector_view = glm::lookAt(m_projector_pos, m_hit_pos, glm::vec3(rotated_axis)); 785 | m_projector_proj = glm::ortho(-m_projector_size, m_projector_size, -proportionate_height, proportionate_height, 0.1f, CAMERA_FAR_PLANE); 786 | 787 | if (m_hit_distance != INFINITY) 788 | m_global_uniforms.light_view_proj = m_projector_proj * m_projector_view; 789 | } 790 | 791 | // ----------------------------------------------------------------------------------------------------------------------------------- 792 | 793 | void update_camera() 794 | { 795 | dw::Camera* current = m_main_camera.get(); 796 | 797 | float forward_delta = m_heading_speed * m_delta; 798 | float right_delta = m_sideways_speed * m_delta; 799 | 800 | current->set_translation_delta(current->m_forward, forward_delta); 801 | current->set_translation_delta(current->m_right, right_delta); 802 | 803 | m_camera_x = m_mouse_delta_x * m_camera_sensitivity; 804 | m_camera_y = m_mouse_delta_y * m_camera_sensitivity; 805 | 806 | if (m_mouse_look) 807 | { 808 | // Activate Mouse Look 809 | current->set_rotatation_delta(glm::vec3((float)(m_camera_y), 810 | (float)(m_camera_x), 811 | (float)(0.0f))); 812 | } 813 | else 814 | { 815 | current->set_rotatation_delta(glm::vec3((float)(0), 816 | (float)(0), 817 | (float)(0))); 818 | } 819 | 820 | current->update(); 821 | update_transforms(current); 822 | } 823 | 824 | // ----------------------------------------------------------------------------------------------------------------------------------- 825 | 826 | private: 827 | // General GPU resources. 828 | std::unique_ptr m_uv_space_vs; 829 | std::unique_ptr m_texture_init_fs; 830 | std::unique_ptr m_decal_project_fs; 831 | std::unique_ptr m_mesh_vs; 832 | std::unique_ptr m_mesh_fs; 833 | std::unique_ptr m_triangle_vs; 834 | std::unique_ptr m_visualize_fs; 835 | std::unique_ptr m_depth_vs; 836 | std::unique_ptr m_depth_fs; 837 | 838 | std::unique_ptr m_texture_init_program; 839 | std::unique_ptr m_decal_program; 840 | std::unique_ptr m_mesh_program; 841 | std::unique_ptr m_visualize_program; 842 | std::unique_ptr m_depth_program; 843 | 844 | std::unique_ptr m_albedo_texture; 845 | std::vector> m_decal_textures; 846 | std::unique_ptr m_depth_texture; 847 | 848 | std::unique_ptr m_albedo_fbo; 849 | std::unique_ptr m_depth_fbo; 850 | 851 | std::unique_ptr m_global_ubo; 852 | 853 | // Camera. 854 | std::unique_ptr m_main_camera; 855 | 856 | GlobalUniforms m_global_uniforms; 857 | 858 | // Scene 859 | dw::Mesh* m_mesh; 860 | glm::mat4 m_transform; 861 | 862 | // Camera controls. 863 | bool m_mouse_look = false; 864 | float m_heading_speed = 0.0f; 865 | float m_sideways_speed = 0.0f; 866 | float m_camera_sensitivity = 0.05f; 867 | float m_camera_speed = 0.02f; 868 | bool m_enable_dither = true; 869 | bool m_debug_gui = true; 870 | 871 | // Embree structure 872 | RTCDevice m_embree_device = nullptr; 873 | RTCScene m_embree_scene = nullptr; 874 | RTCGeometry m_embree_triangle_mesh = nullptr; 875 | RTCIntersectContext m_embree_intersect_context; 876 | 877 | // Last hit 878 | glm::vec3 m_hit_pos; 879 | glm::vec3 m_hit_normal; 880 | float m_hit_distance = INFINITY; 881 | 882 | // Projector 883 | glm::vec3 m_projector_pos; 884 | glm::vec3 m_projector_dir; 885 | glm::mat4 m_projector_view; 886 | glm::mat4 m_projector_proj; 887 | float m_projector_size = 10.0f; 888 | float m_projector_rotation = 0.0f; 889 | bool m_requires_update = false; 890 | 891 | // Debug 892 | bool m_visualize_albedo_map = true; 893 | bool m_visualize_projection_frustum = false; 894 | bool m_visualize_hit_point = false; 895 | bool m_enable_conservative_raster = true; 896 | bool m_randomize_decals = true; 897 | int32_t m_selected_decal = 0; 898 | 899 | // Camera orientation. 900 | float m_camera_x; 901 | float m_camera_y; 902 | }; 903 | 904 | DW_DECLARE_MAIN(TextureSpaceDecals) -------------------------------------------------------------------------------- /src/shader/decal_project_fs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUT VARIABLES ------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | in vec3 FS_IN_WorldPos; 6 | 7 | // ------------------------------------------------------------------ 8 | // OUTPUT VARIABLES ------------------------------------------------ 9 | // ------------------------------------------------------------------ 10 | 11 | out vec4 FS_OUT_Color; 12 | 13 | // ------------------------------------------------------------------ 14 | // UNIFORMS -------------------------------------------------------- 15 | // ------------------------------------------------------------------ 16 | 17 | layout(std140) uniform GlobalUniforms 18 | { 19 | mat4 view_proj; 20 | mat4 decal_view_proj; 21 | vec4 cam_pos; 22 | }; 23 | 24 | uniform sampler2D s_Decal; 25 | uniform sampler2D s_Depth; 26 | 27 | #define BIAS 0.001 28 | 29 | // ------------------------------------------------------------------ 30 | // FUNCTIONS ------------------------------------------------------- 31 | // ------------------------------------------------------------------ 32 | 33 | bool is_outside_decal_bounds(vec3 uv) 34 | { 35 | return (uv.x > 1.0 || uv.x < 0.0 || uv.y > 1.0 || uv.y < 0.0 || uv.z > 1.0 || uv.z < 0.0); 36 | } 37 | 38 | // ------------------------------------------------------------------ 39 | // MAIN ------------------------------------------------------------ 40 | // ------------------------------------------------------------------ 41 | 42 | void main(void) 43 | { 44 | // We project the world space position into the Decals coordinate space 45 | vec4 decal_space_pos = decal_view_proj * vec4(FS_IN_WorldPos, 1.0); 46 | 47 | // Rescale the values to between [0.0 - 1.0] 48 | vec3 decal_uv = decal_space_pos.xyz * 0.5 + 0.5; 49 | 50 | // Check if these coordinates are outside of UV bounds 51 | if (is_outside_decal_bounds(decal_uv)) 52 | discard; 53 | 54 | // Sample the depth from our depth texture. 55 | float compare_depth = texture(s_Depth, decal_uv.xy).r; 56 | 57 | // Compare the depth the current fragment to the depth from the depth texture (closest point from the decal projector). 58 | // If it's greater, the current fragment is NOT visible to the projector and should be discarded. 59 | if ((decal_uv.z - BIAS) > compare_depth) 60 | discard; 61 | 62 | // Sample the decal texture using the Decal UVs. 63 | FS_OUT_Color = texture(s_Decal, decal_uv.xy); 64 | } 65 | 66 | // ------------------------------------------------------------------ 67 | -------------------------------------------------------------------------------- /src/shader/depth_fs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // MAIN ------------------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | void main() 6 | { 7 | } 8 | 9 | // ------------------------------------------------------------------ 10 | -------------------------------------------------------------------------------- /src/shader/depth_vs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUT VARIABLES -------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | layout(location = 0) in vec3 VS_IN_Position; 6 | layout(location = 1) in vec2 VS_IN_Texcoord; 7 | layout(location = 2) in vec3 VS_IN_Normal; 8 | layout(location = 3) in vec3 VS_IN_Tangent; 9 | layout(location = 4) in vec3 VS_IN_Bitangent; 10 | 11 | // ------------------------------------------------------------------ 12 | // UNIFORMS --------------------------------------------------------- 13 | // ------------------------------------------------------------------ 14 | 15 | layout(std140) uniform GlobalUniforms 16 | { 17 | mat4 view_proj; 18 | mat4 decal_view_proj; 19 | vec4 cam_pos; 20 | }; 21 | 22 | uniform mat4 u_Model; 23 | 24 | // ------------------------------------------------------------------ 25 | // MAIN ------------------------------------------------------------- 26 | // ------------------------------------------------------------------ 27 | 28 | void main() 29 | { 30 | gl_Position = decal_view_proj * u_Model * vec4(VS_IN_Position, 1.0f); 31 | } 32 | 33 | // ------------------------------------------------------------------ 34 | -------------------------------------------------------------------------------- /src/shader/fullscreen_triangle_vs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // OUTPUT VARIABLES ------------------------------------------------ 3 | // ------------------------------------------------------------------ 4 | 5 | out vec2 FS_IN_TexCoord; 6 | 7 | // ------------------------------------------------------------------ 8 | // MAIN ------------------------------------------------------------ 9 | // ------------------------------------------------------------------ 10 | 11 | void main(void) 12 | { 13 | float x = -1.0 + float((gl_VertexID & 1) << 2); 14 | float y = -1.0 + float((gl_VertexID & 2) << 1); 15 | FS_IN_TexCoord.x = (x + 1.0) * 0.5; 16 | FS_IN_TexCoord.y = (y + 1.0) * 0.5; 17 | gl_Position = vec4(x, y, 0.0, 1.0); 18 | } 19 | 20 | // ------------------------------------------------------------------ 21 | -------------------------------------------------------------------------------- /src/shader/mesh_fs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // OUTPUT VARIABLES ------------------------------------------------ 3 | // ------------------------------------------------------------------ 4 | 5 | out vec3 FS_OUT_Color; 6 | 7 | // ------------------------------------------------------------------ 8 | // INPUT VARIABLES ------------------------------------------------- 9 | // ------------------------------------------------------------------ 10 | 11 | in vec3 FS_IN_WorldPos; 12 | in vec3 FS_IN_Normal; 13 | in vec2 FS_IN_TexCoord; 14 | 15 | // ------------------------------------------------------------------ 16 | // UNIFORMS --------------------------------------------------------- 17 | // ------------------------------------------------------------------ 18 | 19 | uniform sampler2D s_Texture; 20 | 21 | // ------------------------------------------------------------------ 22 | // MAIN ------------------------------------------------------------- 23 | // ------------------------------------------------------------------ 24 | 25 | void main() 26 | { 27 | vec3 light_pos = vec3(200.0, 200.0, 200.0); 28 | vec3 n = normalize(FS_IN_Normal); 29 | vec3 l = normalize(light_pos - FS_IN_WorldPos); 30 | float lambert = max(0.0f, dot(n, l)); 31 | vec3 diffuse = texture(s_Texture, FS_IN_TexCoord).xyz; 32 | vec3 ambient = diffuse * 0.03; 33 | vec3 color = diffuse * lambert + ambient; 34 | FS_OUT_Color = color; 35 | } 36 | 37 | // ------------------------------------------------------------------ 38 | -------------------------------------------------------------------------------- /src/shader/mesh_vs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUT VARIABLES -------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | layout(location = 0) in vec3 VS_IN_Position; 6 | layout(location = 1) in vec2 VS_IN_Texcoord; 7 | layout(location = 2) in vec3 VS_IN_Normal; 8 | layout(location = 3) in vec3 VS_IN_Tangent; 9 | layout(location = 4) in vec3 VS_IN_Bitangent; 10 | 11 | // ------------------------------------------------------------------ 12 | // OUTPUT VARIABLES ------------------------------------------------- 13 | // ------------------------------------------------------------------ 14 | 15 | out vec3 FS_IN_WorldPos; 16 | out vec3 FS_IN_Normal; 17 | out vec2 FS_IN_TexCoord; 18 | 19 | // ------------------------------------------------------------------ 20 | // UNIFORMS --------------------------------------------------------- 21 | // ------------------------------------------------------------------ 22 | 23 | layout(std140) uniform GlobalUniforms 24 | { 25 | mat4 view_proj; 26 | mat4 decal_view_proj; 27 | vec4 cam_pos; 28 | }; 29 | 30 | uniform mat4 u_Model; 31 | 32 | // ------------------------------------------------------------------ 33 | // MAIN ------------------------------------------------------------- 34 | // ------------------------------------------------------------------ 35 | 36 | void main() 37 | { 38 | vec4 world_pos = u_Model * vec4(VS_IN_Position, 1.0f); 39 | FS_IN_WorldPos = world_pos.xyz; 40 | FS_IN_Normal = normalize(normalize(mat3(u_Model) * VS_IN_Normal)); 41 | FS_IN_TexCoord = VS_IN_Texcoord; 42 | 43 | gl_Position = view_proj * world_pos; 44 | } 45 | 46 | // ------------------------------------------------------------------ 47 | -------------------------------------------------------------------------------- /src/shader/texture_init_fs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUT VARIABLES ------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | in vec3 FS_IN_WorldPos; 6 | 7 | // ------------------------------------------------------------------ 8 | // OUTPUT VARIABLES ------------------------------------------------ 9 | // ------------------------------------------------------------------ 10 | 11 | out vec4 FS_OUT_Color; 12 | 13 | // ------------------------------------------------------------------ 14 | // UNIFORMS -------------------------------------------------------- 15 | // ------------------------------------------------------------------ 16 | 17 | layout(std140) uniform GlobalUniforms 18 | { 19 | mat4 view_proj; 20 | mat4 decal_view_proj; 21 | vec4 cam_pos; 22 | }; 23 | 24 | // ------------------------------------------------------------------ 25 | // MAIN ------------------------------------------------------------ 26 | // ------------------------------------------------------------------ 27 | 28 | void main(void) 29 | { 30 | FS_OUT_Color = vec4(1.0); 31 | } 32 | 33 | // ------------------------------------------------------------------ 34 | -------------------------------------------------------------------------------- /src/shader/uv_space_vs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUTS VARIABLES ------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | layout(location = 0) in vec3 VS_IN_Position; 6 | layout(location = 1) in vec2 VS_IN_TexCoord; 7 | layout(location = 2) in vec3 VS_IN_Normal; 8 | layout(location = 3) in vec3 VS_IN_Tangent; 9 | layout(location = 4) in vec3 VS_IN_Bitangent; 10 | 11 | // ------------------------------------------------------------------ 12 | // OUTPUT VARIABLES ------------------------------------------------ 13 | // ------------------------------------------------------------------ 14 | 15 | out vec3 FS_IN_WorldPos; 16 | 17 | // ------------------------------------------------------------------ 18 | // UNIFORMS --------------------------------------------------------- 19 | // ------------------------------------------------------------------ 20 | 21 | layout(std140) uniform GlobalUniforms 22 | { 23 | mat4 view_proj; 24 | mat4 decal_view_proj; 25 | vec4 cam_pos; 26 | }; 27 | 28 | uniform mat4 u_Model; 29 | 30 | // ------------------------------------------------------------------ 31 | // MAIN ------------------------------------------------------------- 32 | // ------------------------------------------------------------------ 33 | 34 | void main() 35 | { 36 | vec4 world_pos = u_Model * vec4(VS_IN_Position, 1.0); 37 | FS_IN_WorldPos = world_pos.xyz; 38 | 39 | vec2 clip_space_pos = 2.0 * VS_IN_TexCoord - 1.0; 40 | 41 | gl_Position = vec4(clip_space_pos, 0.0, 1.0); 42 | } 43 | 44 | // ------------------------------------------------------------------ 45 | -------------------------------------------------------------------------------- /src/shader/visualize_albedo_fs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUT VARIABLES ------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | in vec2 FS_IN_TexCoord; 6 | 7 | // ------------------------------------------------------------------ 8 | // OUTPUT VARIABLES ------------------------------------------------ 9 | // ------------------------------------------------------------------ 10 | 11 | out vec3 FS_OUT_Color; 12 | 13 | // ------------------------------------------------------------------ 14 | // UNIFORMS -------------------------------------------------------- 15 | // ------------------------------------------------------------------ 16 | 17 | uniform sampler2D s_Texture; 18 | 19 | // ------------------------------------------------------------------ 20 | // MAIN ------------------------------------------------------------ 21 | // ------------------------------------------------------------------ 22 | 23 | void main(void) 24 | { 25 | FS_OUT_Color = texture(s_Texture, FS_IN_TexCoord).rgb; 26 | } 27 | 28 | // ------------------------------------------------------------------ 29 | --------------------------------------------------------------------------------