├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── data ├── noise │ ├── LDR_LLL1_0.png │ ├── LDR_LLL1_1.png │ ├── LDR_LLL1_2.png │ └── LDR_LLL1_3.png ├── screenshot.jpg └── texture │ ├── inscatter.raw │ ├── irradiance.raw │ └── transmittance.raw └── src ├── .clang-format ├── CMakeLists.txt ├── main.cpp └── shader ├── atmosphere.glsl ├── butterfly_cs.glsl ├── grid_non_tess_vs.glsl ├── grid_tcs.glsl ├── grid_tes.glsl ├── grid_vs.glsl ├── inversion_cs.glsl ├── normal_map_cs.glsl ├── ocean_fs.glsl ├── sky_envmap_fs.glsl ├── sky_envmap_vs.glsl ├── sky_fs.glsl ├── sky_vs.glsl ├── tilde_h0_k_cs.glsl ├── tilde_h0_t_cs.glsl ├── triangle_vs.glsl ├── twiddle_factors_cs.glsl ├── visualize_image_fs.glsl └── wireframe_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 | bin/ 36 | bin/* 37 | build/ 38 | build/* 39 | lib/ 40 | lib/* 41 | 42 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/dwSampleFramework"] 2 | path = external/dwSampleFramework 3 | url = https://github.com/diharaw/dwSampleFramework.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8 FATAL_ERROR) 2 | 3 | project("FFTOceanWaves") 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/dwSampleFramework) 15 | 16 | include_directories("${DW_SAMPLE_FRAMEWORK_INCLUDES}") 17 | 18 | add_subdirectory(src) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 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 | [![License: MIT](https://img.shields.io/packagist/l/doctrine/orm.svg)](https://opensource.org/licenses/MIT) 2 | 3 | # FFT Ocean Waves 4 | An OpenGL demo implementing the FFT ocean wave simulation from Jerry Tessendorf's famous paper. 5 | 6 | ## Screenshots 7 | 8 | ![FFTOceanWave](data/screenshot.jpg) 9 | 10 | ## Dependencies 11 | * [dwSampleFramework](https://github.com/diharaw/dwSampleFramework) 12 | 13 | ## License 14 | ``` 15 | Copyright (c) 2020 Dihara Wijetunga 16 | 17 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 18 | associated documentation files (the "Software"), to deal in the Software without restriction, 19 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 20 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 21 | subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in all copies or substantial 24 | portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 27 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 28 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 29 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 30 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | ``` 32 | -------------------------------------------------------------------------------- /data/noise/LDR_LLL1_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/fft-ocean-waves/61442b1b2380f48a90acde8c637d820e0da9c1cf/data/noise/LDR_LLL1_0.png -------------------------------------------------------------------------------- /data/noise/LDR_LLL1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/fft-ocean-waves/61442b1b2380f48a90acde8c637d820e0da9c1cf/data/noise/LDR_LLL1_1.png -------------------------------------------------------------------------------- /data/noise/LDR_LLL1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/fft-ocean-waves/61442b1b2380f48a90acde8c637d820e0da9c1cf/data/noise/LDR_LLL1_2.png -------------------------------------------------------------------------------- /data/noise/LDR_LLL1_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/fft-ocean-waves/61442b1b2380f48a90acde8c637d820e0da9c1cf/data/noise/LDR_LLL1_3.png -------------------------------------------------------------------------------- /data/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/fft-ocean-waves/61442b1b2380f48a90acde8c637d820e0da9c1cf/data/screenshot.jpg -------------------------------------------------------------------------------- /data/texture/inscatter.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/fft-ocean-waves/61442b1b2380f48a90acde8c637d820e0da9c1cf/data/texture/inscatter.raw -------------------------------------------------------------------------------- /data/texture/irradiance.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/fft-ocean-waves/61442b1b2380f48a90acde8c637d820e0da9c1cf/data/texture/irradiance.raw -------------------------------------------------------------------------------- /data/texture/transmittance.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/fft-ocean-waves/61442b1b2380f48a90acde8c637d820e0da9c1cf/data/texture/transmittance.raw -------------------------------------------------------------------------------- /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(FFT_OCEAN_WAVES_SOURCES ${PROJECT_SOURCE_DIR}/src/main.cpp) 9 | file(GLOB_RECURSE SHADER_SOURCES ${PROJECT_SOURCE_DIR}/src/*.glsl) 10 | 11 | if (APPLE) 12 | add_executable(FFTOceanWaves MACOSX_BUNDLE ${FFT_OCEAN_WAVES_SOURCES} ${SHADER_SOURCES} ${ASSET_SOURCES}) 13 | set(MACOSX_BUNDLE_BUNDLE_NAME "FFTOceanWaves") 14 | set_source_files_properties(${SHADER_SOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/shader) 15 | set_source_files_properties(${ASSET_SOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) 16 | else() 17 | add_executable(FFTOceanWaves ${FFT_OCEAN_WAVES_SOURCES}) 18 | endif() 19 | 20 | target_link_libraries(FFTOceanWaves dwSampleFramework) 21 | 22 | if (NOT APPLE) 23 | add_custom_command(TARGET FFTOceanWaves POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/src/shader $/shader) 24 | add_custom_command(TARGET FFTOceanWaves POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/noise $/noise) 25 | add_custom_command(TARGET FFTOceanWaves POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/texture $/texture) 26 | endif() 27 | 28 | if(CLANG_FORMAT_EXE) 29 | add_custom_target(FFTOceanWaves-clang-format COMMAND ${CLANG_FORMAT_EXE} -i -style=file ${FFT_OCEAN_WAVES_SOURCES} ${SHADER_SOURCES}) 30 | endif() 31 | 32 | set_property(TARGET FFTOceanWaves 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 | 14 | #undef min 15 | #define CAMERA_FAR_PLANE 1000.0f 16 | #define DEBUG_CAMERA_FAR_PLANE 10000.0f 17 | #define DISPLACEMENT_MAP_SIZE 256 18 | #define COMPUTE_LOCAL_WORK_GROUP_SIZE 32 19 | #define ENVIRONMENT_MAP_SIZE 512 20 | #define GRID_SIZE 1024 21 | #define GRID_UV_SCALE 64 22 | 23 | struct GlobalUniforms 24 | { 25 | DW_ALIGNED(16) 26 | glm::mat4 view_proj; 27 | }; 28 | 29 | const unsigned char g_bit_rev_table[] = { 30 | 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF 31 | }; 32 | 33 | const unsigned short g_bit_rev_masks[17] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0X0100, 0X0300, 0X0700, 0X0F00, 0X1F00, 0X3F00, 0X7F00, 0XFF00 }; 34 | 35 | unsigned long reverse_bits(unsigned long codeword, unsigned char maxLength) 36 | { 37 | if (maxLength <= 8) 38 | { 39 | codeword = g_bit_rev_table[codeword << (8 - maxLength)]; 40 | } 41 | else 42 | { 43 | unsigned char sc = maxLength - 8; // shift count in bits and index into masks array 44 | 45 | if (maxLength <= 16) 46 | { 47 | codeword = (g_bit_rev_table[codeword & 0X00FF] << sc) 48 | | g_bit_rev_table[codeword >> sc]; 49 | } 50 | else if (maxLength & 1) // if maxLength is 17, 19, 21, or 23 51 | { 52 | codeword = (g_bit_rev_table[codeword & 0X00FF] << sc) 53 | | g_bit_rev_table[codeword >> sc] | (g_bit_rev_table[(codeword & g_bit_rev_masks[sc]) >> (sc - 8)] << 8); 54 | } 55 | else // if maxlength is 18, 20, 22, or 24 56 | { 57 | codeword = (g_bit_rev_table[codeword & 0X00FF] << sc) 58 | | g_bit_rev_table[codeword >> sc] 59 | | (g_bit_rev_table[(codeword & g_bit_rev_masks[sc]) >> (sc >> 1)] << (sc >> 1)); 60 | } 61 | } 62 | 63 | return codeword; 64 | } 65 | 66 | struct SkyModel 67 | { 68 | const float SCALE = 1000.0f; 69 | const int TRANSMITTANCE_W = 256; 70 | const int TRANSMITTANCE_H = 64; 71 | 72 | const int IRRADIANCE_W = 64; 73 | const int IRRADIANCE_H = 16; 74 | 75 | const int INSCATTER_R = 32; 76 | const int INSCATTER_MU = 128; 77 | const int INSCATTER_MU_S = 32; 78 | const int INSCATTER_NU = 8; 79 | 80 | glm::vec3 m_beta_r = glm::vec3(0.0058f, 0.0135f, 0.0331f); 81 | glm::vec3 m_direction = glm::vec3(0.0f, 0.0f, 1.0f); 82 | float m_mie_g = 0.75f; 83 | float m_sun_intensity = 100.0f; 84 | dw::gl::Texture2D* m_transmittance_t; 85 | dw::gl::Texture2D* m_irradiance_t; 86 | dw::gl::Texture3D* m_inscatter_t; 87 | float m_sun_angle = 0.0f; 88 | 89 | bool initialize() 90 | { 91 | m_transmittance_t = new_texture_2d(TRANSMITTANCE_W, TRANSMITTANCE_H); 92 | m_irradiance_t = new_texture_2d(IRRADIANCE_W, IRRADIANCE_H); 93 | m_inscatter_t = new_texture_3d(INSCATTER_MU_S * INSCATTER_NU, INSCATTER_MU, INSCATTER_R); 94 | 95 | FILE* transmittance = fopen("texture/transmittance.raw", "r"); 96 | 97 | if (transmittance) 98 | { 99 | size_t n = sizeof(float) * TRANSMITTANCE_W * TRANSMITTANCE_H * 4; 100 | 101 | void* data = malloc(n); 102 | fread(data, n, 1, transmittance); 103 | 104 | m_transmittance_t->set_data(0, 0, data); 105 | 106 | fclose(transmittance); 107 | free(data); 108 | } 109 | else 110 | return false; 111 | 112 | FILE* irradiance = fopen("texture/irradiance.raw", "r"); 113 | 114 | if (irradiance) 115 | { 116 | size_t n = sizeof(float) * IRRADIANCE_W * IRRADIANCE_H * 4; 117 | 118 | void* data = malloc(n); 119 | fread(data, n, 1, irradiance); 120 | 121 | m_irradiance_t->set_data(0, 0, data); 122 | 123 | fclose(irradiance); 124 | free(data); 125 | } 126 | else 127 | return false; 128 | 129 | FILE* inscatter = fopen("texture/inscatter.raw", "r"); 130 | 131 | if (inscatter) 132 | { 133 | size_t n = sizeof(float) * INSCATTER_MU_S * INSCATTER_NU * INSCATTER_MU * INSCATTER_R * 4; 134 | 135 | void* data = malloc(n); 136 | fread(data, n, 1, inscatter); 137 | 138 | m_inscatter_t->set_data(0, data); 139 | 140 | fclose(inscatter); 141 | free(data); 142 | } 143 | else 144 | return false; 145 | 146 | return true; 147 | } 148 | 149 | void set_render_uniforms(dw::gl::Program* program) 150 | { 151 | m_direction = glm::normalize(glm::vec3(0.0f, sin(m_sun_angle), cos(m_sun_angle))); 152 | 153 | program->set_uniform("betaR", m_beta_r / SCALE); 154 | program->set_uniform("mieG", m_mie_g); 155 | program->set_uniform("SUN_INTENSITY", m_sun_intensity); 156 | program->set_uniform("EARTH_POS", glm::vec3(0.0f, 6360010.0f, 0.0f)); 157 | program->set_uniform("SUN_DIR", m_direction * -1.0f); 158 | 159 | if (program->set_uniform("s_Transmittance", 3)) 160 | m_transmittance_t->bind(3); 161 | 162 | if (program->set_uniform("s_Irradiance", 4)) 163 | m_irradiance_t->bind(4); 164 | 165 | if (program->set_uniform("s_Inscatter", 5)) 166 | m_inscatter_t->bind(5); 167 | } 168 | 169 | dw::gl::Texture2D* new_texture_2d(int width, int height) 170 | { 171 | dw::gl::Texture2D* texture = new dw::gl::Texture2D(width, height, 1, 1, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 172 | texture->set_min_filter(GL_LINEAR); 173 | texture->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 174 | 175 | return texture; 176 | } 177 | 178 | dw::gl::Texture3D* new_texture_3d(int width, int height, int depth) 179 | { 180 | dw::gl::Texture3D* texture = new dw::gl::Texture3D(width, height, depth, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 181 | texture->set_min_filter(GL_LINEAR); 182 | texture->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 183 | 184 | return texture; 185 | } 186 | }; 187 | 188 | struct GridVertex 189 | { 190 | glm::vec3 position; 191 | glm::vec2 texcoord; 192 | }; 193 | 194 | class FFTOceanWaves : public dw::Application 195 | { 196 | protected: 197 | // ----------------------------------------------------------------------------------------------------------------------------------- 198 | 199 | bool init(int argc, const char* argv[]) override 200 | { 201 | // Create GPU resources. 202 | if (!create_shaders()) 203 | return false; 204 | 205 | create_textures(); 206 | create_skybox_resources(); 207 | 208 | if (!create_uniform_buffer()) 209 | return false; 210 | 211 | if (!m_sky_model.initialize()) 212 | return false; 213 | 214 | // Create camera. 215 | create_camera(); 216 | 217 | // FFT precomputations 218 | tilde_h0_k(); 219 | generate_bit_reversed_indices(); 220 | generate_twiddle_factors(); 221 | generate_grid(GRID_SIZE, GRID_UV_SCALE); 222 | glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); 223 | 224 | return true; 225 | } 226 | 227 | // ----------------------------------------------------------------------------------------------------------------------------------- 228 | 229 | void update(double delta) override 230 | { 231 | if (m_debug_gui) 232 | debug_gui(); 233 | 234 | // Update camera. 235 | update_camera(); 236 | 237 | update_uniforms(); 238 | 239 | render_envmap(); 240 | tilde_h0_t(); 241 | butterfly_fft(m_tilde_h0_t_dy, m_dy); 242 | butterfly_fft(m_tilde_h0_t_dx, m_dx); 243 | butterfly_fft(m_tilde_h0_t_dz, m_dz); 244 | generate_normal_map(); 245 | 246 | if (m_visualize_wireframe) 247 | render_grid_wireframe_tessellated(); 248 | else 249 | render_grid_lit_tessellated(); 250 | 251 | render_skybox(); 252 | 253 | if (m_visualize_displacement_map) 254 | render_visualization_quad(m_dy); 255 | } 256 | 257 | // ----------------------------------------------------------------------------------------------------------------------------------- 258 | 259 | void window_resized(int width, int height) override 260 | { 261 | // Override window resized method to update camera projection. 262 | m_main_camera->update_projection(60.0f, 0.1f, CAMERA_FAR_PLANE, float(m_width) / float(m_height)); 263 | } 264 | 265 | // ----------------------------------------------------------------------------------------------------------------------------------- 266 | 267 | void key_pressed(int code) override 268 | { 269 | // Handle forward movement. 270 | if (code == GLFW_KEY_W) 271 | m_heading_speed = m_camera_speed; 272 | else if (code == GLFW_KEY_S) 273 | m_heading_speed = -m_camera_speed; 274 | 275 | // Handle sideways movement. 276 | if (code == GLFW_KEY_A) 277 | m_sideways_speed = -m_camera_speed; 278 | else if (code == GLFW_KEY_D) 279 | m_sideways_speed = m_camera_speed; 280 | 281 | if (code == GLFW_KEY_SPACE) 282 | m_mouse_look = true; 283 | 284 | if (code == GLFW_KEY_G) 285 | m_debug_gui = !m_debug_gui; 286 | } 287 | 288 | // ----------------------------------------------------------------------------------------------------------------------------------- 289 | 290 | void key_released(int code) override 291 | { 292 | // Handle forward movement. 293 | if (code == GLFW_KEY_W || code == GLFW_KEY_S) 294 | m_heading_speed = 0.0f; 295 | 296 | // Handle sideways movement. 297 | if (code == GLFW_KEY_A || code == GLFW_KEY_D) 298 | m_sideways_speed = 0.0f; 299 | 300 | if (code == GLFW_KEY_SPACE) 301 | m_mouse_look = false; 302 | } 303 | 304 | // ----------------------------------------------------------------------------------------------------------------------------------- 305 | 306 | void mouse_pressed(int code) override 307 | { 308 | // Enable mouse look. 309 | if (code == GLFW_MOUSE_BUTTON_RIGHT) 310 | m_mouse_look = true; 311 | } 312 | 313 | // ----------------------------------------------------------------------------------------------------------------------------------- 314 | 315 | void mouse_released(int code) override 316 | { 317 | // Disable mouse look. 318 | if (code == GLFW_MOUSE_BUTTON_RIGHT) 319 | m_mouse_look = false; 320 | } 321 | 322 | // ----------------------------------------------------------------------------------------------------------------------------------- 323 | 324 | protected: 325 | // ----------------------------------------------------------------------------------------------------------------------------------- 326 | 327 | dw::AppSettings intial_app_settings() override 328 | { 329 | dw::AppSettings settings; 330 | 331 | settings.resizable = true; 332 | settings.maximized = false; 333 | settings.refresh_rate = 60; 334 | settings.major_ver = 4; 335 | settings.width = 1920; 336 | settings.height = 1080; 337 | settings.title = "FFT Ocean Waves (c) 2020 Dihara Wijetunga"; 338 | settings.enable_debug_callback = false; 339 | 340 | return settings; 341 | } 342 | 343 | // ----------------------------------------------------------------------------------------------------------------------------------- 344 | 345 | private: 346 | // ----------------------------------------------------------------------------------------------------------------------------------- 347 | 348 | void debug_gui() 349 | { 350 | ImGui::InputFloat("Displacement Scale", &m_displacement_scale); 351 | ImGui::InputFloat("Choppiness", &m_choppiness); 352 | ImGui::InputFloat("Wind Speed (m/s)", &m_wind_speed); 353 | ImGui::InputFloat("Amplitude", &m_amplitude); 354 | ImGui::SliderAngle("Sun Angle", &m_sky_model.m_sun_angle, 0.0f, -180.0f); 355 | ImGui::ColorPicker3("Sea Color", &m_sea_color[0]); 356 | ImGui::Checkbox("Visualize Wireframe", &m_visualize_wireframe); 357 | ImGui::Checkbox("Visualize Displacement Map", &m_visualize_displacement_map); 358 | } 359 | 360 | // ----------------------------------------------------------------------------------------------------------------------------------- 361 | 362 | void render_visualization_quad(std::unique_ptr& texture, int w = 0, int h = 0) 363 | { 364 | glViewport(0, 0, w == 0 ? texture->width() : w, h == 0 ? texture->height() : h); 365 | 366 | glDisable(GL_DEPTH_TEST); 367 | glDisable(GL_CULL_FACE); 368 | glDisable(GL_BLEND); 369 | 370 | // Bind shader program. 371 | m_visualize_image_program->use(); 372 | 373 | if (m_visualize_image_program->set_uniform("s_Image", 0)) 374 | texture->bind(0); 375 | 376 | if (texture->format() == GL_RED) 377 | m_visualize_image_program->set_uniform("u_NumChannels", 1); 378 | else if (texture->format() == GL_RG) 379 | m_visualize_image_program->set_uniform("u_NumChannels", 2); 380 | else if (texture->format() == GL_RGB) 381 | m_visualize_image_program->set_uniform("u_NumChannels", 3); 382 | else if (texture->format() == GL_RGBA) 383 | m_visualize_image_program->set_uniform("u_NumChannels", 4); 384 | 385 | // Render fullscreen triangle 386 | glDrawArrays(GL_TRIANGLES, 0, 3); 387 | } 388 | 389 | // ----------------------------------------------------------------------------------------------------------------------------------- 390 | 391 | void render_grid_wireframe() 392 | { 393 | glViewport(0, 0, m_width, m_height); 394 | 395 | glEnable(GL_DEPTH_TEST); 396 | glEnable(GL_CULL_FACE); 397 | glDisable(GL_BLEND); 398 | 399 | m_ocean_wireframe_no_tess_program->use(); 400 | m_global_ubo->bind_base(0); 401 | 402 | glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 403 | 404 | m_grid_vao->bind(); 405 | 406 | glDrawElements(GL_TRIANGLES, m_grid_num_indices, GL_UNSIGNED_INT, 0); 407 | 408 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 409 | } 410 | 411 | // ----------------------------------------------------------------------------------------------------------------------------------- 412 | 413 | void render_grid_wireframe_tessellated() 414 | { 415 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 416 | glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 417 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 418 | 419 | glViewport(0, 0, m_width, m_height); 420 | 421 | glEnable(GL_DEPTH_TEST); 422 | glEnable(GL_CULL_FACE); 423 | glDisable(GL_BLEND); 424 | 425 | m_ocean_wireframe_program->use(); 426 | m_global_ubo->bind_base(0); 427 | 428 | glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 429 | 430 | m_ocean_wireframe_program->set_uniform("u_CameraPos", m_main_camera->m_position); 431 | m_ocean_wireframe_program->set_uniform("u_DisplacementScale", m_displacement_scale); 432 | m_ocean_wireframe_program->set_uniform("u_Choppiness", m_choppiness); 433 | 434 | if (m_ocean_wireframe_program->set_uniform("s_Dy", 0)) 435 | m_dy->bind(0); 436 | 437 | if (m_ocean_wireframe_program->set_uniform("s_Dx", 1)) 438 | m_dx->bind(1); 439 | 440 | if (m_ocean_wireframe_program->set_uniform("s_Dz", 2)) 441 | m_dz->bind(2); 442 | 443 | if (m_ocean_wireframe_program->set_uniform("s_NormalMap", 3)) 444 | m_normal_map->bind(3); 445 | 446 | m_grid_vao->bind(); 447 | 448 | glPatchParameteri(GL_PATCH_VERTICES, 3); 449 | glDrawElements(GL_PATCHES, m_grid_num_indices, GL_UNSIGNED_INT, 0); 450 | 451 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 452 | } 453 | 454 | // ----------------------------------------------------------------------------------------------------------------------------------- 455 | 456 | void render_grid_lit_tessellated() 457 | { 458 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 459 | glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 460 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 461 | 462 | glViewport(0, 0, m_width, m_height); 463 | 464 | glEnable(GL_DEPTH_TEST); 465 | glEnable(GL_CULL_FACE); 466 | glDisable(GL_BLEND); 467 | 468 | m_ocean_lit_program->use(); 469 | m_global_ubo->bind_base(0); 470 | 471 | m_ocean_lit_program->set_uniform("u_CameraPos", m_main_camera->m_position); 472 | m_ocean_lit_program->set_uniform("u_DisplacementScale", m_displacement_scale); 473 | m_ocean_lit_program->set_uniform("u_Choppiness", m_choppiness); 474 | m_ocean_lit_program->set_uniform("u_SeaColor", m_sea_color); 475 | m_ocean_lit_program->set_uniform("u_SunDirection", m_sky_model.m_direction); 476 | 477 | if (m_ocean_lit_program->set_uniform("s_Dy", 0)) 478 | m_dy->bind(0); 479 | 480 | if (m_ocean_lit_program->set_uniform("s_Dx", 1)) 481 | m_dx->bind(1); 482 | 483 | if (m_ocean_lit_program->set_uniform("s_Dz", 2)) 484 | m_dz->bind(2); 485 | 486 | if (m_ocean_lit_program->set_uniform("s_NormalMap", 3)) 487 | m_normal_map->bind(3); 488 | 489 | if (m_ocean_lit_program->set_uniform("s_Sky", 4)) 490 | m_env_cubemap->bind(4); 491 | 492 | m_grid_vao->bind(); 493 | 494 | glPatchParameteri(GL_PATCH_VERTICES, 3); 495 | glDrawElements(GL_PATCHES, m_grid_num_indices, GL_UNSIGNED_INT, 0); 496 | } 497 | 498 | // ----------------------------------------------------------------------------------------------------------------------------------- 499 | 500 | void render_envmap() 501 | { 502 | m_sky_envmap_program->use(); 503 | m_sky_model.set_render_uniforms(m_sky_envmap_program.get()); 504 | 505 | for (int i = 0; i < 6; i++) 506 | { 507 | m_sky_envmap_program->set_uniform("u_Projection", m_capture_projection); 508 | m_sky_envmap_program->set_uniform("u_View", m_capture_views[i]); 509 | m_sky_envmap_program->set_uniform("u_CameraPos", m_main_camera->m_position); 510 | 511 | m_cubemap_fbos[i]->bind(); 512 | glViewport(0, 0, ENVIRONMENT_MAP_SIZE, ENVIRONMENT_MAP_SIZE); 513 | 514 | glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 515 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 516 | 517 | m_cube_vao->bind(); 518 | 519 | glDrawArrays(GL_TRIANGLES, 0, 36); 520 | } 521 | 522 | m_env_cubemap->generate_mipmaps(); 523 | } 524 | 525 | // ----------------------------------------------------------------------------------------------------------------------------------- 526 | 527 | void render_skybox() 528 | { 529 | glEnable(GL_DEPTH_TEST); 530 | glDepthFunc(GL_LEQUAL); 531 | glDisable(GL_CULL_FACE); 532 | 533 | m_cubemap_program->use(); 534 | m_cube_vao->bind(); 535 | 536 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 537 | glViewport(0, 0, m_width, m_height); 538 | 539 | m_cubemap_program->set_uniform("u_View", m_main_camera->m_view); 540 | m_cubemap_program->set_uniform("u_Projection", m_main_camera->m_projection); 541 | m_cubemap_program->set_uniform("u_CameraPos", m_main_camera->m_position); 542 | 543 | if (m_cubemap_program->set_uniform("s_Cubemap", 0)) 544 | m_env_cubemap->bind(0); 545 | 546 | glDrawArrays(GL_TRIANGLES, 0, 36); 547 | 548 | glDepthFunc(GL_LESS); 549 | } 550 | 551 | // ----------------------------------------------------------------------------------------------------------------------------------- 552 | 553 | void tilde_h0_k() 554 | { 555 | m_wind_direction = glm::normalize(m_wind_direction); 556 | 557 | m_tilde_h0_k_program->use(); 558 | 559 | if (m_tilde_h0_k_program->set_uniform("noise0", 2)) 560 | m_noise0->bind(2); 561 | if (m_tilde_h0_k_program->set_uniform("noise1", 3)) 562 | m_noise1->bind(3); 563 | if (m_tilde_h0_k_program->set_uniform("noise2", 4)) 564 | m_noise2->bind(4); 565 | if (m_tilde_h0_k_program->set_uniform("noise3", 5)) 566 | m_noise3->bind(5); 567 | 568 | m_tilde_h0_k_program->set_uniform("u_Amplitude", m_amplitude); 569 | m_tilde_h0_k_program->set_uniform("u_WindSpeed", m_wind_speed); 570 | m_tilde_h0_k_program->set_uniform("u_WindDirection", m_wind_direction); 571 | m_tilde_h0_k_program->set_uniform("u_SuppressFactor", m_suppression_factor); 572 | m_tilde_h0_k_program->set_uniform("u_N", m_N); 573 | m_tilde_h0_k_program->set_uniform("u_L", m_L); 574 | 575 | m_tilde_h0_k->bind_image(0, 0, 0, GL_WRITE_ONLY, m_tilde_h0_k->internal_format()); 576 | m_tilde_h0_minus_k->bind_image(1, 0, 0, GL_WRITE_ONLY, m_tilde_h0_minus_k->internal_format()); 577 | 578 | uint32_t num_groups = m_N / COMPUTE_LOCAL_WORK_GROUP_SIZE; 579 | 580 | glDispatchCompute(num_groups, num_groups, 1); 581 | 582 | glFinish(); 583 | } 584 | 585 | // ----------------------------------------------------------------------------------------------------------------------------------- 586 | 587 | void tilde_h0_t() 588 | { 589 | m_wind_direction = glm::normalize(m_wind_direction); 590 | 591 | m_tilde_h0_t_program->use(); 592 | 593 | m_tilde_h0_k->bind_image(0, 0, 0, GL_READ_ONLY, m_tilde_h0_k->internal_format()); 594 | m_tilde_h0_minus_k->bind_image(1, 0, 0, GL_READ_ONLY, m_tilde_h0_minus_k->internal_format()); 595 | m_tilde_h0_t_dx->bind_image(2, 0, 0, GL_WRITE_ONLY, m_tilde_h0_t_dx->internal_format()); 596 | m_tilde_h0_t_dy->bind_image(3, 0, 0, GL_WRITE_ONLY, m_tilde_h0_t_dy->internal_format()); 597 | m_tilde_h0_t_dz->bind_image(4, 0, 0, GL_WRITE_ONLY, m_tilde_h0_t_dz->internal_format()); 598 | 599 | m_tilde_h0_t_program->set_uniform("u_Time", float(glfwGetTime())); 600 | m_tilde_h0_t_program->set_uniform("u_N", m_N); 601 | m_tilde_h0_t_program->set_uniform("u_L", m_L); 602 | 603 | uint32_t num_groups = m_N / COMPUTE_LOCAL_WORK_GROUP_SIZE; 604 | 605 | glDispatchCompute(num_groups, num_groups, 1); 606 | 607 | glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 608 | } 609 | 610 | // ----------------------------------------------------------------------------------------------------------------------------------- 611 | 612 | void butterfly_fft(std::unique_ptr& tilde_h0_t, std::unique_ptr& dst) 613 | { 614 | m_butterfly_program->use(); 615 | 616 | m_twiddle_factors->bind_image(0, 0, 0, GL_READ_ONLY, m_twiddle_factors->internal_format()); 617 | tilde_h0_t->bind_image(1, 0, 0, GL_READ_WRITE, tilde_h0_t->internal_format()); 618 | m_ping_pong->bind_image(2, 0, 0, GL_READ_WRITE, m_ping_pong->internal_format()); 619 | 620 | int log_2_n = int(log(m_N) / log(2)); 621 | int pingpong = 0; 622 | 623 | glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "1D FFT Horizontal"); 624 | 625 | // 1D FFT horizontal 626 | for (int i = 0; i < log_2_n; i++) 627 | { 628 | m_butterfly_program->set_uniform("u_PingPong", pingpong); 629 | m_butterfly_program->set_uniform("u_Direction", 0); 630 | m_butterfly_program->set_uniform("u_Stage", i); 631 | 632 | uint32_t num_groups = m_N / COMPUTE_LOCAL_WORK_GROUP_SIZE; 633 | 634 | glDispatchCompute(num_groups, num_groups, 1); 635 | 636 | glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 637 | 638 | pingpong++; 639 | pingpong %= 2; 640 | } 641 | 642 | glPopDebugGroup(); 643 | 644 | glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "1D FFT Vertical"); 645 | 646 | // 1D FFT vertical 647 | for (int i = 0; i < log_2_n; i++) 648 | { 649 | m_butterfly_program->set_uniform("u_PingPong", pingpong); 650 | m_butterfly_program->set_uniform("u_Direction", 1); 651 | m_butterfly_program->set_uniform("u_Stage", i); 652 | 653 | uint32_t num_groups = m_N / COMPUTE_LOCAL_WORK_GROUP_SIZE; 654 | 655 | glDispatchCompute(num_groups, num_groups, 1); 656 | 657 | glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 658 | 659 | pingpong++; 660 | pingpong %= 2; 661 | } 662 | 663 | glPopDebugGroup(); 664 | 665 | glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "FFT Inversion"); 666 | 667 | m_inversion_program->use(); 668 | 669 | m_inversion_program->set_uniform("u_PingPong", pingpong); 670 | m_inversion_program->set_uniform("u_N", m_N); 671 | 672 | dst->bind_image(0, 0, 0, GL_WRITE_ONLY, dst->internal_format()); 673 | tilde_h0_t->bind_image(1, 0, 0, GL_READ_ONLY, tilde_h0_t->internal_format()); 674 | m_ping_pong->bind_image(2, 0, 0, GL_READ_ONLY, m_ping_pong->internal_format()); 675 | 676 | uint32_t num_groups = m_N / COMPUTE_LOCAL_WORK_GROUP_SIZE; 677 | 678 | glDispatchCompute(num_groups, num_groups, 1); 679 | 680 | glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 681 | 682 | glPopDebugGroup(); 683 | } 684 | 685 | // ----------------------------------------------------------------------------------------------------------------------------------- 686 | 687 | void generate_normal_map() 688 | { 689 | glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Generate Normal Map"); 690 | 691 | m_normal_map_program->use(); 692 | 693 | m_normal_map->bind_image(0, 0, 0, GL_WRITE_ONLY, m_normal_map->internal_format()); 694 | 695 | if (m_normal_map_program->set_uniform("s_HeightMap", 0)) 696 | m_dy->bind(0); 697 | 698 | m_normal_map_program->set_uniform("u_N", m_N); 699 | 700 | uint32_t num_groups = m_N / COMPUTE_LOCAL_WORK_GROUP_SIZE; 701 | 702 | glDispatchCompute(num_groups, num_groups, 1); 703 | 704 | glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 705 | 706 | glPopDebugGroup(); 707 | } 708 | 709 | // ----------------------------------------------------------------------------------------------------------------------------------- 710 | 711 | void generate_twiddle_factors() 712 | { 713 | m_twiddle_factors_program->use(); 714 | 715 | uint32_t log_2_n = int(log(m_N) / log(2)); 716 | uint32_t num_groups = m_N / COMPUTE_LOCAL_WORK_GROUP_SIZE; 717 | 718 | m_twiddle_factors->bind_image(0, 0, 0, GL_WRITE_ONLY, m_twiddle_factors->internal_format()); 719 | 720 | m_bit_reversed_indices->bind_base(0); 721 | 722 | m_twiddle_factors_program->set_uniform("u_N", m_N); 723 | m_twiddle_factors_program->set_uniform("u_DisplacementScale", m_N); 724 | m_twiddle_factors_program->set_uniform("u_Choppiness", m_N); 725 | 726 | glDispatchCompute(log_2_n, num_groups, 1); 727 | 728 | glFinish(); 729 | } 730 | 731 | // ----------------------------------------------------------------------------------------------------------------------------------- 732 | 733 | void generate_bit_reversed_indices() 734 | { 735 | std::vector indices; 736 | indices.resize(m_N); 737 | 738 | int32_t num_bits = int(log(m_N) / log(2)); 739 | 740 | for (int i = 0; i < m_N; i++) 741 | indices[i] = reverse_bits(i, num_bits); 742 | 743 | m_bit_reversed_indices = std::unique_ptr(new dw::gl::ShaderStorageBuffer(GL_STATIC_DRAW, sizeof(int32_t) * m_N, indices.data())); 744 | } 745 | 746 | // ----------------------------------------------------------------------------------------------------------------------------------- 747 | 748 | void generate_grid(const int32_t& num_squares_per_side, const float& texcoord_scale) 749 | { 750 | std::vector vertices; 751 | std::vector indices; 752 | const int32_t n = num_squares_per_side; 753 | const int32_t half_n = n / 2; 754 | const int32_t n_verts = n + 1; 755 | 756 | vertices.reserve(n_verts * n_verts); 757 | indices.reserve(n_verts * n_verts * 3); 758 | 759 | // Generate vertices 760 | for (int32_t y = -half_n; y <= half_n; y++) 761 | { 762 | for (int32_t x = -half_n; x <= half_n; x++) 763 | { 764 | GridVertex vert; 765 | 766 | vert.position = glm::vec3(float(x), 0.0f, float(y)); 767 | 768 | float u = float(x + half_n) / float(n); 769 | float v = float(y + half_n) / float(n); 770 | 771 | vert.texcoord = glm::vec2(u * texcoord_scale, v * texcoord_scale); 772 | 773 | vertices.push_back(vert); 774 | } 775 | } 776 | 777 | // Generate indices 778 | for (int32_t y = 0; y < n; y++) 779 | { 780 | for (int32_t x = 0; x < n; x++) 781 | { 782 | uint32_t i0 = (n_verts * y) + x; 783 | uint32_t i1 = (n_verts * (y + 1)) + x; 784 | uint32_t i2 = i0 + 1; 785 | 786 | indices.push_back(i0); 787 | indices.push_back(i1); 788 | indices.push_back(i2); 789 | 790 | uint32_t i3 = i2; 791 | uint32_t i4 = i1; 792 | uint32_t i5 = i1 + 1; 793 | 794 | indices.push_back(i3); 795 | indices.push_back(i4); 796 | indices.push_back(i5); 797 | } 798 | } 799 | 800 | m_grid_num_vertices = vertices.size(); 801 | m_grid_num_indices = indices.size(); 802 | 803 | // Create vertex buffer. 804 | m_grid_vbo = std::make_unique(GL_STATIC_DRAW, sizeof(GridVertex) * vertices.size(), vertices.data()); 805 | 806 | if (!m_grid_vbo) 807 | DW_LOG_ERROR("Failed to create Vertex Buffer"); 808 | 809 | // Create index buffer. 810 | m_grid_ibo = std::make_unique(GL_STATIC_DRAW, sizeof(uint32_t) * indices.size(), indices.data()); 811 | 812 | if (!m_grid_ibo) 813 | DW_LOG_ERROR("Failed to create Index Buffer"); 814 | 815 | // Declare vertex attributes. 816 | dw::gl::VertexAttrib attribs[] = { { 3, GL_FLOAT, false, 0 }, 817 | { 2, GL_FLOAT, false, offsetof(GridVertex, texcoord) } }; 818 | 819 | // Create vertex array. 820 | m_grid_vao = std::make_unique(m_grid_vbo.get(), m_grid_ibo.get(), sizeof(GridVertex), 2, attribs); 821 | 822 | if (!m_grid_vao) 823 | DW_LOG_ERROR("Failed to create Vertex Array"); 824 | } 825 | 826 | // ----------------------------------------------------------------------------------------------------------------------------------- 827 | 828 | bool create_shaders() 829 | { 830 | { 831 | // Create general shaders 832 | m_triangle_vs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_VERTEX_SHADER, "shader/triangle_vs.glsl")); 833 | m_visualize_image_fs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/visualize_image_fs.glsl")); 834 | m_tilde_h0_k_cs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/tilde_h0_k_cs.glsl")); 835 | m_tilde_h0_t_cs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/tilde_h0_t_cs.glsl")); 836 | m_twiddle_factors_cs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/twiddle_factors_cs.glsl")); 837 | m_butterfly_cs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/butterfly_cs.glsl")); 838 | m_inversion_cs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/inversion_cs.glsl")); 839 | m_normal_map_cs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/normal_map_cs.glsl")); 840 | m_grid_vs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_VERTEX_SHADER, "shader/grid_vs.glsl")); 841 | m_grid_non_tess_vs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_VERTEX_SHADER, "shader/grid_non_tess_vs.glsl")); 842 | m_grid_tcs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_TESS_CONTROL_SHADER, "shader/grid_tcs.glsl")); 843 | m_grid_tes = std::unique_ptr(dw::gl::Shader::create_from_file(GL_TESS_EVALUATION_SHADER, "shader/grid_tes.glsl")); 844 | m_ocean_wireframe_fs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/wireframe_fs.glsl")); 845 | m_ocean_lit_fs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/ocean_fs.glsl")); 846 | m_sky_envmap_vs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_VERTEX_SHADER, "shader/sky_envmap_vs.glsl")); 847 | m_sky_envmap_fs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/sky_envmap_fs.glsl")); 848 | m_cubemap_vs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_VERTEX_SHADER, "shader/sky_vs.glsl")); 849 | m_cubemap_fs = std::unique_ptr(dw::gl::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/sky_fs.glsl")); 850 | 851 | { 852 | if (!m_triangle_vs || !m_visualize_image_fs) 853 | { 854 | DW_LOG_FATAL("Failed to create Shaders"); 855 | return false; 856 | } 857 | 858 | // Create general shader program 859 | dw::gl::Shader* shaders[] = { m_triangle_vs.get(), m_visualize_image_fs.get() }; 860 | m_visualize_image_program = std::make_unique(2, shaders); 861 | 862 | if (!m_visualize_image_program) 863 | { 864 | DW_LOG_FATAL("Failed to create Shader Program"); 865 | return false; 866 | } 867 | } 868 | 869 | { 870 | if (!m_tilde_h0_k_cs) 871 | { 872 | DW_LOG_FATAL("Failed to create Shaders"); 873 | return false; 874 | } 875 | 876 | // Create general shader program 877 | dw::gl::Shader* shaders[] = { m_tilde_h0_k_cs.get() }; 878 | m_tilde_h0_k_program = std::make_unique(1, shaders); 879 | 880 | if (!m_tilde_h0_k_program) 881 | { 882 | DW_LOG_FATAL("Failed to create Shader Program"); 883 | return false; 884 | } 885 | } 886 | 887 | { 888 | if (!m_tilde_h0_t_cs) 889 | { 890 | DW_LOG_FATAL("Failed to create Shaders"); 891 | return false; 892 | } 893 | 894 | // Create general shader program 895 | dw::gl::Shader* shaders[] = { m_tilde_h0_t_cs.get() }; 896 | m_tilde_h0_t_program = std::make_unique(1, shaders); 897 | 898 | if (!m_tilde_h0_t_program) 899 | { 900 | DW_LOG_FATAL("Failed to create Shader Program"); 901 | return false; 902 | } 903 | } 904 | 905 | { 906 | if (!m_twiddle_factors_cs) 907 | { 908 | DW_LOG_FATAL("Failed to create Shaders"); 909 | return false; 910 | } 911 | 912 | // Create general shader program 913 | dw::gl::Shader* shaders[] = { m_twiddle_factors_cs.get() }; 914 | m_twiddle_factors_program = std::make_unique(1, shaders); 915 | 916 | if (!m_twiddle_factors_program) 917 | { 918 | DW_LOG_FATAL("Failed to create Shader Program"); 919 | return false; 920 | } 921 | } 922 | 923 | { 924 | if (!m_butterfly_cs) 925 | { 926 | DW_LOG_FATAL("Failed to create Shaders"); 927 | return false; 928 | } 929 | 930 | // Create general shader program 931 | dw::gl::Shader* shaders[] = { m_butterfly_cs.get() }; 932 | m_butterfly_program = std::make_unique(1, shaders); 933 | 934 | if (!m_butterfly_program) 935 | { 936 | DW_LOG_FATAL("Failed to create Shader Program"); 937 | return false; 938 | } 939 | } 940 | 941 | { 942 | if (!m_inversion_cs) 943 | { 944 | DW_LOG_FATAL("Failed to create Shaders"); 945 | return false; 946 | } 947 | 948 | // Create general shader program 949 | dw::gl::Shader* shaders[] = { m_inversion_cs.get() }; 950 | m_inversion_program = std::make_unique(1, shaders); 951 | 952 | if (!m_inversion_program) 953 | { 954 | DW_LOG_FATAL("Failed to create Shader Program"); 955 | return false; 956 | } 957 | } 958 | 959 | { 960 | if (!m_normal_map_cs) 961 | { 962 | DW_LOG_FATAL("Failed to create Shaders"); 963 | return false; 964 | } 965 | 966 | // Create general shader program 967 | dw::gl::Shader* shaders[] = { m_normal_map_cs.get() }; 968 | m_normal_map_program = std::make_unique(1, shaders); 969 | 970 | if (!m_normal_map_program) 971 | { 972 | DW_LOG_FATAL("Failed to create Shader Program"); 973 | return false; 974 | } 975 | } 976 | 977 | { 978 | if (!m_grid_non_tess_vs || !m_ocean_wireframe_fs) 979 | { 980 | DW_LOG_FATAL("Failed to create Shaders"); 981 | return false; 982 | } 983 | 984 | // Create general shader program 985 | dw::gl::Shader* shaders[] = { m_grid_non_tess_vs.get(), m_ocean_wireframe_fs.get() }; 986 | m_ocean_wireframe_no_tess_program = std::make_unique(2, shaders); 987 | 988 | if (!m_ocean_wireframe_no_tess_program) 989 | { 990 | DW_LOG_FATAL("Failed to create Shader Program"); 991 | return false; 992 | } 993 | 994 | m_ocean_wireframe_no_tess_program->uniform_block_binding("GlobalUniforms", 0); 995 | } 996 | 997 | { 998 | if (!m_grid_vs || !m_grid_tcs || !m_grid_tes || !m_ocean_wireframe_fs) 999 | { 1000 | DW_LOG_FATAL("Failed to create Shaders"); 1001 | return false; 1002 | } 1003 | 1004 | // Create general shader program 1005 | dw::gl::Shader* shaders[] = { m_grid_vs.get(), m_grid_tcs.get(), m_grid_tes.get(), m_ocean_wireframe_fs.get() }; 1006 | m_ocean_wireframe_program = std::make_unique(4, shaders); 1007 | 1008 | if (!m_ocean_wireframe_program) 1009 | { 1010 | DW_LOG_FATAL("Failed to create Shader Program"); 1011 | return false; 1012 | } 1013 | 1014 | m_ocean_wireframe_program->uniform_block_binding("GlobalUniforms", 0); 1015 | } 1016 | 1017 | { 1018 | if (!m_grid_vs || !m_grid_tcs || !m_grid_tes || !m_ocean_lit_fs) 1019 | { 1020 | DW_LOG_FATAL("Failed to create Shaders"); 1021 | return false; 1022 | } 1023 | 1024 | // Create general shader program 1025 | dw::gl::Shader* shaders[] = { m_grid_vs.get(), m_grid_tcs.get(), m_grid_tes.get(), m_ocean_lit_fs.get() }; 1026 | m_ocean_lit_program = std::make_unique(4, shaders); 1027 | 1028 | if (!m_ocean_lit_program) 1029 | { 1030 | DW_LOG_FATAL("Failed to create Shader Program"); 1031 | return false; 1032 | } 1033 | 1034 | m_ocean_lit_program->uniform_block_binding("GlobalUniforms", 0); 1035 | } 1036 | 1037 | { 1038 | if (!m_sky_envmap_vs || !m_sky_envmap_fs) 1039 | { 1040 | DW_LOG_FATAL("Failed to create Shaders"); 1041 | return false; 1042 | } 1043 | 1044 | // Create general shader program 1045 | dw::gl::Shader* shaders[] = { m_sky_envmap_vs.get(), m_sky_envmap_fs.get() }; 1046 | m_sky_envmap_program = std::make_unique(2, shaders); 1047 | 1048 | if (!m_sky_envmap_program) 1049 | { 1050 | DW_LOG_FATAL("Failed to create Shader Program"); 1051 | return false; 1052 | } 1053 | 1054 | m_sky_envmap_program->uniform_block_binding("GlobalUniforms", 0); 1055 | } 1056 | 1057 | { 1058 | if (!m_cubemap_vs || !m_cubemap_fs) 1059 | { 1060 | DW_LOG_FATAL("Failed to create Shaders"); 1061 | return false; 1062 | } 1063 | 1064 | // Create general shader program 1065 | dw::gl::Shader* shaders[] = { m_cubemap_vs.get(), m_cubemap_fs.get() }; 1066 | m_cubemap_program = std::make_unique(2, shaders); 1067 | 1068 | if (!m_cubemap_program) 1069 | { 1070 | DW_LOG_FATAL("Failed to create Shader Program"); 1071 | return false; 1072 | } 1073 | 1074 | m_cubemap_program->uniform_block_binding("GlobalUniforms", 0); 1075 | } 1076 | } 1077 | 1078 | return true; 1079 | } 1080 | 1081 | // ----------------------------------------------------------------------------------------------------------------------------------- 1082 | 1083 | void create_textures() 1084 | { 1085 | m_noise0 = std::unique_ptr(dw::gl::Texture2D::create_from_files("noise/LDR_LLL1_0.png", false, false)); 1086 | m_noise1 = std::unique_ptr(dw::gl::Texture2D::create_from_files("noise/LDR_LLL1_1.png", false, false)); 1087 | m_noise2 = std::unique_ptr(dw::gl::Texture2D::create_from_files("noise/LDR_LLL1_2.png", false, false)); 1088 | m_noise3 = std::unique_ptr(dw::gl::Texture2D::create_from_files("noise/LDR_LLL1_3.png", false, false)); 1089 | m_tilde_h0_k = std::make_unique(m_N, m_N, 1, 1, 1, GL_RG32F, GL_RG, GL_FLOAT); 1090 | m_tilde_h0_minus_k = std::make_unique(m_N, m_N, 1, 1, 1, GL_RG32F, GL_RG, GL_FLOAT); 1091 | m_tilde_h0_t_dx = std::make_unique(m_N, m_N, 1, 1, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 1092 | m_tilde_h0_t_dy = std::make_unique(m_N, m_N, 1, 1, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 1093 | m_tilde_h0_t_dz = std::make_unique(m_N, m_N, 1, 1, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 1094 | m_twiddle_factors = std::make_unique(log(m_N) / log(2), m_N, 1, 1, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 1095 | m_ping_pong = std::make_unique(m_N, m_N, 1, 1, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 1096 | m_dx = std::make_unique(m_N, m_N, 1, 1, 1, GL_R32F, GL_RED, GL_FLOAT); 1097 | m_dy = std::make_unique(m_N, m_N, 1, 1, 1, GL_R32F, GL_RED, GL_FLOAT); 1098 | m_dz = std::make_unique(m_N, m_N, 1, 1, 1, GL_R32F, GL_RED, GL_FLOAT); 1099 | m_normal_map = std::make_unique(m_N, m_N, 1, 1, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 1100 | m_env_cubemap = std::make_unique(ENVIRONMENT_MAP_SIZE, ENVIRONMENT_MAP_SIZE, 1, 1, GL_RGB16F, GL_RGB, GL_HALF_FLOAT); 1101 | 1102 | m_noise0->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 1103 | m_noise0->set_min_filter(GL_NEAREST); 1104 | m_noise0->set_mag_filter(GL_NEAREST); 1105 | 1106 | m_noise1->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 1107 | m_noise1->set_min_filter(GL_NEAREST); 1108 | m_noise1->set_mag_filter(GL_NEAREST); 1109 | 1110 | m_noise2->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 1111 | m_noise2->set_min_filter(GL_NEAREST); 1112 | m_noise2->set_mag_filter(GL_NEAREST); 1113 | 1114 | m_noise3->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 1115 | m_noise3->set_min_filter(GL_NEAREST); 1116 | m_noise3->set_mag_filter(GL_NEAREST); 1117 | 1118 | m_tilde_h0_k->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 1119 | m_tilde_h0_k->set_min_filter(GL_NEAREST); 1120 | m_tilde_h0_k->set_mag_filter(GL_NEAREST); 1121 | 1122 | m_tilde_h0_minus_k->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 1123 | m_tilde_h0_minus_k->set_min_filter(GL_NEAREST); 1124 | m_tilde_h0_minus_k->set_mag_filter(GL_NEAREST); 1125 | 1126 | m_twiddle_factors->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 1127 | m_twiddle_factors->set_min_filter(GL_NEAREST); 1128 | m_twiddle_factors->set_mag_filter(GL_NEAREST); 1129 | 1130 | m_tilde_h0_t_dx->set_wrapping(GL_REPEAT, GL_REPEAT, GL_REPEAT); 1131 | m_tilde_h0_t_dx->set_min_filter(GL_LINEAR); 1132 | m_tilde_h0_t_dx->set_mag_filter(GL_LINEAR); 1133 | 1134 | m_tilde_h0_t_dy->set_wrapping(GL_REPEAT, GL_REPEAT, GL_REPEAT); 1135 | m_tilde_h0_t_dy->set_min_filter(GL_LINEAR); 1136 | m_tilde_h0_t_dy->set_mag_filter(GL_LINEAR); 1137 | 1138 | m_tilde_h0_t_dz->set_wrapping(GL_REPEAT, GL_REPEAT, GL_REPEAT); 1139 | m_tilde_h0_t_dz->set_min_filter(GL_LINEAR); 1140 | m_tilde_h0_t_dz->set_mag_filter(GL_LINEAR); 1141 | 1142 | m_normal_map->set_wrapping(GL_REPEAT, GL_REPEAT, GL_REPEAT); 1143 | m_normal_map->set_min_filter(GL_LINEAR); 1144 | m_normal_map->set_mag_filter(GL_LINEAR); 1145 | } 1146 | 1147 | // ----------------------------------------------------------------------------------------------------------------------------------- 1148 | 1149 | void create_skybox_resources() 1150 | { 1151 | float vertices[] = { 1152 | // back face 1153 | -1.0f, 1154 | -1.0f, 1155 | -1.0f, 1156 | 0.0f, 1157 | 0.0f, 1158 | -1.0f, 1159 | 0.0f, 1160 | 0.0f, // bottom-left 1161 | 1.0f, 1162 | 1.0f, 1163 | -1.0f, 1164 | 0.0f, 1165 | 0.0f, 1166 | -1.0f, 1167 | 1.0f, 1168 | 1.0f, // top-right 1169 | 1.0f, 1170 | -1.0f, 1171 | -1.0f, 1172 | 0.0f, 1173 | 0.0f, 1174 | -1.0f, 1175 | 1.0f, 1176 | 0.0f, // bottom-right 1177 | 1.0f, 1178 | 1.0f, 1179 | -1.0f, 1180 | 0.0f, 1181 | 0.0f, 1182 | -1.0f, 1183 | 1.0f, 1184 | 1.0f, // top-right 1185 | -1.0f, 1186 | -1.0f, 1187 | -1.0f, 1188 | 0.0f, 1189 | 0.0f, 1190 | -1.0f, 1191 | 0.0f, 1192 | 0.0f, // bottom-left 1193 | -1.0f, 1194 | 1.0f, 1195 | -1.0f, 1196 | 0.0f, 1197 | 0.0f, 1198 | -1.0f, 1199 | 0.0f, 1200 | 1.0f, // top-left 1201 | // front face 1202 | -1.0f, 1203 | -1.0f, 1204 | 1.0f, 1205 | 0.0f, 1206 | 0.0f, 1207 | 1.0f, 1208 | 0.0f, 1209 | 0.0f, // bottom-left 1210 | 1.0f, 1211 | -1.0f, 1212 | 1.0f, 1213 | 0.0f, 1214 | 0.0f, 1215 | 1.0f, 1216 | 1.0f, 1217 | 0.0f, // bottom-right 1218 | 1.0f, 1219 | 1.0f, 1220 | 1.0f, 1221 | 0.0f, 1222 | 0.0f, 1223 | 1.0f, 1224 | 1.0f, 1225 | 1.0f, // top-right 1226 | 1.0f, 1227 | 1.0f, 1228 | 1.0f, 1229 | 0.0f, 1230 | 0.0f, 1231 | 1.0f, 1232 | 1.0f, 1233 | 1.0f, // top-right 1234 | -1.0f, 1235 | 1.0f, 1236 | 1.0f, 1237 | 0.0f, 1238 | 0.0f, 1239 | 1.0f, 1240 | 0.0f, 1241 | 1.0f, // top-left 1242 | -1.0f, 1243 | -1.0f, 1244 | 1.0f, 1245 | 0.0f, 1246 | 0.0f, 1247 | 1.0f, 1248 | 0.0f, 1249 | 0.0f, // bottom-left 1250 | // left face 1251 | -1.0f, 1252 | 1.0f, 1253 | 1.0f, 1254 | -1.0f, 1255 | 0.0f, 1256 | 0.0f, 1257 | 1.0f, 1258 | 0.0f, // top-right 1259 | -1.0f, 1260 | 1.0f, 1261 | -1.0f, 1262 | -1.0f, 1263 | 0.0f, 1264 | 0.0f, 1265 | 1.0f, 1266 | 1.0f, // top-left 1267 | -1.0f, 1268 | -1.0f, 1269 | -1.0f, 1270 | -1.0f, 1271 | 0.0f, 1272 | 0.0f, 1273 | 0.0f, 1274 | 1.0f, // bottom-left 1275 | -1.0f, 1276 | -1.0f, 1277 | -1.0f, 1278 | -1.0f, 1279 | 0.0f, 1280 | 0.0f, 1281 | 0.0f, 1282 | 1.0f, // bottom-left 1283 | -1.0f, 1284 | -1.0f, 1285 | 1.0f, 1286 | -1.0f, 1287 | 0.0f, 1288 | 0.0f, 1289 | 0.0f, 1290 | 0.0f, // bottom-right 1291 | -1.0f, 1292 | 1.0f, 1293 | 1.0f, 1294 | -1.0f, 1295 | 0.0f, 1296 | 0.0f, 1297 | 1.0f, 1298 | 0.0f, // top-right 1299 | // right face 1300 | 1.0f, 1301 | 1.0f, 1302 | 1.0f, 1303 | 1.0f, 1304 | 0.0f, 1305 | 0.0f, 1306 | 1.0f, 1307 | 0.0f, // top-left 1308 | 1.0f, 1309 | -1.0f, 1310 | -1.0f, 1311 | 1.0f, 1312 | 0.0f, 1313 | 0.0f, 1314 | 0.0f, 1315 | 1.0f, // bottom-right 1316 | 1.0f, 1317 | 1.0f, 1318 | -1.0f, 1319 | 1.0f, 1320 | 0.0f, 1321 | 0.0f, 1322 | 1.0f, 1323 | 1.0f, // top-right 1324 | 1.0f, 1325 | -1.0f, 1326 | -1.0f, 1327 | 1.0f, 1328 | 0.0f, 1329 | 0.0f, 1330 | 0.0f, 1331 | 1.0f, // bottom-right 1332 | 1.0f, 1333 | 1.0f, 1334 | 1.0f, 1335 | 1.0f, 1336 | 0.0f, 1337 | 0.0f, 1338 | 1.0f, 1339 | 0.0f, // top-left 1340 | 1.0f, 1341 | -1.0f, 1342 | 1.0f, 1343 | 1.0f, 1344 | 0.0f, 1345 | 0.0f, 1346 | 0.0f, 1347 | 0.0f, // bottom-left 1348 | // bottom face 1349 | -1.0f, 1350 | -1.0f, 1351 | -1.0f, 1352 | 0.0f, 1353 | -1.0f, 1354 | 0.0f, 1355 | 0.0f, 1356 | 1.0f, // top-right 1357 | 1.0f, 1358 | -1.0f, 1359 | -1.0f, 1360 | 0.0f, 1361 | -1.0f, 1362 | 0.0f, 1363 | 1.0f, 1364 | 1.0f, // top-left 1365 | 1.0f, 1366 | -1.0f, 1367 | 1.0f, 1368 | 0.0f, 1369 | -1.0f, 1370 | 0.0f, 1371 | 1.0f, 1372 | 0.0f, // bottom-left 1373 | 1.0f, 1374 | -1.0f, 1375 | 1.0f, 1376 | 0.0f, 1377 | -1.0f, 1378 | 0.0f, 1379 | 1.0f, 1380 | 0.0f, // bottom-left 1381 | -1.0f, 1382 | -1.0f, 1383 | 1.0f, 1384 | 0.0f, 1385 | -1.0f, 1386 | 0.0f, 1387 | 0.0f, 1388 | 0.0f, // bottom-right 1389 | -1.0f, 1390 | -1.0f, 1391 | -1.0f, 1392 | 0.0f, 1393 | -1.0f, 1394 | 0.0f, 1395 | 0.0f, 1396 | 1.0f, // top-right 1397 | // top face 1398 | -1.0f, 1399 | 1.0f, 1400 | -1.0f, 1401 | 0.0f, 1402 | 1.0f, 1403 | 0.0f, 1404 | 0.0f, 1405 | 1.0f, // top-left 1406 | 1.0f, 1407 | 1.0f, 1408 | 1.0f, 1409 | 0.0f, 1410 | 1.0f, 1411 | 0.0f, 1412 | 1.0f, 1413 | 0.0f, // bottom-right 1414 | 1.0f, 1415 | 1.0f, 1416 | -1.0f, 1417 | 0.0f, 1418 | 1.0f, 1419 | 0.0f, 1420 | 1.0f, 1421 | 1.0f, // top-right 1422 | 1.0f, 1423 | 1.0f, 1424 | 1.0f, 1425 | 0.0f, 1426 | 1.0f, 1427 | 0.0f, 1428 | 1.0f, 1429 | 0.0f, // bottom-right 1430 | -1.0f, 1431 | 1.0f, 1432 | -1.0f, 1433 | 0.0f, 1434 | 1.0f, 1435 | 0.0f, 1436 | 0.0f, 1437 | 1.0f, // top-left 1438 | -1.0f, 1439 | 1.0f, 1440 | 1.0f, 1441 | 0.0f, 1442 | 1.0f, 1443 | 0.0f, 1444 | 0.0f, 1445 | 0.0f // bottom-left 1446 | }; 1447 | 1448 | m_cube_vbo = std::make_unique(GL_STATIC_DRAW, sizeof(vertices), vertices); 1449 | 1450 | if (!m_cube_vbo) 1451 | DW_LOG_ERROR("Failed to create Vertex Buffer"); 1452 | 1453 | // Declare vertex attributes. 1454 | dw::gl::VertexAttrib attribs[] = { 1455 | { 3, GL_FLOAT, false, 0 }, 1456 | { 3, GL_FLOAT, false, (3 * sizeof(float)) }, 1457 | { 2, GL_FLOAT, false, (6 * sizeof(float)) } 1458 | }; 1459 | 1460 | // Create vertex array. 1461 | m_cube_vao = std::make_unique(m_cube_vbo.get(), nullptr, (8 * sizeof(float)), 3, attribs); 1462 | 1463 | m_capture_projection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f); 1464 | m_capture_views = { 1465 | glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), 1466 | glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), 1467 | glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)), 1468 | glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)), 1469 | glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)), 1470 | glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)) 1471 | }; 1472 | 1473 | for (int i = 0; i < 6; i++) 1474 | { 1475 | m_cubemap_fbos.push_back(std::make_unique()); 1476 | m_cubemap_fbos[i]->attach_render_target(0, m_env_cubemap.get(), i, 0, 0, true, true); 1477 | } 1478 | } 1479 | 1480 | // ----------------------------------------------------------------------------------------------------------------------------------- 1481 | 1482 | bool create_uniform_buffer() 1483 | { 1484 | // Create uniform buffer for global data 1485 | m_global_ubo = std::make_unique(GL_DYNAMIC_DRAW, sizeof(GlobalUniforms)); 1486 | 1487 | return true; 1488 | } 1489 | 1490 | // ----------------------------------------------------------------------------------------------------------------------------------- 1491 | 1492 | void create_camera() 1493 | { 1494 | m_main_camera = std::make_unique(60.0f, 0.1f, CAMERA_FAR_PLANE, float(m_width) / float(m_height), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(-1.0f, 0.0, 0.0f)); 1495 | m_main_camera->set_rotatation_delta(glm::vec3(0.0f, -90.0f, 0.0f)); 1496 | m_main_camera->update(); 1497 | } 1498 | 1499 | // ----------------------------------------------------------------------------------------------------------------------------------- 1500 | 1501 | void update_uniforms() 1502 | { 1503 | void* ptr = m_global_ubo->map(GL_WRITE_ONLY); 1504 | memcpy(ptr, &m_global_uniforms, sizeof(GlobalUniforms)); 1505 | m_global_ubo->unmap(); 1506 | } 1507 | 1508 | // ----------------------------------------------------------------------------------------------------------------------------------- 1509 | 1510 | void update_transforms(dw::Camera* camera) 1511 | { 1512 | // Update camera matrices. 1513 | m_global_uniforms.view_proj = camera->m_projection * camera->m_view; 1514 | } 1515 | 1516 | // ----------------------------------------------------------------------------------------------------------------------------------- 1517 | 1518 | void update_camera() 1519 | { 1520 | dw::Camera* current = m_main_camera.get(); 1521 | 1522 | float forward_delta = m_heading_speed * m_delta; 1523 | float right_delta = m_sideways_speed * m_delta; 1524 | 1525 | current->set_translation_delta(current->m_forward, forward_delta); 1526 | current->set_translation_delta(current->m_right, right_delta); 1527 | 1528 | m_camera_x = m_mouse_delta_x * m_camera_sensitivity; 1529 | m_camera_y = m_mouse_delta_y * m_camera_sensitivity; 1530 | 1531 | if (m_mouse_look) 1532 | { 1533 | // Activate Mouse Look 1534 | current->set_rotatation_delta(glm::vec3((float)(m_camera_y), 1535 | (float)(m_camera_x), 1536 | (float)(0.0f))); 1537 | } 1538 | else 1539 | { 1540 | current->set_rotatation_delta(glm::vec3((float)(0), 1541 | (float)(0), 1542 | (float)(0))); 1543 | } 1544 | 1545 | current->update(); 1546 | update_transforms(current); 1547 | } 1548 | 1549 | // ----------------------------------------------------------------------------------------------------------------------------------- 1550 | 1551 | private: 1552 | // General GPU resources. 1553 | std::unique_ptr m_triangle_vs; 1554 | std::unique_ptr m_visualize_image_fs; 1555 | std::unique_ptr m_tilde_h0_k_cs; 1556 | std::unique_ptr m_tilde_h0_t_cs; 1557 | std::unique_ptr m_twiddle_factors_cs; 1558 | std::unique_ptr m_butterfly_cs; 1559 | std::unique_ptr m_inversion_cs; 1560 | std::unique_ptr m_normal_map_cs; 1561 | std::unique_ptr m_grid_vs; 1562 | std::unique_ptr m_grid_non_tess_vs; 1563 | std::unique_ptr m_grid_tcs; 1564 | std::unique_ptr m_grid_tes; 1565 | std::unique_ptr m_ocean_wireframe_fs; 1566 | std::unique_ptr m_ocean_lit_fs; 1567 | std::unique_ptr m_sky_envmap_vs; 1568 | std::unique_ptr m_sky_envmap_fs; 1569 | std::unique_ptr m_cubemap_vs; 1570 | std::unique_ptr m_cubemap_fs; 1571 | 1572 | std::unique_ptr m_visualize_image_program; 1573 | std::unique_ptr m_tilde_h0_k_program; 1574 | std::unique_ptr m_tilde_h0_t_program; 1575 | std::unique_ptr m_twiddle_factors_program; 1576 | std::unique_ptr m_butterfly_program; 1577 | std::unique_ptr m_inversion_program; 1578 | std::unique_ptr m_normal_map_program; 1579 | std::unique_ptr m_ocean_wireframe_program; 1580 | std::unique_ptr m_ocean_wireframe_no_tess_program; 1581 | std::unique_ptr m_ocean_lit_program; 1582 | std::unique_ptr m_sky_envmap_program; 1583 | std::unique_ptr m_cubemap_program; 1584 | 1585 | std::unique_ptr m_noise0; 1586 | std::unique_ptr m_noise1; 1587 | std::unique_ptr m_noise2; 1588 | std::unique_ptr m_noise3; 1589 | std::unique_ptr m_tilde_h0_k; 1590 | std::unique_ptr m_tilde_h0_minus_k; 1591 | std::unique_ptr m_tilde_h0_t_dy; 1592 | std::unique_ptr m_tilde_h0_t_dx; 1593 | std::unique_ptr m_tilde_h0_t_dz; 1594 | std::unique_ptr m_twiddle_factors; 1595 | std::unique_ptr m_ping_pong; 1596 | std::unique_ptr m_dx; 1597 | std::unique_ptr m_dy; 1598 | std::unique_ptr m_dz; 1599 | std::unique_ptr m_normal_map; 1600 | std::unique_ptr m_env_cubemap; 1601 | 1602 | std::unique_ptr m_bit_reversed_indices; 1603 | 1604 | std::unique_ptr m_grid_vbo; 1605 | std::unique_ptr m_grid_ibo; 1606 | std::unique_ptr m_grid_vao; 1607 | uint32_t m_grid_num_vertices = 0; 1608 | uint32_t m_grid_num_indices = 0; 1609 | 1610 | std::unique_ptr m_global_ubo; 1611 | std::unique_ptr m_main_camera; 1612 | SkyModel m_sky_model; 1613 | std::vector m_capture_views; 1614 | glm::mat4 m_capture_projection; 1615 | std::vector> m_cubemap_fbos; 1616 | std::unique_ptr m_cube_vbo; 1617 | std::unique_ptr m_cube_vao; 1618 | 1619 | GlobalUniforms m_global_uniforms; 1620 | 1621 | // Camera controls. 1622 | bool m_visualize_displacement_map = false; 1623 | bool m_debug_gui = true; 1624 | bool m_mouse_look = false; 1625 | float m_heading_speed = 0.0f; 1626 | float m_sideways_speed = 0.0f; 1627 | float m_camera_sensitivity = 0.05f; 1628 | float m_camera_speed = 0.001f; 1629 | 1630 | // Ocean 1631 | bool m_visualize_wireframe = false; 1632 | float m_displacement_scale = 0.5f; 1633 | float m_choppiness = 0.75f; 1634 | glm::vec3 m_sea_color = glm::vec3(0.0f, 0.169668034f, 0.439894319f); 1635 | 1636 | // Camera orientation. 1637 | float m_camera_x; 1638 | float m_camera_y; 1639 | 1640 | // FFT options 1641 | float m_wind_speed = 80.0f; 1642 | float m_amplitude = 2.0f; 1643 | float m_suppression_factor = 0.1f; 1644 | glm::vec2 m_wind_direction = glm::vec2(1.0f, 1.0f); 1645 | int32_t m_N = DISPLACEMENT_MAP_SIZE; 1646 | int32_t m_L = 1000; 1647 | }; 1648 | 1649 | DW_DECLARE_MAIN(FFTOceanWaves) -------------------------------------------------------------------------------- /src/shader/atmosphere.glsl: -------------------------------------------------------------------------------- 1 | // 2 | // Precomputed Atmospheric Scattering 3 | // Copyright (c) 2008 INRIA 4 | // All rights reserved. 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions 8 | // are met: 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 2. Redistributions in binary form must reproduce the above copyright 12 | // notice, this list of conditions and the following disclaimer in the 13 | // documentation and/or other materials provided with the distribution. 14 | // 3. Neither the name of the copyright holders nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 | // THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: Eric Bruneton 31 | // 32 | 33 | uniform sampler2D s_Transmittance; 34 | uniform sampler2D s_Irradiance; 35 | uniform sampler3D s_Inscatter; 36 | 37 | uniform vec3 EARTH_POS; 38 | uniform vec3 SUN_DIR; 39 | uniform float SUN_INTENSITY; 40 | uniform vec3 betaR; 41 | uniform float mieG; 42 | 43 | #define M_PI 3.141592 44 | #define Rg 6360000.0 45 | #define Rt 6420000.0 46 | #define RL 6421000.0 47 | #define RES_R 32.0 48 | #define RES_MU 128.0 49 | #define RES_MU_S 32.0 50 | #define RES_NU 8.0 51 | 52 | vec3 hdr(vec3 L) 53 | { 54 | L = L * 0.4; 55 | L.r = L.r < 1.413 ? pow(L.r * 0.38317, 1.0 / 2.2) : 1.0 - exp(-L.r); 56 | L.g = L.g < 1.413 ? pow(L.g * 0.38317, 1.0 / 2.2) : 1.0 - exp(-L.g); 57 | L.b = L.b < 1.413 ? pow(L.b * 0.38317, 1.0 / 2.2) : 1.0 - exp(-L.b); 58 | return L; 59 | } 60 | 61 | vec4 Texture4D(sampler3D table, float r, float mu, float muS, float nu) 62 | { 63 | float H = sqrt(Rt * Rt - Rg * Rg); 64 | float rho = sqrt(r * r - Rg * Rg); 65 | 66 | float rmu = r * mu; 67 | float delta = rmu * rmu - r * r + Rg * Rg; 68 | vec4 cst = rmu < 0.0 && delta > 0.0 ? vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / RES_MU) : vec4(-1.0, H * H, H, 0.5 + 0.5 / RES_MU); 69 | float uR = 0.5 / RES_R + rho / H * (1.0 - 1.0 / RES_R); 70 | float uMu = cst.w + (rmu * cst.x + sqrt(delta + cst.y)) / (rho + cst.z) * (0.5 - 1.0 / float(RES_MU)); 71 | // paper formula 72 | //float uMuS = 0.5 / RES_MU_S + max((1.0 - exp(-3.0 * muS - 0.6)) / (1.0 - exp(-3.6)), 0.0) * (1.0 - 1.0 / RES_MU_S); 73 | // better formula 74 | float uMuS = 0.5 / RES_MU_S + (atan(max(muS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / RES_MU_S); 75 | 76 | float lep = (nu + 1.0) / 2.0 * (RES_NU - 1.0); 77 | float uNu = floor(lep); 78 | lep = lep - uNu; 79 | 80 | return texture(table, vec3((uNu + uMuS) / RES_NU, uMu, uR)) * (1.0 - lep) + texture(table, vec3((uNu + uMuS + 1.0) / RES_NU, uMu, uR)) * lep; 81 | } 82 | 83 | vec3 GetMie(vec4 rayMie) 84 | { 85 | // approximated single Mie scattering (cf. approximate Cm in paragraph "Angular precision") 86 | // rayMie.rgb=C*, rayMie.w=Cm,r 87 | return rayMie.rgb * rayMie.w / max(rayMie.r, 1e-4) * (betaR.r / betaR); 88 | } 89 | 90 | float PhaseFunctionR(float mu) 91 | { 92 | // Rayleigh phase function 93 | return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu); 94 | } 95 | 96 | float PhaseFunctionM(float mu) 97 | { 98 | // Mie phase function 99 | return 1.5 * 1.0 / (4.0 * M_PI) * (1.0 - mieG * mieG) * pow(1.0 + (mieG * mieG) - 2.0 * mieG * mu, -3.0 / 2.0) * (1.0 + mu * mu) / (2.0 + mieG * mieG); 100 | } 101 | 102 | vec3 Transmittance(float r, float mu) 103 | { 104 | // transmittance(=transparency) of atmosphere for infinite ray (r,mu) 105 | // (mu=cos(view zenith angle)), intersections with ground ignored 106 | float uR, uMu; 107 | uR = sqrt((r - Rg) / (Rt - Rg)); 108 | uMu = atan((mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5; 109 | 110 | return texture(s_Transmittance, vec2(uMu, uR)).rgb; 111 | } 112 | 113 | vec3 TransmittanceWithShadow(float r, float mu) 114 | { 115 | // transmittance(=transparency) of atmosphere for infinite ray (r,mu) 116 | // (mu=cos(view zenith angle)), or zero if ray intersects ground 117 | 118 | return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? vec3(0, 0, 0) : Transmittance(r, mu); 119 | } 120 | 121 | vec3 Irradiance(float r, float muS) 122 | { 123 | float uR = (r - Rg) / (Rt - Rg); 124 | float uMuS = (muS + 0.2) / (1.0 + 0.2); 125 | 126 | return texture(s_Irradiance, vec2(uMuS, uR)).rgb; 127 | } 128 | 129 | vec3 SunRadiance(vec3 worldPos) 130 | { 131 | vec3 worldV = normalize(worldPos + EARTH_POS); // vertical vector 132 | float r = length(worldPos + EARTH_POS); 133 | float muS = dot(worldV, SUN_DIR); 134 | 135 | return TransmittanceWithShadow(r, muS) * SUN_INTENSITY; 136 | } 137 | 138 | vec3 SkyIrradiance(float r, float muS) 139 | { 140 | return Irradiance(r, muS) * SUN_INTENSITY; 141 | } 142 | 143 | vec3 SkyIrradiance(vec3 worldPos) 144 | { 145 | vec3 worldV = normalize(worldPos + EARTH_POS); // vertical vector 146 | float r = length(worldPos + EARTH_POS); 147 | float muS = dot(worldV, SUN_DIR); 148 | 149 | return Irradiance(r, muS) * SUN_INTENSITY; 150 | } 151 | 152 | vec3 SkyRadiance(vec3 camera, vec3 viewdir, out vec3 extinction) 153 | { 154 | // scattered sunlight between two points 155 | // camera=observer 156 | // viewdir=unit vector towards observed point 157 | // sundir=unit vector towards the sun 158 | // return scattered light 159 | 160 | camera += EARTH_POS; 161 | 162 | vec3 result = vec3(0, 0, 0); 163 | float r = length(camera); 164 | float rMu = dot(camera, viewdir); 165 | float mu = rMu / r; 166 | float r0 = r; 167 | float mu0 = mu; 168 | 169 | float deltaSq = sqrt(rMu * rMu - r * r + Rt * Rt); 170 | float din = max(-rMu - deltaSq, 0.0); 171 | if (din > 0.0) 172 | { 173 | camera += din * viewdir; 174 | rMu += din; 175 | mu = rMu / Rt; 176 | r = Rt; 177 | } 178 | 179 | float nu = dot(viewdir, SUN_DIR); 180 | float muS = dot(camera, SUN_DIR) / r; 181 | 182 | vec4 inScatter = Texture4D(s_Inscatter, r, rMu / r, muS, nu); 183 | extinction = Transmittance(r, mu); 184 | 185 | if (r <= Rt) 186 | { 187 | vec3 inScatterM = GetMie(inScatter); 188 | float phase = PhaseFunctionR(nu); 189 | float phaseM = PhaseFunctionM(nu); 190 | result = inScatter.rgb * phase + inScatterM * phaseM; 191 | } 192 | else 193 | { 194 | result = vec3(0, 0, 0); 195 | extinction = vec3(1, 1, 1); 196 | } 197 | 198 | return result * SUN_INTENSITY; 199 | } 200 | 201 | vec3 InScattering(vec3 camera, vec3 _point, out vec3 extinction, float shaftWidth) 202 | { 203 | // single scattered sunlight between two points 204 | // camera=observer 205 | // point=point on the ground 206 | // sundir=unit vector towards the sun 207 | // return scattered light and extinction coefficient 208 | 209 | vec3 result = vec3(0, 0, 0); 210 | extinction = vec3(1, 1, 1); 211 | 212 | vec3 viewdir = _point - camera; 213 | float d = length(viewdir); 214 | viewdir = viewdir / d; 215 | float r = length(camera); 216 | 217 | if (r < 0.9 * Rg) 218 | { 219 | camera.y += Rg; 220 | _point.y += Rg; 221 | r = length(camera); 222 | } 223 | float rMu = dot(camera, viewdir); 224 | float mu = rMu / r; 225 | float r0 = r; 226 | float mu0 = mu; 227 | _point -= viewdir * clamp(shaftWidth, 0.0, d); 228 | 229 | float deltaSq = sqrt(rMu * rMu - r * r + Rt * Rt); 230 | float din = max(-rMu - deltaSq, 0.0); 231 | 232 | if (din > 0.0 && din < d) 233 | { 234 | camera += din * viewdir; 235 | rMu += din; 236 | mu = rMu / Rt; 237 | r = Rt; 238 | d -= din; 239 | } 240 | 241 | if (r <= Rt) 242 | { 243 | float nu = dot(viewdir, SUN_DIR); 244 | float muS = dot(camera, SUN_DIR) / r; 245 | 246 | vec4 inScatter; 247 | 248 | if (r < Rg + 600.0) 249 | { 250 | // avoids imprecision problems in aerial perspective near ground 251 | float f = (Rg + 600.0) / r; 252 | r = r * f; 253 | rMu = rMu * f; 254 | _point = _point * f; 255 | } 256 | 257 | float r1 = length(_point); 258 | float rMu1 = dot(_point, viewdir); 259 | float mu1 = rMu1 / r1; 260 | float muS1 = dot(_point, SUN_DIR) / r1; 261 | 262 | if (mu > 0.0) 263 | extinction = min(Transmittance(r, mu) / Transmittance(r1, mu1), 1.0); 264 | else 265 | extinction = min(Transmittance(r1, -mu1) / Transmittance(r, -mu), 1.0); 266 | 267 | const float EPS = 0.004; 268 | float lim = -sqrt(1.0 - (Rg / r) * (Rg / r)); 269 | 270 | if (abs(mu - lim) < EPS) 271 | { 272 | float a = ((mu - lim) + EPS) / (2.0 * EPS); 273 | 274 | mu = lim - EPS; 275 | r1 = sqrt(r * r + d * d + 2.0 * r * d * mu); 276 | mu1 = (r * mu + d) / r1; 277 | 278 | vec4 inScatter0 = Texture4D(s_Inscatter, r, mu, muS, nu); 279 | vec4 inScatter1 = Texture4D(s_Inscatter, r1, mu1, muS1, nu); 280 | vec4 inScatterA = max(inScatter0 - inScatter1 * extinction.rgbr, 0.0); 281 | 282 | mu = lim + EPS; 283 | r1 = sqrt(r * r + d * d + 2.0 * r * d * mu); 284 | mu1 = (r * mu + d) / r1; 285 | 286 | inScatter0 = Texture4D(s_Inscatter, r, mu, muS, nu); 287 | inScatter1 = Texture4D(s_Inscatter, r1, mu1, muS1, nu); 288 | vec4 inScatterB = max(inScatter0 - inScatter1 * extinction.rgbr, 0.0); 289 | 290 | inScatter = mix(inScatterA, inScatterB, a); 291 | } 292 | else 293 | { 294 | vec4 inScatter0 = Texture4D(s_Inscatter, r, mu, muS, nu); 295 | vec4 inScatter1 = Texture4D(s_Inscatter, r1, mu1, muS1, nu); 296 | inScatter = max(inScatter0 - inScatter1 * extinction.rgbr, 0.0); 297 | } 298 | 299 | // avoids imprecision problems in Mie scattering when sun is below horizon 300 | inScatter.w *= smoothstep(0.00, 0.02, muS); 301 | 302 | vec3 inScatterM = GetMie(inScatter); 303 | float phase = PhaseFunctionR(nu); 304 | float phaseM = PhaseFunctionM(nu); 305 | result = inScatter.rgb * phase + inScatterM * phaseM; 306 | } 307 | 308 | return result * SUN_INTENSITY; 309 | } -------------------------------------------------------------------------------- /src/shader/butterfly_cs.glsl: -------------------------------------------------------------------------------- 1 | #define LOCAL_SIZE 32 2 | #define M_PI 3.1415926535897932384626433832795 3 | 4 | // ------------------------------------------------------------------ 5 | // INPUTS ----------------------------------------------------------- 6 | // ------------------------------------------------------------------ 7 | 8 | layout(local_size_x = LOCAL_SIZE, local_size_y = LOCAL_SIZE, local_size_z = 1) in; 9 | 10 | // ------------------------------------------------------------------ 11 | // UNIFORMS --------------------------------------------------------- 12 | // ------------------------------------------------------------------ 13 | 14 | layout(binding = 0, rgba32f) readonly uniform image2D twiddle_factors; 15 | layout(binding = 1, rgba32f) uniform image2D pingpong0; 16 | layout(binding = 2, rgba32f) uniform image2D pingpong1; 17 | 18 | uniform int u_PingPong; 19 | uniform int u_Direction; 20 | uniform int u_Stage; 21 | 22 | // ------------------------------------------------------------------ 23 | // FUNCTION --------------------------------------------------------- 24 | // ------------------------------------------------------------------ 25 | 26 | struct complex 27 | { 28 | float real; 29 | float im; 30 | }; 31 | 32 | // ------------------------------------------------------------------ 33 | 34 | complex mul(complex c0, complex c1) 35 | { 36 | complex c; 37 | c.real = c0.real * c1.real - c0.im * c1.im; 38 | c.im = c0.real * c1.im + c0.im * c1.real; 39 | return c; 40 | } 41 | 42 | // ------------------------------------------------------------------ 43 | 44 | complex add(complex c0, complex c1) 45 | { 46 | complex c; 47 | c.real = c0.real + c1.real; 48 | c.im = c0.im + c1.im; 49 | return c; 50 | } 51 | 52 | // ------------------------------------------------------------------ 53 | 54 | void horizontal_butterflies() 55 | { 56 | complex H; 57 | ivec2 x = ivec2(gl_GlobalInvocationID.xy); 58 | 59 | if (u_PingPong == 0) 60 | { 61 | vec4 data = imageLoad(twiddle_factors, ivec2(u_Stage, x.x)).rgba; 62 | vec2 p_ = imageLoad(pingpong0, ivec2(data.z, x.y)).rg; 63 | vec2 q_ = imageLoad(pingpong0, ivec2(data.w, x.y)).rg; 64 | vec2 w_ = vec2(data.x, data.y); 65 | 66 | complex p = complex(p_.x, p_.y); 67 | complex q = complex(q_.x, q_.y); 68 | complex w = complex(w_.x, w_.y); 69 | 70 | //Butterfly operation 71 | H = add(p, mul(w, q)); 72 | 73 | imageStore(pingpong1, x, vec4(H.real, H.im, 0, 1)); 74 | } 75 | else if (u_PingPong == 1) 76 | { 77 | vec4 data = imageLoad(twiddle_factors, ivec2(u_Stage, x.x)).rgba; 78 | vec2 p_ = imageLoad(pingpong1, ivec2(data.z, x.y)).rg; 79 | vec2 q_ = imageLoad(pingpong1, ivec2(data.w, x.y)).rg; 80 | vec2 w_ = vec2(data.x, data.y); 81 | 82 | complex p = complex(p_.x, p_.y); 83 | complex q = complex(q_.x, q_.y); 84 | complex w = complex(w_.x, w_.y); 85 | 86 | //Butterfly operation 87 | H = add(p, mul(w, q)); 88 | 89 | imageStore(pingpong0, x, vec4(H.real, H.im, 0, 1)); 90 | } 91 | } 92 | 93 | // ------------------------------------------------------------------ 94 | 95 | void vertical_butterflies() 96 | { 97 | complex H; 98 | ivec2 x = ivec2(gl_GlobalInvocationID.xy); 99 | 100 | if (u_PingPong == 0) 101 | { 102 | vec4 data = imageLoad(twiddle_factors, ivec2(u_Stage, x.y)).rgba; 103 | vec2 p_ = imageLoad(pingpong0, ivec2(x.x, data.z)).rg; 104 | vec2 q_ = imageLoad(pingpong0, ivec2(x.x, data.w)).rg; 105 | vec2 w_ = vec2(data.x, data.y); 106 | 107 | complex p = complex(p_.x, p_.y); 108 | complex q = complex(q_.x, q_.y); 109 | complex w = complex(w_.x, w_.y); 110 | 111 | //Butterfly operation 112 | H = add(p, mul(w, q)); 113 | 114 | imageStore(pingpong1, x, vec4(H.real, H.im, 0, 1)); 115 | } 116 | else if (u_PingPong == 1) 117 | { 118 | vec4 data = imageLoad(twiddle_factors, ivec2(u_Stage, x.y)).rgba; 119 | vec2 p_ = imageLoad(pingpong1, ivec2(x.x, data.z)).rg; 120 | vec2 q_ = imageLoad(pingpong1, ivec2(x.x, data.w)).rg; 121 | vec2 w_ = vec2(data.x, data.y); 122 | 123 | complex p = complex(p_.x, p_.y); 124 | complex q = complex(q_.x, q_.y); 125 | complex w = complex(w_.x, w_.y); 126 | 127 | //Butterfly operation 128 | H = add(p, mul(w, q)); 129 | 130 | imageStore(pingpong0, x, vec4(H.real, H.im, 0, 1)); 131 | } 132 | } 133 | 134 | // ------------------------------------------------------------------ 135 | // MAIN ------------------------------------------------------------- 136 | // ------------------------------------------------------------------ 137 | 138 | void main() 139 | { 140 | if (u_Direction == 0) 141 | horizontal_butterflies(); 142 | else if (u_Direction == 1) 143 | vertical_butterflies(); 144 | } 145 | 146 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/grid_non_tess_vs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUTS ----------------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | layout(location = 0) in vec3 VS_IN_Position; 6 | layout(location = 1) in vec2 VS_IN_Texcoord; 7 | 8 | // ------------------------------------------------------------------ 9 | // UNIFORMS --------------------------------------------------------- 10 | // ------------------------------------------------------------------ 11 | 12 | layout(std140) uniform u_GlobalUBO 13 | { 14 | mat4 view_proj; 15 | }; 16 | 17 | // ------------------------------------------------------------------ 18 | // MAIN ------------------------------------------------------------- 19 | // ------------------------------------------------------------------ 20 | 21 | void main() 22 | { 23 | gl_Position = view_proj * vec4(VS_IN_Position, 1.0); 24 | } 25 | 26 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/grid_tcs.glsl: -------------------------------------------------------------------------------- 1 | layout(vertices = 3) out; 2 | 3 | // ------------------------------------------------------------------ 4 | // INPUTS ----------------------------------------------------------- 5 | // ------------------------------------------------------------------ 6 | 7 | in vec3 TCS_IN_FragPos[]; 8 | in vec2 TCS_IN_TexCoord[]; 9 | 10 | // ------------------------------------------------------------------ 11 | // OUTPUTS ---------------------------------------------------------- 12 | // ------------------------------------------------------------------ 13 | 14 | out vec3 TES_IN_FragPos[]; 15 | out vec2 TES_IN_TexCoord[]; 16 | 17 | // ------------------------------------------------------------------ 18 | // UNIFORMS --------------------------------------------------------- 19 | // ------------------------------------------------------------------ 20 | 21 | uniform vec3 u_CameraPos; 22 | 23 | // ------------------------------------------------------------------ 24 | // FUNCTIONS -------------------------------------------------------- 25 | // ------------------------------------------------------------------ 26 | 27 | float tessellation_level(float d0, float d1) 28 | { 29 | float avg_d = (d0 + d1) / 2.0; 30 | 31 | if (avg_d <= 10.0) 32 | return 20.0; 33 | else if (avg_d <= 20.0) 34 | return 10.0; 35 | else if (avg_d <= 30.0) 36 | return 5.0; 37 | else 38 | return 1.0; 39 | } 40 | 41 | // ------------------------------------------------------------------ 42 | // MAIN ------------------------------------------------------------- 43 | // ------------------------------------------------------------------ 44 | 45 | void main() 46 | { 47 | TES_IN_FragPos[gl_InvocationID] = TCS_IN_FragPos[gl_InvocationID]; 48 | TES_IN_TexCoord[gl_InvocationID] = TCS_IN_TexCoord[gl_InvocationID]; 49 | 50 | // Calculate distances to each vertex 51 | float eye_to_v0_dist = distance(u_CameraPos, TES_IN_FragPos[0]); 52 | float eye_to_v1_dist = distance(u_CameraPos, TES_IN_FragPos[1]); 53 | float eye_to_v2_dist = distance(u_CameraPos, TES_IN_FragPos[2]); 54 | 55 | // Calculate tessellation levels 56 | gl_TessLevelOuter[0] = tessellation_level(eye_to_v1_dist, eye_to_v2_dist); 57 | gl_TessLevelOuter[1] = tessellation_level(eye_to_v2_dist, eye_to_v0_dist); 58 | gl_TessLevelOuter[2] = tessellation_level(eye_to_v0_dist, eye_to_v1_dist); 59 | gl_TessLevelInner[0] = gl_TessLevelOuter[2]; 60 | } 61 | 62 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/grid_tes.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUTS ----------------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | layout(triangles, equal_spacing, ccw) in; 6 | 7 | in vec3 TES_IN_FragPos[]; 8 | in vec2 TES_IN_TexCoord[]; 9 | 10 | // ------------------------------------------------------------------ 11 | // OUTPUTS ---------------------------------------------------------- 12 | // ------------------------------------------------------------------ 13 | 14 | out vec3 FS_IN_FragPos; 15 | out vec3 FS_IN_Normal; 16 | out vec2 FS_IN_TexCoord; 17 | 18 | // ------------------------------------------------------------------ 19 | // UNIFORMS --------------------------------------------------------- 20 | // ------------------------------------------------------------------ 21 | 22 | layout(std140) uniform u_GlobalUBO 23 | { 24 | mat4 view_proj; 25 | }; 26 | 27 | uniform sampler2D s_Dy; 28 | uniform sampler2D s_Dx; 29 | uniform sampler2D s_Dz; 30 | uniform sampler2D s_NormalMap; 31 | 32 | uniform float u_DisplacementScale; 33 | uniform float u_Choppiness; 34 | 35 | // ------------------------------------------------------------------ 36 | // FUNCTIONS -------------------------------------------------------- 37 | // ------------------------------------------------------------------ 38 | 39 | vec2 interpolate_2d(vec2 v0, vec2 v1, vec2 v2) 40 | { 41 | return vec2(gl_TessCoord.x) * v0 + vec2(gl_TessCoord.y) * v1 + vec2(gl_TessCoord.z) * v2; 42 | } 43 | 44 | // ------------------------------------------------------------------ 45 | 46 | vec3 interpolate_3d(vec3 v0, vec3 v1, vec3 v2) 47 | { 48 | return vec3(gl_TessCoord.x) * v0 + vec3(gl_TessCoord.y) * v1 + vec3(gl_TessCoord.z) * v2; 49 | } 50 | 51 | // ------------------------------------------------------------------ 52 | // MAIN ------------------------------------------------------------- 53 | // ------------------------------------------------------------------ 54 | 55 | void main() 56 | { 57 | FS_IN_FragPos = interpolate_3d(TES_IN_FragPos[0], TES_IN_FragPos[1], TES_IN_FragPos[2]); 58 | FS_IN_TexCoord = interpolate_2d(TES_IN_TexCoord[0], TES_IN_TexCoord[1], TES_IN_TexCoord[2]); 59 | 60 | FS_IN_FragPos.y += texture(s_Dy, FS_IN_TexCoord).r * u_DisplacementScale; 61 | FS_IN_FragPos.x -= texture(s_Dx, FS_IN_TexCoord).r * u_Choppiness; 62 | FS_IN_FragPos.z -= texture(s_Dz, FS_IN_TexCoord).r * u_Choppiness; 63 | 64 | FS_IN_Normal = texture(s_NormalMap, FS_IN_TexCoord).xyz; 65 | 66 | gl_Position = view_proj * vec4(FS_IN_FragPos, 1.0); 67 | } 68 | 69 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/grid_vs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUTS ----------------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | layout(location = 0) in vec3 VS_IN_Position; 6 | layout(location = 1) in vec2 VS_IN_Texcoord; 7 | 8 | // ------------------------------------------------------------------ 9 | // OUTPUTS ---------------------------------------------------------- 10 | // ------------------------------------------------------------------ 11 | 12 | out vec3 TCS_IN_FragPos; 13 | out vec2 TCS_IN_TexCoord; 14 | 15 | // ------------------------------------------------------------------ 16 | // MAIN ------------------------------------------------------------- 17 | // ------------------------------------------------------------------ 18 | 19 | void main() 20 | { 21 | TCS_IN_FragPos = VS_IN_Position; 22 | TCS_IN_TexCoord = VS_IN_Texcoord; 23 | } 24 | 25 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/inversion_cs.glsl: -------------------------------------------------------------------------------- 1 | #define LOCAL_SIZE 32 2 | #define M_PI 3.1415926535897932384626433832795 3 | 4 | // ------------------------------------------------------------------ 5 | // INPUTS ----------------------------------------------------------- 6 | // ------------------------------------------------------------------ 7 | 8 | layout(local_size_x = LOCAL_SIZE, local_size_y = LOCAL_SIZE, local_size_z = 1) in; 9 | 10 | // ------------------------------------------------------------------ 11 | // UNIFORMS --------------------------------------------------------- 12 | // ------------------------------------------------------------------ 13 | 14 | layout(binding = 0, r32f) writeonly uniform image2D displacement; 15 | layout(binding = 1, rgba32f) readonly uniform image2D pingpong0; 16 | layout(binding = 2, rgba32f) readonly uniform image2D pingpong1; 17 | 18 | uniform int u_PingPong; 19 | uniform int u_N; 20 | 21 | // ------------------------------------------------------------------ 22 | // MAIN ------------------------------------------------------------- 23 | // ------------------------------------------------------------------ 24 | 25 | void main() 26 | { 27 | ivec2 x = ivec2(gl_GlobalInvocationID.xy); 28 | 29 | float perms[] = { 1.0, -1.0 }; 30 | int index = int(mod((int(x.x + x.y)), 2)); 31 | float perm = perms[index]; 32 | 33 | if (u_PingPong == 0) 34 | { 35 | float h = imageLoad(pingpong0, x).r; 36 | imageStore(displacement, x, vec4(perm * (h / float(u_N * u_N)), 0, 0, 1)); 37 | } 38 | else if (u_PingPong == 1) 39 | { 40 | float h = imageLoad(pingpong1, x).r; 41 | imageStore(displacement, x, vec4(perm * (h / float(u_N * u_N)), 0, 0, 1)); 42 | } 43 | } 44 | 45 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/normal_map_cs.glsl: -------------------------------------------------------------------------------- 1 | #define LOCAL_SIZE 32 2 | #define M_PI 3.1415926535897932384626433832795 3 | 4 | // ------------------------------------------------------------------ 5 | // INPUTS ----------------------------------------------------------- 6 | // ------------------------------------------------------------------ 7 | 8 | layout(local_size_x = LOCAL_SIZE, local_size_y = LOCAL_SIZE, local_size_z = 1) in; 9 | 10 | // ------------------------------------------------------------------ 11 | // UNIFORMS --------------------------------------------------------- 12 | // ------------------------------------------------------------------ 13 | 14 | layout(binding = 0, rgba32f) writeonly uniform image2D normal_map; 15 | 16 | uniform sampler2D s_HeightMap; 17 | 18 | uniform int u_N; 19 | 20 | // ------------------------------------------------------------------ 21 | // MAIN ------------------------------------------------------------- 22 | // ------------------------------------------------------------------ 23 | 24 | void main() 25 | { 26 | // z0 -- z1 -- z2 27 | // | | | 28 | // z3 -- h -- z4 29 | // | | | 30 | // z5 -- z6 -- z7 31 | 32 | ivec2 x = ivec2(gl_GlobalInvocationID.xy); 33 | vec2 tex_coord = gl_GlobalInvocationID.xy / float(u_N); 34 | 35 | float texelSize = 1.0 / u_N; 36 | 37 | float z0 = texture(s_HeightMap, tex_coord + vec2(-texelSize, -texelSize)).r; 38 | float z1 = texture(s_HeightMap, tex_coord + vec2(0, -texelSize)).r; 39 | float z2 = texture(s_HeightMap, tex_coord + vec2(texelSize, -texelSize)).r; 40 | float z3 = texture(s_HeightMap, tex_coord + vec2(-texelSize, 0)).r; 41 | float z4 = texture(s_HeightMap, tex_coord + vec2(texelSize, 0)).r; 42 | float z5 = texture(s_HeightMap, tex_coord + vec2(-texelSize, texelSize)).r; 43 | float z6 = texture(s_HeightMap, tex_coord + vec2(0, texelSize)).r; 44 | float z7 = texture(s_HeightMap, tex_coord + vec2(texelSize, texelSize)).r; 45 | 46 | vec3 normal; 47 | 48 | // Sobel Filter 49 | normal.z = z0 + 2 * z1 + z2 - z5 - 2 * z6 - z7; 50 | normal.x = z0 + 2 * z3 + z5 - z2 - 2 * z4 - z7; 51 | normal.y = 1.0; 52 | 53 | imageStore(normal_map, x, vec4(normalize(normal), 1)); 54 | } 55 | 56 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/ocean_fs.glsl: -------------------------------------------------------------------------------- 1 | out vec4 FS_OUT_Color; 2 | 3 | in vec3 FS_IN_FragPos; 4 | in vec3 FS_IN_Normal; 5 | 6 | uniform samplerCube s_Sky; 7 | uniform vec3 u_CameraPos; 8 | uniform vec3 u_SunDirection; 9 | uniform vec3 u_SeaColor; 10 | 11 | vec3 fresnel_schlick(float cosTheta, vec3 F0) 12 | { 13 | return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); 14 | } 15 | 16 | void main() 17 | { 18 | // Input lighting data 19 | vec3 N = FS_IN_Normal; 20 | vec3 V = normalize(u_CameraPos - FS_IN_FragPos); 21 | vec3 R = reflect(-V, N); 22 | vec3 L = -u_SunDirection; 23 | 24 | vec3 F0 = vec3(0.04); 25 | vec3 F = fresnel_schlick(max(dot(N, V), 0.0), F0); 26 | 27 | vec3 albedo = mix(u_SeaColor, texture(s_Sky, R).rgb, F); 28 | 29 | float NdotL = max(dot(N, L), 0.0); 30 | vec3 color = NdotL * albedo; 31 | 32 | // HDR tonemapping 33 | color = color / (color + vec3(1.0)); 34 | // gamma correct 35 | color = pow(color, vec3(1.0 / 2.2)); 36 | 37 | FS_OUT_Color = vec4(color, 1.0); 38 | } 39 | -------------------------------------------------------------------------------- /src/shader/sky_envmap_fs.glsl: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // ------------------------------------------------------------------ 4 | // OUPUT ------------------------------------------------------------ 5 | // ------------------------------------------------------------------ 6 | 7 | out vec4 PS_OUT_Color; 8 | 9 | // ------------------------------------------------------------------ 10 | // INPUT ------------------------------------------------------------ 11 | // ------------------------------------------------------------------ 12 | 13 | in vec3 PS_IN_WorldPos; 14 | 15 | // ------------------------------------------------------------------ 16 | // UNIFORM ---------------------------------------------------------- 17 | // ------------------------------------------------------------------ 18 | 19 | uniform vec3 u_CameraPos; 20 | 21 | // ------------------------------------------------------------------ 22 | // MAIN ------------------------------------------------------------- 23 | // ------------------------------------------------------------------ 24 | 25 | void main() 26 | { 27 | vec3 dir = normalize(PS_IN_WorldPos); 28 | 29 | float sun = step(cos(M_PI / 360.0), dot(dir, SUN_DIR)); 30 | 31 | vec3 sunColor = vec3(sun, sun, sun) * SUN_INTENSITY; 32 | 33 | vec3 extinction; 34 | vec3 inscatter = SkyRadiance(u_CameraPos, dir, extinction); 35 | vec3 col = sunColor * extinction + inscatter; 36 | 37 | PS_OUT_Color = vec4(col, 1.0); 38 | } 39 | 40 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_envmap_vs.glsl: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec3 position; 2 | layout(location = 1) in vec3 normal; 3 | layout(location = 2) in vec2 texcoord; 4 | 5 | uniform mat4 u_Projection; 6 | uniform mat4 u_View; 7 | 8 | out vec3 PS_IN_WorldPos; 9 | 10 | void main(void) 11 | { 12 | PS_IN_WorldPos = position; 13 | gl_Position = u_Projection * u_View * vec4(position, 1.0f); 14 | } 15 | -------------------------------------------------------------------------------- /src/shader/sky_fs.glsl: -------------------------------------------------------------------------------- 1 | out vec3 PS_OUT_Color; 2 | 3 | in vec3 FS_IN_WorldPos; 4 | 5 | uniform samplerCube s_Cubemap; 6 | 7 | // ------------------------------------------------------------------ 8 | // MAIN ------------------------------------------------------------- 9 | // ------------------------------------------------------------------ 10 | 11 | void main() 12 | { 13 | vec3 env_color = texture(s_Cubemap, FS_IN_WorldPos).rgb; 14 | 15 | // HDR tonemap and gamma correct 16 | env_color = env_color / (env_color + vec3(1.0)); 17 | env_color = pow(env_color, vec3(1.0 / 2.2)); 18 | 19 | PS_OUT_Color = env_color; 20 | } 21 | 22 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_vs.glsl: -------------------------------------------------------------------------------- 1 | layout(location = 0) in vec3 VS_IN_Position; 2 | 3 | // ------------------------------------------------------------------ 4 | // OUTPUT VARIABLES ------------------------------------------------ 5 | // ------------------------------------------------------------------ 6 | 7 | out vec3 FS_IN_WorldPos; 8 | 9 | // ------------------------------------------------------------------ 10 | // UNIFORMS -------------------------------------------------------- 11 | // ------------------------------------------------------------------ 12 | 13 | uniform mat4 u_Projection; 14 | uniform mat4 u_View; 15 | 16 | // ------------------------------------------------------------------ 17 | // MAIN ------------------------------------------------------------ 18 | // ------------------------------------------------------------------ 19 | 20 | void main() 21 | { 22 | FS_IN_WorldPos = VS_IN_Position; 23 | 24 | mat4 rotView = mat4(mat3(u_View)); 25 | vec4 clipPos = u_Projection * rotView * vec4(VS_IN_Position, 1.0); 26 | 27 | gl_Position = clipPos.xyww; 28 | } -------------------------------------------------------------------------------- /src/shader/tilde_h0_k_cs.glsl: -------------------------------------------------------------------------------- 1 | #define LOCAL_SIZE 32 2 | #define M_PI 3.1415926535897932384626433832795 3 | 4 | // ------------------------------------------------------------------ 5 | // INPUTS ----------------------------------------------------------- 6 | // ------------------------------------------------------------------ 7 | 8 | layout(local_size_x = LOCAL_SIZE, local_size_y = LOCAL_SIZE, local_size_z = 1) in; 9 | 10 | // ------------------------------------------------------------------ 11 | // INPUT ------------------------------------------------------------ 12 | // ------------------------------------------------------------------ 13 | 14 | uniform sampler2D noise0; 15 | uniform sampler2D noise1; 16 | uniform sampler2D noise2; 17 | uniform sampler2D noise3; 18 | 19 | uniform float u_Amplitude; 20 | uniform float u_WindSpeed; 21 | uniform float u_SuppressFactor; 22 | uniform vec2 u_WindDirection; 23 | uniform int u_N; 24 | uniform int u_L; 25 | 26 | const float g = 9.81; 27 | 28 | layout(binding = 0, rg32f) writeonly uniform image2D tilde_h0k; 29 | layout(binding = 1, rg32f) writeonly uniform image2D tilde_h0minusk; 30 | 31 | // ------------------------------------------------------------------ 32 | // FUNCTIONS -------------------------------------------------------- 33 | // ------------------------------------------------------------------ 34 | 35 | float suppression_factor(float k_mag_sqr) 36 | { 37 | return exp(-k_mag_sqr * u_SuppressFactor * u_SuppressFactor); 38 | } 39 | 40 | // ------------------------------------------------------------------ 41 | 42 | float philips_power_spectrum(vec2 k, float k_mag, float k_mag_sqr, float L_philips, float suppression) 43 | { 44 | return (u_Amplitude * (exp(-1.0 / (k_mag_sqr * L_philips * L_philips))) * pow(dot(normalize(k), u_WindDirection), 2.0) * suppression) / (k_mag_sqr * k_mag_sqr); 45 | } 46 | 47 | // ------------------------------------------------------------------ 48 | 49 | // Box-Muller-Method 50 | 51 | vec4 gauss_rnd() 52 | { 53 | vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / float(u_N); 54 | 55 | float noise00 = clamp(texture(noise0, texCoord).r, 0.001, 1.0); 56 | float noise01 = clamp(texture(noise1, texCoord).r, 0.001, 1.0); 57 | float noise02 = clamp(texture(noise2, texCoord).r, 0.001, 1.0); 58 | float noise03 = clamp(texture(noise3, texCoord).r, 0.001, 1.0); 59 | 60 | float u0 = 2.0 * M_PI * noise00; 61 | float v0 = sqrt(-2.0 * log(noise01)); 62 | float u1 = 2.0 * M_PI * noise02; 63 | float v1 = sqrt(-2.0 * log(noise03)); 64 | 65 | vec4 rnd = vec4(v0 * cos(u0), v0 * sin(u0), v1 * cos(u1), v1 * sin(u1)); 66 | 67 | return rnd; 68 | } 69 | 70 | // ------------------------------------------------------------------ 71 | // MAIN ------------------------------------------------------------- 72 | // ------------------------------------------------------------------ 73 | 74 | void main() 75 | { 76 | vec2 x = vec2(gl_GlobalInvocationID.xy) - float(u_N) / 2.0; 77 | vec2 k = vec2((2.0 * M_PI * float(x.x)) / float(u_L), (2.0 * M_PI * float(x.y)) / float(u_L)); 78 | float L_philips = (u_WindSpeed * u_WindSpeed) / g; 79 | float k_mag = length(k); 80 | 81 | if (k_mag < 0.00001) 82 | k_mag = 0.00001; 83 | 84 | float k_mag_sqr = k_mag * k_mag; 85 | float suppression = suppression_factor(k_mag_sqr); 86 | 87 | float h0k = clamp(sqrt(philips_power_spectrum(k, k_mag, k_mag_sqr, L_philips, suppression)) / sqrt(2.0), -4000.0, 4000.0); 88 | float h0minusk = clamp(sqrt(philips_power_spectrum(-k, k_mag, k_mag_sqr, L_philips, suppression)) / sqrt(2.0), -4000.0, 4000.0); 89 | 90 | vec4 rnd = gauss_rnd(); 91 | 92 | imageStore(tilde_h0k, ivec2(gl_GlobalInvocationID.xy), vec4(rnd.xy * h0k, 0.0, 1.0)); 93 | imageStore(tilde_h0minusk, ivec2(gl_GlobalInvocationID.xy), vec4(rnd.zw * h0minusk, 0.0, 1.0)); 94 | } 95 | 96 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/tilde_h0_t_cs.glsl: -------------------------------------------------------------------------------- 1 | #define LOCAL_SIZE 32 2 | #define M_PI 3.1415926535897932384626433832795 3 | 4 | // ------------------------------------------------------------------ 5 | // INPUTS ----------------------------------------------------------- 6 | // ------------------------------------------------------------------ 7 | 8 | layout(local_size_x = LOCAL_SIZE, local_size_y = LOCAL_SIZE, local_size_z = 1) in; 9 | 10 | // ------------------------------------------------------------------ 11 | // STRUCTURES ------------------------------------------------------- 12 | // ------------------------------------------------------------------ 13 | 14 | struct complex 15 | { 16 | float real; 17 | float im; 18 | }; 19 | 20 | // ------------------------------------------------------------------ 21 | 22 | complex mul(complex c0, complex c1) 23 | { 24 | complex c; 25 | c.real = c0.real * c1.real - c0.im * c1.im; 26 | c.im = c0.real * c1.im + c0.im * c1.real; 27 | return c; 28 | } 29 | 30 | // ------------------------------------------------------------------ 31 | 32 | complex add(complex c0, complex c1) 33 | { 34 | complex c; 35 | c.real = c0.real + c1.real; 36 | c.im = c0.im + c1.im; 37 | return c; 38 | } 39 | 40 | // ------------------------------------------------------------------ 41 | 42 | complex conjugate(complex c) 43 | { 44 | complex c_conj; 45 | c_conj.real = c.real; 46 | c_conj.im = -c.im; 47 | return c; 48 | } 49 | 50 | // ------------------------------------------------------------------ 51 | // UNIFORMS --------------------------------------------------------- 52 | // ------------------------------------------------------------------ 53 | 54 | uniform float u_Time; 55 | uniform int u_N; 56 | uniform int u_L; 57 | 58 | const float g = 9.81; 59 | 60 | layout(binding = 0, rg32f) readonly uniform image2D tilde_h0k; 61 | layout(binding = 1, rg32f) readonly uniform image2D tilde_h0minusk; 62 | layout(binding = 2, rgba32f) writeonly uniform image2D tilde_hkt_dx; 63 | layout(binding = 3, rgba32f) writeonly uniform image2D tilde_hkt_dy; 64 | layout(binding = 4, rgba32f) writeonly uniform image2D tilde_hkt_dz; 65 | 66 | // ------------------------------------------------------------------ 67 | // MAIN ------------------------------------------------------------- 68 | // ------------------------------------------------------------------ 69 | 70 | void main() 71 | { 72 | vec2 x = vec2(gl_GlobalInvocationID.xy) - float(u_N) / 2.0; 73 | vec2 k = vec2((2.0 * M_PI * float(x.x)) / float(u_L), (2.0 * M_PI * float(x.y)) / float(u_L)); 74 | float k_mag = length(k); 75 | 76 | if (k_mag < 0.00001) 77 | k_mag = 0.00001; 78 | 79 | float w = sqrt(g * k_mag); 80 | 81 | vec2 h0k = imageLoad(tilde_h0k, ivec2(gl_GlobalInvocationID.xy)).xy; 82 | vec2 h0minusk = imageLoad(tilde_h0minusk, ivec2(gl_GlobalInvocationID.xy)).xy; 83 | 84 | complex fourier_amp; 85 | 86 | fourier_amp.real = h0k.x; 87 | fourier_amp.im = h0k.y; 88 | 89 | complex fourier_amp_conj; 90 | 91 | fourier_amp_conj.real = h0minusk.x; 92 | fourier_amp_conj.im = h0minusk.y; 93 | 94 | fourier_amp_conj = conjugate(fourier_amp_conj); 95 | 96 | float consinus = cos(w * u_Time); 97 | float sinus = sin(w * u_Time); 98 | 99 | complex exp_iwkt; 100 | 101 | exp_iwkt.real = consinus; 102 | exp_iwkt.im = sinus; 103 | 104 | complex exp_iwkt_minus; 105 | 106 | exp_iwkt_minus.real = consinus; 107 | exp_iwkt_minus.im = -sinus; 108 | 109 | // dy 110 | complex d_k_t_dy = add(mul(fourier_amp, exp_iwkt), mul(fourier_amp_conj, exp_iwkt_minus)); 111 | 112 | // dx 113 | complex dx; 114 | 115 | dx.real = 0.0; 116 | dx.im = -k.x / k_mag; 117 | 118 | complex d_k_t_dx = mul(dx, d_k_t_dy); 119 | 120 | // dz 121 | complex dy; 122 | 123 | dy.real = 0.0; 124 | dy.im = -k.y / k_mag; 125 | 126 | complex d_k_t_dz = mul(dy, d_k_t_dy); 127 | 128 | imageStore(tilde_hkt_dx, ivec2(gl_GlobalInvocationID.xy), vec4(d_k_t_dx.real, d_k_t_dx.im, 0.0, 1.0)); 129 | imageStore(tilde_hkt_dy, ivec2(gl_GlobalInvocationID.xy), vec4(d_k_t_dy.real, d_k_t_dy.im, 0.0, 1.0)); 130 | imageStore(tilde_hkt_dz, ivec2(gl_GlobalInvocationID.xy), vec4(d_k_t_dz.real, d_k_t_dz.im, 0.0, 1.0)); 131 | } 132 | 133 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/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/twiddle_factors_cs.glsl: -------------------------------------------------------------------------------- 1 | #define LOCAL_SIZE 32 2 | #define M_PI 3.1415926535897932384626433832795 3 | 4 | // ------------------------------------------------------------------ 5 | // INPUTS ----------------------------------------------------------- 6 | // ------------------------------------------------------------------ 7 | 8 | layout(local_size_x = 1, local_size_y = LOCAL_SIZE, local_size_z = 1) in; 9 | 10 | // ------------------------------------------------------------------ 11 | // UNIFORMS --------------------------------------------------------- 12 | // ------------------------------------------------------------------ 13 | 14 | layout(binding = 0, rgba32f) writeonly uniform image2D twiddle_factors; 15 | 16 | layout(std430, binding = 0) buffer indices 17 | { 18 | int j[]; 19 | } 20 | bit_reversed; 21 | 22 | struct complex 23 | { 24 | float real; 25 | float im; 26 | }; 27 | 28 | uniform int u_N; 29 | 30 | // ------------------------------------------------------------------ 31 | // MAIN ------------------------------------------------------------- 32 | // ------------------------------------------------------------------ 33 | 34 | void main() 35 | { 36 | vec2 x = gl_GlobalInvocationID.xy; 37 | float k = mod(x.y * (float(u_N) / pow(2, x.x + 1)), u_N); 38 | complex twiddle = complex(cos(2.0 * M_PI * k / float(u_N)), sin(2.0 * M_PI * k / float(u_N))); 39 | 40 | int butterflyspan = int(pow(2, x.x)); 41 | 42 | int butterflywing; 43 | 44 | if (mod(x.y, pow(2, x.x + 1)) < pow(2, x.x)) 45 | butterflywing = 1; 46 | else 47 | butterflywing = 0; 48 | 49 | // first stage, bit reversed indices 50 | if (x.x == 0) 51 | { 52 | // top butterfly wing 53 | if (butterflywing == 1) 54 | imageStore(twiddle_factors, ivec2(x), vec4(twiddle.real, twiddle.im, bit_reversed.j[int(x.y)], bit_reversed.j[int(x.y + 1)])); 55 | // bot butterfly wing 56 | else 57 | imageStore(twiddle_factors, ivec2(x), vec4(twiddle.real, twiddle.im, bit_reversed.j[int(x.y - 1)], bit_reversed.j[int(x.y)])); 58 | } 59 | // second to log2(N) stage 60 | else 61 | { 62 | // top butterfly wing 63 | if (butterflywing == 1) 64 | imageStore(twiddle_factors, ivec2(x), vec4(twiddle.real, twiddle.im, x.y, x.y + butterflyspan)); 65 | // bot butterfly wing 66 | else 67 | imageStore(twiddle_factors, ivec2(x), vec4(twiddle.real, twiddle.im, x.y - butterflyspan, x.y)); 68 | } 69 | } 70 | 71 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/visualize_image_fs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // INPUT VARIABLES ------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | in vec2 FS_IN_TexCoord; 6 | 7 | // ------------------------------------------------------------------ 8 | // OUTPUT VARIABLES ------------------------------------------------ 9 | // ------------------------------------------------------------------ 10 | 11 | out vec4 FS_OUT_Color; 12 | 13 | // ------------------------------------------------------------------ 14 | // UNIFORMS -------------------------------------------------------- 15 | // ------------------------------------------------------------------ 16 | 17 | uniform sampler2D s_Image; 18 | 19 | uniform int u_NumChannels; 20 | 21 | // ------------------------------------------------------------------ 22 | // MAIN ------------------------------------------------------------ 23 | // ------------------------------------------------------------------ 24 | 25 | void main(void) 26 | { 27 | if (u_NumChannels == 1) 28 | FS_OUT_Color = vec4(texture(s_Image, FS_IN_TexCoord).rrr, 1.0); 29 | else if (u_NumChannels == 2) 30 | FS_OUT_Color = vec4(texture(s_Image, FS_IN_TexCoord).rg, 0.0, 1.0); 31 | else if (u_NumChannels == 3) 32 | FS_OUT_Color = vec4(texture(s_Image, FS_IN_TexCoord).rgb, 1.0); 33 | else 34 | FS_OUT_Color = texture(s_Image, FS_IN_TexCoord); 35 | } 36 | 37 | // ------------------------------------------------------------------ 38 | -------------------------------------------------------------------------------- /src/shader/wireframe_fs.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // OUTPUTS ---------------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | out vec4 FS_OUT_Color; 6 | 7 | // ------------------------------------------------------------------ 8 | // MAIN ------------------------------------------------------------- 9 | // ------------------------------------------------------------------ 10 | 11 | void main() 12 | { 13 | FS_OUT_Color = vec4(1.0); 14 | } 15 | 16 | // ------------------------------------------------------------------ --------------------------------------------------------------------------------