├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── data ├── SkyModels_1.jpg └── SkyModels_2.jpg └── src ├── .clang-format ├── CMakeLists.txt ├── bruneton_sky_model.cpp ├── bruneton_sky_model.h ├── hosek_data_rgb.inl ├── hosek_wilkie_sky_model.cpp ├── hosek_wilkie_sky_model.h ├── main.cpp ├── preetham_sky_model.cpp ├── preetham_sky_model.h ├── shader ├── fullscreen_fs.glsl ├── fullscreen_vs.glsl ├── mesh_fs.glsl ├── mesh_vs.glsl ├── sky_fs.glsl ├── sky_models │ ├── bruneton │ │ ├── atmosphere.glsl │ │ ├── copy_inscatter_1_cs.glsl │ │ ├── copy_inscatter_n_cs.glsl │ │ ├── copy_irradiance_cs.glsl │ │ ├── inscatter_1_cs.glsl │ │ ├── inscatter_n_cs.glsl │ │ ├── inscatter_s_cs.glsl │ │ ├── irradiance_1_cs.glsl │ │ ├── irradiance_n_cs.glsl │ │ ├── precompute_common.glsl │ │ └── transmittance_cs.glsl │ ├── hosek_wilkie │ │ └── atmosphere.glsl │ └── preetham │ │ └── atmosphere.glsl └── sky_vs.glsl └── sky_model.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | build/* 35 | build/ 36 | external/* 37 | external/ 38 | bin/ 39 | lib/ 40 | x64/ 41 | x64/* 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("SkyModels") 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) 2019 Dihara Wijetunga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sky Models 2 | A collection of various Sky Model implementations in OpenGL suitable for real-time rendering. 3 | 4 | * Bruneton - [Precomputed Atmospheric Scattering 5 | ](http://www-ljk.imag.fr/Publications/Basilic/com.lmc.publi.PUBLI_Article@11e7cdda2f7_f64b69/article.pdf) 6 | * Preetham - [A Practical Analytic Model for Daylight](https://www.cs.utah.edu/~shirley/papers/sunsky/sunsky.pdf) 7 | * Hosek-Wilkie - [An Analytic Model for Full Spectral Sky-Dome Radiance](https://cgg.mff.cuni.cz/projects/SkylightModelling/HosekWilkie_SkylightModel_SIGGRAPH2012_Preprint_lowres.pdf) 8 | 9 | Bruneton model implementation based on the [Unity port](https://github.com/Scrawk/Brunetons-Atmospheric-Scatter) by Scrawk. 10 | 11 | ## Screenshots 12 | ![SkyModels](data/SkyModels_1.jpg) 13 | ![SkyModels](data/SkyModels_2.jpg) 14 | 15 | ## Dependencies 16 | * [dwSampleFramework](https://github.com/diharaw/dwSampleFramework) 17 | 18 | ## License 19 | ``` 20 | Copyright (c) 2019 Dihara Wijetunga 21 | 22 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 23 | associated documentation files (the "Software"), to deal in the Software without restriction, 24 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 25 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 26 | subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all copies or substantial 29 | portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 32 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 33 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 34 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 35 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 36 | ``` 37 | -------------------------------------------------------------------------------- /data/SkyModels_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/sky-models/c74ce88ccec91aeb9502fb24a7e51e0fb3bfc51a/data/SkyModels_1.jpg -------------------------------------------------------------------------------- /data/SkyModels_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diharaw/sky-models/c74ce88ccec91aeb9502fb24a7e51e0fb3bfc51a/data/SkyModels_2.jpg -------------------------------------------------------------------------------- /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(SKY_MODELS_SOURCES ${PROJECT_SOURCE_DIR}/src/main.cpp 9 | ${PROJECT_SOURCE_DIR}/src/bruneton_sky_model.h 10 | ${PROJECT_SOURCE_DIR}/src/bruneton_sky_model.cpp 11 | ${PROJECT_SOURCE_DIR}/src/preetham_sky_model.h 12 | ${PROJECT_SOURCE_DIR}/src/preetham_sky_model.cpp 13 | ${PROJECT_SOURCE_DIR}/src/hosek_wilkie_sky_model.h 14 | ${PROJECT_SOURCE_DIR}/src/hosek_wilkie_sky_model.cpp 15 | ${PROJECT_SOURCE_DIR}/src/sky_model.h 16 | ${PROJECT_SOURCE_DIR}/src/hosek_data_rgb.inl) 17 | 18 | if (EMSCRIPTEN) 19 | set(CMAKE_EXECUTABLE_SUFFIX ".html") 20 | endif() 21 | 22 | if(APPLE) 23 | add_executable(SkyModels MACOSX_BUNDLE ${SKY_MODELS_SOURCES}) 24 | set(MACOSX_BUNDLE_BUNDLE_NAME "com.dihara.skymodels") 25 | else() 26 | add_executable(SkyModels ${SKY_MODELS_SOURCES}) 27 | endif() 28 | 29 | target_link_libraries(SkyModels dwSampleFramework) 30 | 31 | if (EMSCRIPTEN) 32 | set_target_properties(SkyModels PROPERTIES LINK_FLAGS "--embed-file ${PROJECT_SOURCE_DIR}/shader/fs.glsl@shader/fs.glsl --embed-file ${PROJECT_SOURCE_DIR}/shader/fs.glsl@shader/fs.glsl -O3 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s USE_GLFW=3 -s USE_WEBGL2=1") 33 | endif() 34 | 35 | if (APPLE) 36 | add_custom_command(TARGET SkyModels POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/src/shader $/SkyModels.app/Contents/Resources/shader) 37 | add_custom_command(TARGET SkyModels POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/mesh $/SkyModels.app/Contents/Resources/mesh) 38 | else() 39 | add_custom_command(TARGET SkyModels POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/src/shader $/shader) 40 | add_custom_command(TARGET SkyModels POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data/mesh $/mesh) 41 | endif() 42 | 43 | if(CLANG_FORMAT_EXE) 44 | add_custom_target(clang-format-project-files COMMAND ${CLANG_FORMAT_EXE} -i -style=file ${SKY_MODELS_SOURCES}) 45 | endif() 46 | 47 | set_property(TARGET SkyModels PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin/$(Configuration)") -------------------------------------------------------------------------------- /src/bruneton_sky_model.cpp: -------------------------------------------------------------------------------- 1 | #include "bruneton_sky_model.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // ----------------------------------------------------------------------------------------------------------------------------------- 8 | 9 | BrunetonSkyModel::BrunetonSkyModel() 10 | { 11 | m_transmittance_t = nullptr; 12 | m_irradiance_t[0] = nullptr; 13 | m_irradiance_t[1] = nullptr; 14 | m_inscatter_t[0] = nullptr; 15 | m_inscatter_t[1] = nullptr; 16 | m_delta_et = nullptr; 17 | m_delta_srt = nullptr; 18 | m_delta_smt = nullptr; 19 | m_delta_jt = nullptr; 20 | } 21 | 22 | // ----------------------------------------------------------------------------------------------------------------------------------- 23 | 24 | BrunetonSkyModel::~BrunetonSkyModel() 25 | { 26 | DW_SAFE_DELETE(m_copy_inscatter_1_program); 27 | DW_SAFE_DELETE(m_copy_inscatter_n_program); 28 | DW_SAFE_DELETE(m_copy_irradiance_program); 29 | DW_SAFE_DELETE(m_inscatter_1_program); 30 | DW_SAFE_DELETE(m_inscatter_n_program); 31 | DW_SAFE_DELETE(m_inscatter_s_program); 32 | DW_SAFE_DELETE(m_irradiance_1_program); 33 | DW_SAFE_DELETE(m_irradiance_n_program); 34 | DW_SAFE_DELETE(m_transmittance_program); 35 | 36 | DW_SAFE_DELETE(m_copy_inscatter_1_cs); 37 | DW_SAFE_DELETE(m_copy_inscatter_n_cs); 38 | DW_SAFE_DELETE(m_copy_irradiance_cs); 39 | DW_SAFE_DELETE(m_inscatter_1_cs); 40 | DW_SAFE_DELETE(m_inscatter_n_cs); 41 | DW_SAFE_DELETE(m_inscatter_s_cs); 42 | DW_SAFE_DELETE(m_irradiance_1_cs); 43 | DW_SAFE_DELETE(m_irradiance_n_cs); 44 | DW_SAFE_DELETE(m_transmittance_cs); 45 | 46 | DW_SAFE_DELETE(m_transmittance_t); 47 | DW_SAFE_DELETE(m_delta_et); 48 | DW_SAFE_DELETE(m_delta_srt); 49 | DW_SAFE_DELETE(m_delta_smt); 50 | DW_SAFE_DELETE(m_delta_jt); 51 | DW_SAFE_DELETE(m_irradiance_t[0]); 52 | DW_SAFE_DELETE(m_irradiance_t[0]); 53 | DW_SAFE_DELETE(m_inscatter_t[0]); 54 | DW_SAFE_DELETE(m_inscatter_t[1]); 55 | } 56 | 57 | // ----------------------------------------------------------------------------------------------------------------------------------- 58 | 59 | bool BrunetonSkyModel::initialize() 60 | { 61 | if (!dw::utility::create_compute_program("shader/sky_models/bruneton/copy_inscatter_1_cs.glsl", &m_copy_inscatter_1_cs, &m_copy_inscatter_1_program)) 62 | DW_LOG_ERROR("Failed to load shaders"); 63 | 64 | if (!dw::utility::create_compute_program("shader/sky_models/bruneton/copy_inscatter_n_cs.glsl", &m_copy_inscatter_n_cs, &m_copy_inscatter_n_program)) 65 | DW_LOG_ERROR("Failed to load shaders"); 66 | 67 | if (!dw::utility::create_compute_program("shader/sky_models/bruneton/copy_irradiance_cs.glsl", &m_copy_irradiance_cs, &m_copy_irradiance_program)) 68 | DW_LOG_ERROR("Failed to load shaders"); 69 | 70 | if (!dw::utility::create_compute_program("shader/sky_models/bruneton/inscatter_1_cs.glsl", &m_inscatter_1_cs, &m_inscatter_1_program)) 71 | DW_LOG_ERROR("Failed to load shaders"); 72 | 73 | if (!dw::utility::create_compute_program("shader/sky_models/bruneton/inscatter_n_cs.glsl", &m_inscatter_n_cs, &m_inscatter_n_program)) 74 | DW_LOG_ERROR("Failed to load shaders"); 75 | 76 | if (!dw::utility::create_compute_program("shader/sky_models/bruneton/inscatter_s_cs.glsl", &m_inscatter_s_cs, &m_inscatter_s_program)) 77 | DW_LOG_ERROR("Failed to load shaders"); 78 | 79 | if (!dw::utility::create_compute_program("shader/sky_models/bruneton/irradiance_1_cs.glsl", &m_irradiance_1_cs, &m_irradiance_1_program)) 80 | DW_LOG_ERROR("Failed to load shaders"); 81 | 82 | if (!dw::utility::create_compute_program("shader/sky_models/bruneton/irradiance_n_cs.glsl", &m_irradiance_n_cs, &m_irradiance_n_program)) 83 | DW_LOG_ERROR("Failed to load shaders"); 84 | 85 | if (!dw::utility::create_compute_program("shader/sky_models/bruneton/transmittance_cs.glsl", &m_transmittance_cs, &m_transmittance_program)) 86 | DW_LOG_ERROR("Failed to load shaders"); 87 | 88 | m_transmittance_t = new_texture_2d(TRANSMITTANCE_W, TRANSMITTANCE_H); 89 | 90 | m_irradiance_t[0] = new_texture_2d(IRRADIANCE_W, IRRADIANCE_H); 91 | m_irradiance_t[1] = new_texture_2d(IRRADIANCE_W, IRRADIANCE_H); 92 | 93 | m_inscatter_t[0] = new_texture_3d(INSCATTER_MU_S * INSCATTER_NU, INSCATTER_MU, INSCATTER_R); 94 | m_inscatter_t[1] = new_texture_3d(INSCATTER_MU_S * INSCATTER_NU, INSCATTER_MU, INSCATTER_R); 95 | 96 | m_delta_et = new_texture_2d(IRRADIANCE_W, IRRADIANCE_H); 97 | m_delta_srt = new_texture_3d(INSCATTER_MU_S * INSCATTER_NU, INSCATTER_MU, INSCATTER_R); 98 | m_delta_smt = new_texture_3d(INSCATTER_MU_S * INSCATTER_NU, INSCATTER_MU, INSCATTER_R); 99 | m_delta_jt = new_texture_3d(INSCATTER_MU_S * INSCATTER_NU, INSCATTER_MU, INSCATTER_R); 100 | 101 | if (!load_cached_textures()) 102 | precompute(); 103 | 104 | return true; 105 | } 106 | 107 | // ----------------------------------------------------------------------------------------------------------------------------------- 108 | 109 | void BrunetonSkyModel::update() 110 | { 111 | 112 | } 113 | 114 | // ----------------------------------------------------------------------------------------------------------------------------------- 115 | 116 | void BrunetonSkyModel::set_render_uniforms(dw::Program* program) 117 | { 118 | program->set_uniform("betaR", m_beta_r / SCALE); 119 | program->set_uniform("mieG", m_mie_g); 120 | program->set_uniform("SUN_INTENSITY", m_sun_intensity); 121 | program->set_uniform("EARTH_POS", glm::vec3(0.0f, 6360010.0f, 0.0f)); 122 | program->set_uniform("SUN_DIR", m_direction * 1.0f); 123 | 124 | if (program->set_uniform("s_Transmittance", 0)) 125 | m_transmittance_t->bind(0); 126 | 127 | if (program->set_uniform("s_Irradiance", 1)) 128 | m_irradiance_t[READ]->bind(1); 129 | 130 | if (program->set_uniform("s_Inscatter", 2)) 131 | m_inscatter_t[READ]->bind(2); 132 | } 133 | 134 | // ----------------------------------------------------------------------------------------------------------------------------------- 135 | 136 | void BrunetonSkyModel::set_uniforms(dw::Program* program) 137 | { 138 | program->set_uniform("Rg", Rg); 139 | program->set_uniform("Rt", Rt); 140 | program->set_uniform("RL", RL); 141 | program->set_uniform("TRANSMITTANCE_W", TRANSMITTANCE_W); 142 | program->set_uniform("TRANSMITTANCE_H", TRANSMITTANCE_H); 143 | program->set_uniform("SKY_W", IRRADIANCE_W); 144 | program->set_uniform("SKY_H", IRRADIANCE_H); 145 | program->set_uniform("RES_R", INSCATTER_R); 146 | program->set_uniform("RES_MU", INSCATTER_MU); 147 | program->set_uniform("RES_MU_S", INSCATTER_MU_S); 148 | program->set_uniform("RES_NU", INSCATTER_NU); 149 | program->set_uniform("AVERAGE_GROUND_REFLECTANCE", AVERAGE_GROUND_REFLECTANCE); 150 | program->set_uniform("HR", HR); 151 | program->set_uniform("HM", HM); 152 | program->set_uniform("betaR", BETA_R); 153 | program->set_uniform("betaMSca", BETA_MSca); 154 | program->set_uniform("betaMEx", BETA_MEx); 155 | program->set_uniform("mieG", glm::clamp(MIE_G, 0.0f, 0.99f)); 156 | } 157 | 158 | // ----------------------------------------------------------------------------------------------------------------------------------- 159 | 160 | bool BrunetonSkyModel::load_cached_textures() 161 | { 162 | FILE* transmittance = fopen("transmittance.raw", "r"); 163 | 164 | if (transmittance) 165 | { 166 | size_t n = sizeof(float) * TRANSMITTANCE_W * TRANSMITTANCE_H * 4; 167 | 168 | void* data = malloc(n); 169 | fread(data, n, 1, transmittance); 170 | 171 | m_transmittance_t->set_data(0, 0, data); 172 | 173 | fclose(transmittance); 174 | free(data); 175 | } 176 | else 177 | return false; 178 | 179 | FILE* irradiance = fopen("irradiance.raw", "r"); 180 | 181 | if (irradiance) 182 | { 183 | size_t n = sizeof(float) * IRRADIANCE_W * IRRADIANCE_H * 4; 184 | 185 | void* data = malloc(n); 186 | fread(data, n, 1, irradiance); 187 | 188 | m_irradiance_t[READ]->set_data(0, 0, data); 189 | 190 | fclose(irradiance); 191 | free(data); 192 | } 193 | else 194 | return false; 195 | 196 | FILE* inscatter = fopen("inscatter.raw", "r"); 197 | 198 | if (inscatter) 199 | { 200 | size_t n = sizeof(float) * INSCATTER_MU_S * INSCATTER_NU * INSCATTER_MU * INSCATTER_R * 4; 201 | 202 | void* data = malloc(n); 203 | fread(data, n, 1, inscatter); 204 | 205 | m_inscatter_t[READ]->set_data(0, data); 206 | 207 | fclose(inscatter); 208 | free(data); 209 | } 210 | else 211 | return false; 212 | 213 | return true; 214 | } 215 | 216 | // ----------------------------------------------------------------------------------------------------------------------------------- 217 | 218 | void BrunetonSkyModel::write_textures() 219 | { 220 | { 221 | FILE* transmittance = fopen("transmittance.raw", "wb"); 222 | 223 | size_t n = sizeof(float) * TRANSMITTANCE_W * TRANSMITTANCE_H * 4; 224 | void* data = malloc(n); 225 | 226 | m_transmittance_t->data(0, 0, data); 227 | 228 | fwrite(data, n, 1, transmittance); 229 | 230 | fclose(transmittance); 231 | free(data); 232 | } 233 | 234 | { 235 | FILE* irradiance = fopen("irradiance.raw", "wb"); 236 | 237 | size_t n = sizeof(float) * IRRADIANCE_W * IRRADIANCE_H * 4; 238 | void* data = malloc(n); 239 | 240 | m_irradiance_t[READ]->data(0, 0, data); 241 | 242 | fwrite(data, n, 1, irradiance); 243 | 244 | fclose(irradiance); 245 | free(data); 246 | } 247 | 248 | { 249 | FILE* inscatter = fopen("inscatter.raw", "wb"); 250 | 251 | size_t n = sizeof(float) * INSCATTER_MU_S * INSCATTER_NU * INSCATTER_MU * INSCATTER_R * 4; 252 | void* data = malloc(n); 253 | 254 | m_inscatter_t[READ]->data(0, data); 255 | 256 | fwrite(data, n, 1, inscatter); 257 | 258 | fclose(inscatter); 259 | free(data); 260 | } 261 | } 262 | 263 | // ----------------------------------------------------------------------------------------------------------------------------------- 264 | 265 | void BrunetonSkyModel::precompute() 266 | { 267 | // ----------------------------------------------------------------------------- 268 | // 1. Compute Transmittance Texture T 269 | // ----------------------------------------------------------------------------- 270 | 271 | m_transmittance_program->use(); 272 | set_uniforms(m_transmittance_program); 273 | 274 | m_transmittance_t->bind_image(0, 0, 0, GL_READ_WRITE, m_transmittance_t->internal_format()); 275 | 276 | GL_CHECK_ERROR(glDispatchCompute(TRANSMITTANCE_W/NUM_THREADS, TRANSMITTANCE_H/NUM_THREADS, 1)); 277 | GL_CHECK_ERROR(glFinish()); 278 | 279 | // ----------------------------------------------------------------------------- 280 | // 2. Compute Irradiance Texture deltaE 281 | // ----------------------------------------------------------------------------- 282 | 283 | m_irradiance_1_program->use(); 284 | set_uniforms(m_irradiance_1_program); 285 | 286 | m_delta_et->bind_image(0, 0, 0, GL_READ_WRITE, m_delta_et->internal_format()); 287 | 288 | if (m_irradiance_1_program->set_uniform("s_TransmittanceRead", 0)) 289 | m_transmittance_t->bind(0); 290 | 291 | GL_CHECK_ERROR(glDispatchCompute(IRRADIANCE_W/NUM_THREADS, IRRADIANCE_H/NUM_THREADS, 1)); 292 | GL_CHECK_ERROR(glFinish()); 293 | 294 | // ----------------------------------------------------------------------------- 295 | // 3. Compute Single Scattering Texture 296 | // ----------------------------------------------------------------------------- 297 | 298 | m_inscatter_1_program->use(); 299 | set_uniforms(m_inscatter_1_program); 300 | 301 | m_delta_srt->bind_image(0, 0, 0, GL_READ_WRITE, m_delta_srt->internal_format()); 302 | m_delta_smt->bind_image(1, 0, 0, GL_READ_WRITE, m_delta_smt->internal_format()); 303 | 304 | if (m_inscatter_1_program->set_uniform("s_TransmittanceRead", 0)) 305 | m_transmittance_t->bind(0); 306 | 307 | for (int i = 0; i < INSCATTER_R; i++) 308 | { 309 | m_inscatter_1_program->set_uniform("u_Layer", i); 310 | GL_CHECK_ERROR(glDispatchCompute((INSCATTER_MU_S*INSCATTER_NU)/NUM_THREADS, INSCATTER_MU/NUM_THREADS, 1)); 311 | GL_CHECK_ERROR(glFinish()); 312 | } 313 | 314 | // ----------------------------------------------------------------------------- 315 | // 4. Copy deltaE into Irradiance Texture E 316 | // ----------------------------------------------------------------------------- 317 | 318 | m_copy_irradiance_program->use(); 319 | set_uniforms(m_copy_irradiance_program); 320 | 321 | m_copy_irradiance_program->set_uniform("u_K", 0.0f); 322 | 323 | m_irradiance_t[WRITE]->bind_image(0, 0, 0, GL_READ_WRITE, m_irradiance_t[WRITE]->internal_format()); 324 | 325 | if (m_copy_irradiance_program->set_uniform("s_DeltaERead", 0)) 326 | m_delta_et->bind(0); 327 | 328 | if (m_copy_irradiance_program->set_uniform("s_IrradianceRead", 1)) 329 | m_irradiance_t[READ]->bind(1); 330 | 331 | GL_CHECK_ERROR(glDispatchCompute(IRRADIANCE_W/NUM_THREADS, IRRADIANCE_H/NUM_THREADS, 1)); 332 | GL_CHECK_ERROR(glFinish()); 333 | 334 | for (int order = 2; order < 4; order++) 335 | { 336 | // ----------------------------------------------------------------------------- 337 | // 5. Copy deltaS into Inscatter Texture S 338 | // ----------------------------------------------------------------------------- 339 | 340 | m_copy_inscatter_1_program->use(); 341 | set_uniforms(m_copy_inscatter_1_program); 342 | 343 | m_inscatter_t[WRITE]->bind_image(0, 0, 0, GL_READ_WRITE, m_inscatter_t[WRITE]->internal_format()); 344 | 345 | if (m_copy_inscatter_1_program->set_uniform("s_DeltaSRRead", 0)) 346 | m_delta_srt->bind(0); 347 | 348 | if (m_copy_inscatter_1_program->set_uniform("s_DeltaSMRead", 1)) 349 | m_delta_smt->bind(1); 350 | 351 | for (int i = 0; i < INSCATTER_R; i++) 352 | { 353 | m_copy_inscatter_1_program->set_uniform("u_Layer", i); 354 | GL_CHECK_ERROR(glDispatchCompute((INSCATTER_MU_S*INSCATTER_NU)/NUM_THREADS, INSCATTER_MU/NUM_THREADS, 1)); 355 | GL_CHECK_ERROR(glFinish()); 356 | } 357 | 358 | swap(m_inscatter_t); 359 | 360 | // ----------------------------------------------------------------------------- 361 | // 6. Compute deltaJ 362 | // ----------------------------------------------------------------------------- 363 | 364 | m_inscatter_s_program->use(); 365 | set_uniforms(m_inscatter_s_program); 366 | 367 | m_inscatter_s_program->set_uniform("first", (order == 2) ? 1 : 0); 368 | 369 | m_delta_jt->bind_image(0, 0, 0, GL_READ_WRITE, m_delta_jt->internal_format()); 370 | 371 | if (m_inscatter_s_program->set_uniform("s_TransmittanceRead", 0)) 372 | m_transmittance_t->bind(0); 373 | 374 | if (m_inscatter_s_program->set_uniform("s_DeltaERead", 1)) 375 | m_delta_et->bind(1); 376 | 377 | if (m_inscatter_s_program->set_uniform("s_DeltaSRRead", 2)) 378 | m_delta_srt->bind(2); 379 | 380 | if (m_inscatter_s_program->set_uniform("s_DeltaSMRead", 3)) 381 | m_delta_smt->bind(3); 382 | 383 | for (int i = 0; i < INSCATTER_R; i++) 384 | { 385 | m_inscatter_s_program->set_uniform("u_Layer", i); 386 | GL_CHECK_ERROR(glDispatchCompute((INSCATTER_MU_S*INSCATTER_NU)/NUM_THREADS, INSCATTER_MU/NUM_THREADS, 1)); 387 | GL_CHECK_ERROR(glFinish()); 388 | } 389 | 390 | // ----------------------------------------------------------------------------- 391 | // 7. Compute deltaE 392 | // ----------------------------------------------------------------------------- 393 | 394 | m_irradiance_n_program->use(); 395 | set_uniforms(m_irradiance_n_program); 396 | 397 | m_irradiance_n_program->set_uniform("first", (order == 2) ? 1 : 0); 398 | 399 | m_delta_et->bind_image(0, 0, 0, GL_READ_WRITE, m_delta_et->internal_format()); 400 | 401 | if (m_irradiance_n_program->set_uniform("s_DeltaSRRead", 0)) 402 | m_delta_srt->bind(0); 403 | 404 | if (m_irradiance_n_program->set_uniform("s_DeltaSMRead", 1)) 405 | m_delta_smt->bind(1); 406 | 407 | GL_CHECK_ERROR(glDispatchCompute(IRRADIANCE_W/NUM_THREADS, IRRADIANCE_H/NUM_THREADS, 1)); 408 | GL_CHECK_ERROR(glFinish()); 409 | 410 | // ----------------------------------------------------------------------------- 411 | // 8. Compute deltaS 412 | // ----------------------------------------------------------------------------- 413 | 414 | m_inscatter_n_program->use(); 415 | set_uniforms(m_inscatter_n_program); 416 | 417 | m_inscatter_n_program->set_uniform("first", (order == 2) ? 1 : 0); 418 | 419 | m_delta_srt->bind_image(0, 0, 0, GL_READ_WRITE, m_delta_srt->internal_format()); 420 | 421 | if (m_inscatter_n_program->set_uniform("s_TransmittanceRead", 0)) 422 | m_transmittance_t->bind(0); 423 | 424 | if (m_inscatter_n_program->set_uniform("s_DeltaJRead", 1)) 425 | m_delta_jt->bind(1); 426 | 427 | for (int i = 0; i < INSCATTER_R; i++) 428 | { 429 | m_inscatter_n_program->set_uniform("u_Layer", i); 430 | GL_CHECK_ERROR(glDispatchCompute((INSCATTER_MU_S*INSCATTER_NU)/NUM_THREADS, INSCATTER_MU/NUM_THREADS, 1)); 431 | GL_CHECK_ERROR(glFinish()); 432 | } 433 | 434 | // ----------------------------------------------------------------------------- 435 | // 9. Adds deltaE into Irradiance Texture E 436 | // ----------------------------------------------------------------------------- 437 | 438 | m_copy_irradiance_program->use(); 439 | set_uniforms(m_copy_irradiance_program); 440 | 441 | m_copy_irradiance_program->set_uniform("u_K", 1.0f); 442 | 443 | m_irradiance_t[WRITE]->bind_image(0, 0, 0, GL_READ_WRITE, m_irradiance_t[WRITE]->internal_format()); 444 | 445 | if (m_copy_irradiance_program->set_uniform("s_DeltaERead", 0)) 446 | m_delta_et->bind(0); 447 | 448 | if (m_copy_irradiance_program->set_uniform("s_IrradianceRead", 1)) 449 | m_irradiance_t[READ]->bind(1); 450 | 451 | GL_CHECK_ERROR(glDispatchCompute(IRRADIANCE_W/NUM_THREADS, IRRADIANCE_H/NUM_THREADS, 1)); 452 | GL_CHECK_ERROR(glFinish()); 453 | 454 | swap(m_irradiance_t); 455 | 456 | // ----------------------------------------------------------------------------- 457 | // 10. Adds deltaS into Inscatter Texture S 458 | // ----------------------------------------------------------------------------- 459 | 460 | m_copy_inscatter_n_program->use(); 461 | set_uniforms(m_copy_inscatter_n_program); 462 | 463 | m_inscatter_t[WRITE]->bind_image(0, 0, 0, GL_READ_WRITE, m_inscatter_t[WRITE]->internal_format()); 464 | 465 | if (m_copy_inscatter_n_program->set_uniform("s_InscatterRead", 0)) 466 | m_inscatter_t[READ]->bind(0); 467 | 468 | if (m_copy_inscatter_n_program->set_uniform("s_DeltaSRead", 1)) 469 | m_delta_srt->bind(1); 470 | 471 | for (int i = 0; i < INSCATTER_R; i++) 472 | { 473 | m_copy_inscatter_n_program->set_uniform("u_Layer", i); 474 | GL_CHECK_ERROR(glDispatchCompute((INSCATTER_MU_S*INSCATTER_NU)/NUM_THREADS, INSCATTER_MU/NUM_THREADS, 1)); 475 | GL_CHECK_ERROR(glFinish()); 476 | } 477 | 478 | swap(m_inscatter_t); 479 | } 480 | 481 | // ----------------------------------------------------------------------------- 482 | // 11. Save to disk 483 | // ----------------------------------------------------------------------------- 484 | 485 | write_textures(); 486 | } 487 | 488 | // ----------------------------------------------------------------------------------------------------------------------------------- 489 | 490 | dw::Texture2D* BrunetonSkyModel::new_texture_2d(int width, int height) 491 | { 492 | dw::Texture2D* texture = new dw::Texture2D(width, height, 1, 1, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 493 | texture->set_min_filter(GL_LINEAR); 494 | texture->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 495 | 496 | return texture; 497 | } 498 | 499 | // ----------------------------------------------------------------------------------------------------------------------------------- 500 | 501 | dw::Texture3D* BrunetonSkyModel::new_texture_3d(int width, int height, int depth) 502 | { 503 | dw::Texture3D* texture = new dw::Texture3D(width, height, depth, 1, GL_RGBA32F, GL_RGBA, GL_FLOAT); 504 | texture->set_min_filter(GL_LINEAR); 505 | texture->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 506 | 507 | return texture; 508 | } 509 | 510 | // ----------------------------------------------------------------------------------------------------------------------------------- 511 | 512 | void BrunetonSkyModel::swap(dw::Texture2D** arr) 513 | { 514 | dw::Texture2D* tmp = arr[READ]; 515 | arr[READ] = arr[WRITE]; 516 | arr[WRITE] = tmp; 517 | } 518 | 519 | // ----------------------------------------------------------------------------------------------------------------------------------- 520 | 521 | void BrunetonSkyModel::swap(dw::Texture3D** arr) 522 | { 523 | dw::Texture3D* tmp = arr[READ]; 524 | arr[READ] = arr[WRITE]; 525 | arr[WRITE] = tmp; 526 | } 527 | 528 | // ----------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /src/bruneton_sky_model.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sky_model.h" 4 | #include 5 | 6 | class BrunetonSkyModel : public SkyModel 7 | { 8 | private: 9 | //Dont change these 10 | const int NUM_THREADS = 8; 11 | const int READ = 0; 12 | const int WRITE = 1; 13 | const float SCALE = 1000.0f; 14 | 15 | //Will save the tables as 8 bit png files so they can be 16 | //viewed in photoshop. Used for debugging. 17 | const bool WRITE_DEBUG_TEX = false; 18 | 19 | //You can change these 20 | //The radius of the planet (Rg), radius of the atmosphere (Rt) 21 | const float Rg = 6360.0f; 22 | const float Rt = 6420.0f; 23 | const float RL = 6421.0f; 24 | 25 | //Dimensions of the tables 26 | const int TRANSMITTANCE_W = 256; 27 | const int TRANSMITTANCE_H = 64; 28 | 29 | const int IRRADIANCE_W = 64; 30 | const int IRRADIANCE_H = 16; 31 | 32 | const int INSCATTER_R = 32; 33 | const int INSCATTER_MU = 128; 34 | const int INSCATTER_MU_S = 32; 35 | const int INSCATTER_NU = 8; 36 | 37 | //Physical settings, Mie and Rayliegh values 38 | const float AVERAGE_GROUND_REFLECTANCE = 0.1f; 39 | const glm::vec4 BETA_R = glm::vec4(5.8e-3f, 1.35e-2f, 3.31e-2f, 0.0f); 40 | const glm::vec4 BETA_MSca = glm::vec4(4e-3f, 4e-3f, 4e-3f, 0.0f); 41 | const glm::vec4 BETA_MEx = glm::vec4(4.44e-3f, 4.44e-3f, 4.44e-3f, 0.0f); 42 | 43 | //Asymmetry factor for the mie phase function 44 | //A higher number meands more light is scattered in the forward direction 45 | const float MIE_G = 0.8f; 46 | 47 | //Half heights for the atmosphere air density (HR) and particle density (HM) 48 | //This is the height in km that half the particles are found below 49 | const float HR = 8.0f; 50 | const float HM = 1.2f; 51 | 52 | glm::vec3 m_beta_r = glm::vec3(0.0058f, 0.0135f, 0.0331f); 53 | float m_mie_g = 0.75f; 54 | float m_sun_intensity = 100.0f; 55 | 56 | dw::Texture2D* m_transmittance_t; 57 | dw::Texture2D* m_delta_et; 58 | dw::Texture3D* m_delta_srt; 59 | dw::Texture3D* m_delta_smt; 60 | dw::Texture3D* m_delta_jt; 61 | dw::Texture2D* m_irradiance_t[2]; 62 | dw::Texture3D* m_inscatter_t[2]; 63 | 64 | dw::Shader* m_copy_inscatter_1_cs; 65 | dw::Shader* m_copy_inscatter_n_cs; 66 | dw::Shader* m_copy_irradiance_cs; 67 | dw::Shader* m_inscatter_1_cs; 68 | dw::Shader* m_inscatter_n_cs; 69 | dw::Shader* m_inscatter_s_cs; 70 | dw::Shader* m_irradiance_1_cs; 71 | dw::Shader* m_irradiance_n_cs; 72 | dw::Shader* m_transmittance_cs; 73 | 74 | dw::Program* m_copy_inscatter_1_program; 75 | dw::Program* m_copy_inscatter_n_program; 76 | dw::Program* m_copy_irradiance_program; 77 | dw::Program* m_inscatter_1_program; 78 | dw::Program* m_inscatter_n_program; 79 | dw::Program* m_inscatter_s_program; 80 | dw::Program* m_irradiance_1_program; 81 | dw::Program* m_irradiance_n_program; 82 | dw::Program* m_transmittance_program; 83 | 84 | public: 85 | BrunetonSkyModel(); 86 | ~BrunetonSkyModel(); 87 | 88 | bool initialize() override; 89 | void update() override; 90 | void set_render_uniforms(dw::Program* program) override; 91 | 92 | private: 93 | void set_uniforms(dw::Program* program); 94 | bool load_cached_textures(); 95 | void write_textures(); 96 | void precompute(); 97 | dw::Texture2D* new_texture_2d(int width, int height); 98 | dw::Texture3D* new_texture_3d(int width, int height, int depth); 99 | void swap(dw::Texture2D** arr); 100 | void swap(dw::Texture3D** arr); 101 | }; -------------------------------------------------------------------------------- /src/hosek_wilkie_sky_model.cpp: -------------------------------------------------------------------------------- 1 | #include "hosek_wilkie_sky_model.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define _USE_MATH_DEFINES 8 | #include 9 | 10 | #include "hosek_data_rgb.inl" 11 | 12 | // ----------------------------------------------------------------------------------------------------------------------------------- 13 | 14 | 15 | double evaluate_spline(const double* spline, size_t stride, double value) 16 | { 17 | return 18 | 1 * pow(1 - value, 5) * spline[0 * stride] + 19 | 5 * pow(1 - value, 4) * pow(value, 1) * spline[1 * stride] + 20 | 10 * pow(1 - value, 3) * pow(value, 2) * spline[2 * stride] + 21 | 10 * pow(1 - value, 2) * pow(value, 3) * spline[3 * stride] + 22 | 5 * pow(1 - value, 1) * pow(value, 4) * spline[4 * stride] + 23 | 1 * pow(value, 5) * spline[5 * stride]; 24 | } 25 | 26 | // ----------------------------------------------------------------------------------------------------------------------------------- 27 | 28 | double evaluate(const double * dataset, size_t stride, float turbidity, float albedo, float sunTheta) 29 | { 30 | // splines are functions of elevation^1/3 31 | double elevationK = pow(std::max(0.f, 1.f - sunTheta / (M_PI / 2.f)), 1.f / 3.0f); 32 | 33 | // table has values for turbidity 1..10 34 | int turbidity0 = glm::clamp(static_cast(turbidity), 1, 10); 35 | int turbidity1 = std::min(turbidity0 + 1, 10); 36 | float turbidityK = glm::clamp(turbidity - turbidity0, 0.f, 1.f); 37 | 38 | const double * datasetA0 = dataset; 39 | const double * datasetA1 = dataset + stride * 6 * 10; 40 | 41 | double a0t0 = evaluate_spline(datasetA0 + stride * 6 * (turbidity0 - 1), stride, elevationK); 42 | double a1t0 = evaluate_spline(datasetA1 + stride * 6 * (turbidity0 - 1), stride, elevationK); 43 | double a0t1 = evaluate_spline(datasetA0 + stride * 6 * (turbidity1 - 1), stride, elevationK); 44 | double a1t1 = evaluate_spline(datasetA1 + stride * 6 * (turbidity1 - 1), stride, elevationK); 45 | 46 | return a0t0 * (1 - albedo) * (1 - turbidityK) + a1t0 * albedo * (1 - turbidityK) + a0t1 * (1 - albedo) * turbidityK + a1t1 * albedo * turbidityK; 47 | } 48 | 49 | // ----------------------------------------------------------------------------------------------------------------------------------- 50 | 51 | glm::vec3 hosek_wilkie(float cos_theta, float gamma, float cos_gamma, glm::vec3 A, glm::vec3 B, glm::vec3 C, glm::vec3 D, glm::vec3 E, glm::vec3 F, glm::vec3 G, glm::vec3 H, glm::vec3 I) 52 | { 53 | glm::vec3 chi = (1.f + cos_gamma * cos_gamma) / pow(1.f + H * H - 2.f * cos_gamma * H, glm::vec3(1.5f)); 54 | return (1.f + A * exp(B / (cos_theta + 0.01f))) * (C + D * exp(E * gamma) + F * (cos_gamma * cos_gamma) + G * chi + I * (float) sqrt(std::max(0.f, cos_theta))); 55 | } 56 | 57 | // ----------------------------------------------------------------------------------------------------------------------------------- 58 | 59 | HosekWilkieSkyModel::HosekWilkieSkyModel() 60 | { 61 | 62 | } 63 | 64 | // ----------------------------------------------------------------------------------------------------------------------------------- 65 | 66 | HosekWilkieSkyModel::~HosekWilkieSkyModel() 67 | { 68 | 69 | } 70 | 71 | // ----------------------------------------------------------------------------------------------------------------------------------- 72 | 73 | bool HosekWilkieSkyModel::initialize() 74 | { 75 | return true; 76 | } 77 | 78 | // ----------------------------------------------------------------------------------------------------------------------------------- 79 | 80 | void HosekWilkieSkyModel::update() 81 | { 82 | const float sunTheta = std::acos(glm::clamp(m_direction.y, 0.f, 1.f)); 83 | 84 | for (int i = 0; i < 3; ++i) 85 | { 86 | A[i] = evaluate(datasetsRGB[i] + 0, 9, m_turbidity, m_albedo, sunTheta); 87 | B[i] = evaluate(datasetsRGB[i] + 1, 9, m_turbidity, m_albedo, sunTheta); 88 | C[i] = evaluate(datasetsRGB[i] + 2, 9, m_turbidity, m_albedo, sunTheta); 89 | D[i] = evaluate(datasetsRGB[i] + 3, 9, m_turbidity, m_albedo, sunTheta); 90 | E[i] = evaluate(datasetsRGB[i] + 4, 9, m_turbidity, m_albedo, sunTheta); 91 | F[i] = evaluate(datasetsRGB[i] + 5, 9, m_turbidity, m_albedo, sunTheta); 92 | G[i] = evaluate(datasetsRGB[i] + 6, 9, m_turbidity, m_albedo, sunTheta); 93 | 94 | // Swapped in the dataset 95 | H[i] = evaluate(datasetsRGB[i] + 8, 9, m_turbidity, m_albedo, sunTheta); 96 | I[i] = evaluate(datasetsRGB[i] + 7, 9, m_turbidity, m_albedo, sunTheta); 97 | 98 | Z[i] = evaluate(datasetsRGBRad[i], 1, m_turbidity, m_albedo, sunTheta); 99 | } 100 | 101 | if (m_normalized_sun_y) 102 | { 103 | glm::vec3 S = hosek_wilkie(std::cos(sunTheta), 0, 1.f, A, B, C, D, E, F, G, H, I) * Z; 104 | Z /= glm::dot(S, glm::vec3(0.2126, 0.7152, 0.0722)); 105 | Z *= m_normalized_sun_y; 106 | } 107 | } 108 | 109 | // ----------------------------------------------------------------------------------------------------------------------------------- 110 | 111 | void HosekWilkieSkyModel::set_render_uniforms(dw::Program* program) 112 | { 113 | program->set_uniform("u_Direction", m_direction); 114 | program->set_uniform("A", A); 115 | program->set_uniform("B", B); 116 | program->set_uniform("C", C); 117 | program->set_uniform("D", D); 118 | program->set_uniform("E", E); 119 | program->set_uniform("F", F); 120 | program->set_uniform("G", G); 121 | program->set_uniform("H", H); 122 | program->set_uniform("I", I); 123 | program->set_uniform("Z", Z); 124 | } 125 | 126 | // ----------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /src/hosek_wilkie_sky_model.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sky_model.h" 4 | 5 | // An Analytic Model for Full Spectral Sky-Dome Radiance (Lukas Hosek, Alexander Wilkie) 6 | class HosekWilkieSkyModel : public SkyModel 7 | { 8 | public: 9 | HosekWilkieSkyModel(); 10 | ~HosekWilkieSkyModel(); 11 | 12 | bool initialize() override; 13 | void update() override; 14 | void set_render_uniforms(dw::Program* program) override; 15 | 16 | private: 17 | glm::vec3 A, B, C, D, E, F, G, H, I; 18 | glm::vec3 Z; 19 | }; -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "bruneton_sky_model.h" 11 | #include "preetham_sky_model.h" 12 | #include "hosek_wilkie_sky_model.h" 13 | 14 | // Uniform buffer data structure. 15 | struct ObjectUniforms 16 | { 17 | DW_ALIGNED(16) glm::mat4 model; 18 | }; 19 | 20 | struct GlobalUniforms 21 | { 22 | DW_ALIGNED(16) glm::mat4 view; 23 | DW_ALIGNED(16) glm::mat4 projection; 24 | DW_ALIGNED(16) glm::mat4 inv_view; 25 | DW_ALIGNED(16) glm::mat4 inv_projection; 26 | DW_ALIGNED(16) glm::mat4 inv_view_projection; 27 | DW_ALIGNED(16) glm::vec4 view_pos; 28 | }; 29 | 30 | #define CAMERA_FAR_PLANE 10000.0f 31 | 32 | class SkyModels : public dw::Application 33 | { 34 | protected: 35 | 36 | // ----------------------------------------------------------------------------------------------------------------------------------- 37 | 38 | bool init(int argc, const char* argv[]) override 39 | { 40 | // Create GPU resources. 41 | if (!create_shaders()) 42 | return false; 43 | 44 | if (!create_uniform_buffer()) 45 | return false; 46 | 47 | // Load mesh. 48 | if (!load_mesh()) 49 | return false; 50 | 51 | if (!create_framebuffer()) 52 | return false; 53 | 54 | // Create camera. 55 | create_camera(); 56 | 57 | m_mesh_transforms.model = glm::mat4(1.0f); 58 | 59 | m_sun_angle = glm::radians(-180.0f); 60 | 61 | return m_bruneton_model.initialize() && m_preetham_model.initialize() && m_hosek_wilkie_model.initialize(); 62 | } 63 | 64 | // ----------------------------------------------------------------------------------------------------------------------------------- 65 | 66 | void update(double delta) override 67 | { 68 | // Update camera. 69 | update_camera(); 70 | 71 | update_global_uniforms(m_global_uniforms); 72 | update_object_uniforms(m_mesh_transforms); 73 | 74 | if (m_show_gui) 75 | ui(); 76 | 77 | m_bruneton_model.set_direction(m_direction); 78 | m_preetham_model.set_direction(m_direction); 79 | m_hosek_wilkie_model.set_direction(m_direction); 80 | 81 | if (m_sky_model == 0) 82 | m_bruneton_model.update(); 83 | else if (m_sky_model == 1) 84 | m_preetham_model.update(); 85 | else if (m_sky_model == 2) 86 | m_hosek_wilkie_model.update(); 87 | 88 | render_meshes(); 89 | 90 | render_cubemap(); 91 | 92 | render_fullscreen_triangle(); 93 | 94 | if (m_debug_mode) 95 | m_debug_draw.frustum(m_main_camera->m_view_projection, glm::vec3(0.0f, 1.0f, 0.0f)); 96 | 97 | // Render debug draw. 98 | m_debug_draw.render(nullptr, m_width, m_height, m_debug_mode ? m_debug_camera->m_view_projection : m_main_camera->m_view_projection); 99 | } 100 | 101 | // ----------------------------------------------------------------------------------------------------------------------------------- 102 | 103 | void shutdown() override 104 | { 105 | dw::Mesh::unload(m_mesh); 106 | } 107 | 108 | // ----------------------------------------------------------------------------------------------------------------------------------- 109 | 110 | void window_resized(int width, int height) override 111 | { 112 | // Override window resized method to update camera projection. 113 | m_main_camera->update_projection(60.0f, 0.1f, CAMERA_FAR_PLANE, float(m_width) / float(m_height)); 114 | m_debug_camera->update_projection(60.0f, 0.1f, CAMERA_FAR_PLANE * 2.0f, float(m_width) / float(m_height)); 115 | 116 | create_framebuffer(); 117 | } 118 | 119 | // ----------------------------------------------------------------------------------------------------------------------------------- 120 | 121 | void key_pressed(int code) override 122 | { 123 | // Handle forward movement. 124 | if(code == GLFW_KEY_W) 125 | m_heading_speed = m_camera_speed; 126 | else if(code == GLFW_KEY_S) 127 | m_heading_speed = -m_camera_speed; 128 | 129 | // Handle sideways movement. 130 | if(code == GLFW_KEY_A) 131 | m_sideways_speed = -m_camera_speed; 132 | else if(code == GLFW_KEY_D) 133 | m_sideways_speed = m_camera_speed; 134 | 135 | if (code == GLFW_KEY_K) 136 | m_debug_mode = !m_debug_mode; 137 | } 138 | 139 | // ----------------------------------------------------------------------------------------------------------------------------------- 140 | 141 | void key_released(int code) override 142 | { 143 | // Handle forward movement. 144 | if(code == GLFW_KEY_W || code == GLFW_KEY_S) 145 | m_heading_speed = 0.0f; 146 | 147 | // Handle sideways movement. 148 | if(code == GLFW_KEY_A || code == GLFW_KEY_D) 149 | m_sideways_speed = 0.0f; 150 | 151 | if (code == GLFW_KEY_G) 152 | m_show_gui = !m_show_gui; 153 | } 154 | 155 | // ----------------------------------------------------------------------------------------------------------------------------------- 156 | 157 | void mouse_pressed(int code) override 158 | { 159 | // Enable mouse look. 160 | if (code == GLFW_MOUSE_BUTTON_RIGHT) 161 | m_mouse_look = true; 162 | } 163 | 164 | // ----------------------------------------------------------------------------------------------------------------------------------- 165 | 166 | void mouse_released(int code) override 167 | { 168 | // Disable mouse look. 169 | if (code == GLFW_MOUSE_BUTTON_RIGHT) 170 | m_mouse_look = false; 171 | } 172 | 173 | // ----------------------------------------------------------------------------------------------------------------------------------- 174 | 175 | protected: 176 | 177 | // ----------------------------------------------------------------------------------------------------------------------------------- 178 | 179 | dw::AppSettings intial_app_settings() override 180 | { 181 | dw::AppSettings settings; 182 | 183 | settings.resizable = true; 184 | settings.maximized = false; 185 | settings.refresh_rate = 60; 186 | settings.major_ver = 4; 187 | settings.width = 1280; 188 | settings.height = 720; 189 | settings.title = "Sky Models"; 190 | 191 | return settings; 192 | } 193 | 194 | // ----------------------------------------------------------------------------------------------------------------------------------- 195 | 196 | private: 197 | 198 | // ----------------------------------------------------------------------------------------------------------------------------------- 199 | 200 | void ui() 201 | { 202 | ImGui::InputFloat("Exposure", &m_exposure); 203 | ImGui::SliderAngle("Sun Angle", &m_sun_angle, 0.0f, -180.0f); 204 | 205 | const char* sky_models[] = { "Bruneton", "Preetham", "Hosek-Wilkie" }; 206 | ImGui::Combo("Sky Model", &m_sky_model, sky_models, IM_ARRAYSIZE(sky_models)); 207 | 208 | float turbidity = 0.0f; 209 | 210 | if (m_sky_model > 0) 211 | { 212 | if (m_sky_model == 1) 213 | turbidity = m_preetham_model.turbidity(); 214 | if (m_sky_model == 2) 215 | turbidity = m_hosek_wilkie_model.turbidity(); 216 | 217 | ImGui::SliderFloat("Turbidity", &turbidity, 2.0f, 30.0f); 218 | 219 | if (m_sky_model == 1) 220 | m_preetham_model.set_turbidity(turbidity); 221 | if (m_sky_model == 2) 222 | m_hosek_wilkie_model.set_turbidity(turbidity); 223 | } 224 | 225 | m_direction = glm::normalize(glm::vec3(0.0f, sin(m_sun_angle), cos(m_sun_angle))); 226 | 227 | ImGui::Text("Sun Direction = [ %f, %f, %f ]", m_direction.x, m_direction.y, m_direction.z); 228 | } 229 | 230 | // ----------------------------------------------------------------------------------------------------------------------------------- 231 | 232 | bool create_shaders() 233 | { 234 | { 235 | // Create general shaders 236 | m_mesh_vs = std::unique_ptr(dw::Shader::create_from_file(GL_VERTEX_SHADER, "shader/mesh_vs.glsl")); 237 | m_mesh_fs = std::unique_ptr(dw::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/mesh_fs.glsl")); 238 | 239 | if (!m_mesh_vs || !m_mesh_fs) 240 | { 241 | DW_LOG_FATAL("Failed to create Shaders"); 242 | return false; 243 | } 244 | 245 | // Create general shader program 246 | dw::Shader* shaders[] = { m_mesh_vs.get(), m_mesh_fs.get() }; 247 | m_mesh_program = std::make_unique(2, shaders); 248 | 249 | if (!m_mesh_program) 250 | { 251 | DW_LOG_FATAL("Failed to create Shader Program"); 252 | return false; 253 | } 254 | 255 | m_mesh_program->uniform_block_binding("u_GlobalUBO", 0); 256 | m_mesh_program->uniform_block_binding("u_ObjectUBO", 1); 257 | } 258 | 259 | { 260 | m_fullscreen_vs = std::unique_ptr(dw::Shader::create_from_file(GL_VERTEX_SHADER, "shader/fullscreen_vs.glsl")); 261 | m_fullscreen_fs = std::unique_ptr(dw::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/fullscreen_fs.glsl")); 262 | 263 | if (!m_fullscreen_vs || !m_fullscreen_fs) 264 | { 265 | DW_LOG_FATAL("Failed to create Shaders"); 266 | return false; 267 | } 268 | 269 | // Create general shader program 270 | dw::Shader* shaders[] = { m_fullscreen_vs.get(), m_fullscreen_fs.get() }; 271 | m_fullscreen_program = std::make_unique(2, shaders); 272 | 273 | if (!m_fullscreen_program) 274 | { 275 | DW_LOG_FATAL("Failed to create Shader Program"); 276 | return false; 277 | } 278 | } 279 | 280 | { 281 | m_sky_vs = std::unique_ptr(dw::Shader::create_from_file(GL_VERTEX_SHADER, "shader/sky_vs.glsl")); 282 | m_sky_fs = std::unique_ptr(dw::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/sky_fs.glsl")); 283 | 284 | if (!m_sky_vs || !m_sky_fs) 285 | { 286 | DW_LOG_FATAL("Failed to create Shaders"); 287 | return false; 288 | } 289 | 290 | // Create general shader program 291 | dw::Shader* shaders[] = { m_sky_vs.get(), m_sky_fs.get() }; 292 | m_sky_program = std::make_unique(2, shaders); 293 | 294 | if (!m_sky_program) 295 | { 296 | DW_LOG_FATAL("Failed to create Shader Program"); 297 | return false; 298 | } 299 | 300 | m_sky_program->uniform_block_binding("u_GlobalUBO", 0); 301 | } 302 | 303 | return true; 304 | } 305 | 306 | // ----------------------------------------------------------------------------------------------------------------------------------- 307 | 308 | bool create_uniform_buffer() 309 | { 310 | // Create uniform buffer for object matrix data 311 | m_object_ubo = std::make_unique(GL_DYNAMIC_DRAW, sizeof(ObjectUniforms)); 312 | 313 | // Create uniform buffer for global data 314 | m_global_ubo = std::make_unique(GL_DYNAMIC_DRAW, sizeof(GlobalUniforms)); 315 | 316 | return true; 317 | } 318 | 319 | // ----------------------------------------------------------------------------------------------------------------------------------- 320 | 321 | bool create_framebuffer() 322 | { 323 | if (m_fbo) 324 | m_fbo.reset(); 325 | 326 | if (m_color_rt) 327 | m_color_rt.reset(); 328 | 329 | if (m_depth_rt) 330 | m_depth_rt.reset(); 331 | 332 | m_color_rt = std::make_unique(m_width, m_height, 1, 1, 1, GL_RGB16F, GL_RGB, GL_HALF_FLOAT); 333 | m_color_rt->set_min_filter(GL_LINEAR); 334 | m_color_rt->set_wrapping(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 335 | 336 | m_depth_rt = std::make_unique(m_width, m_height, 1, 1, 1, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); 337 | m_depth_rt->set_min_filter(GL_LINEAR); 338 | 339 | m_fbo = std::make_unique(); 340 | 341 | m_fbo->attach_render_target(0, m_color_rt.get(), 0, 0); 342 | m_fbo->attach_depth_stencil_target(m_depth_rt.get(), 0, 0); 343 | 344 | return true; 345 | } 346 | 347 | // ----------------------------------------------------------------------------------------------------------------------------------- 348 | 349 | bool load_mesh() 350 | { 351 | m_mesh = dw::Mesh::load("mesh/teapot_smooth.obj"); 352 | 353 | if (!m_mesh) 354 | { 355 | DW_LOG_FATAL("Failed to load mesh!"); 356 | return false; 357 | } 358 | 359 | return true; 360 | } 361 | 362 | // ----------------------------------------------------------------------------------------------------------------------------------- 363 | 364 | void create_camera() 365 | { 366 | m_main_camera = std::make_unique(60.0f, 0.1f, CAMERA_FAR_PLANE, float(m_width) / float(m_height), glm::vec3(0.0f, 5.0f, 150.0f), glm::vec3(0.0f, 0.0, -1.0f)); 367 | m_debug_camera = std::make_unique(60.0f, 0.1f, CAMERA_FAR_PLANE * 2.0f, float(m_width) / float(m_height), glm::vec3(0.0f, 5.0f, 150.0f), glm::vec3(0.0f, 0.0, -1.0f)); 368 | } 369 | 370 | // ----------------------------------------------------------------------------------------------------------------------------------- 371 | 372 | void render_mesh(dw::Mesh* mesh) 373 | { 374 | // Bind uniform buffers. 375 | m_object_ubo->bind_base(1); 376 | 377 | // Bind vertex array. 378 | mesh->mesh_vertex_array()->bind(); 379 | 380 | dw::SubMesh* submeshes = mesh->sub_meshes(); 381 | 382 | for (uint32_t i = 0; i < mesh->sub_mesh_count(); i++) 383 | { 384 | dw::SubMesh& submesh = submeshes[i]; 385 | // Issue draw call. 386 | glDrawElementsBaseVertex(GL_TRIANGLES, submesh.index_count, GL_UNSIGNED_INT, (void*)(sizeof(unsigned int) * submesh.base_index), submesh.base_vertex); 387 | } 388 | } 389 | 390 | // ----------------------------------------------------------------------------------------------------------------------------------- 391 | 392 | void render_meshes() 393 | { 394 | glEnable(GL_DEPTH_TEST); 395 | glDisable(GL_CULL_FACE); 396 | 397 | m_fbo->bind(); 398 | glViewport(0, 0, m_width, m_height); 399 | 400 | glClearColor(0.5f, 0.5f, 0.5f, 1.0f); 401 | glClearDepth(1.0); 402 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 403 | 404 | // Bind shader program. 405 | m_mesh_program->use(); 406 | 407 | // Bind uniform buffers. 408 | m_global_ubo->bind_base(0); 409 | 410 | m_mesh_program->set_uniform("direction", m_direction); 411 | 412 | // Draw meshes. 413 | render_mesh(m_mesh); 414 | } 415 | 416 | // ----------------------------------------------------------------------------------------------------------------------------------- 417 | 418 | void render_cubemap() 419 | { 420 | glEnable(GL_DEPTH_TEST); 421 | glDepthFunc(GL_LEQUAL); 422 | glDisable(GL_CULL_FACE); 423 | 424 | m_sky_program->use(); 425 | 426 | m_global_ubo->bind_base(0); 427 | 428 | m_fbo->bind(); 429 | glViewport(0, 0, m_width, m_height); 430 | 431 | /*m_cubemap_program->set_uniform("s_Skybox", 0); 432 | m_cubemap->bind(0);*/ 433 | 434 | m_sky_program->set_uniform("sky_model", m_sky_model); 435 | 436 | if (m_sky_model == 0) 437 | m_bruneton_model.set_render_uniforms(m_sky_program.get()); 438 | else if (m_sky_model == 1) 439 | m_preetham_model.set_render_uniforms(m_sky_program.get()); 440 | else if (m_sky_model == 2) 441 | m_hosek_wilkie_model.set_render_uniforms(m_sky_program.get()); 442 | 443 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 444 | 445 | glDepthFunc(GL_LESS); 446 | } 447 | 448 | // ----------------------------------------------------------------------------------------------------------------------------------- 449 | 450 | void render_fullscreen_triangle() 451 | { 452 | glDisable(GL_DEPTH_TEST); 453 | glDisable(GL_CULL_FACE); 454 | 455 | m_fullscreen_program->use(); 456 | 457 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 458 | glViewport(0, 0, m_width, m_height); 459 | 460 | glClearColor(1.0f, 0.0f, 0.0f, 1.0f); 461 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 462 | 463 | m_fullscreen_program->set_uniform("exposure", m_exposure); 464 | 465 | m_fullscreen_program->set_uniform("s_Texture", 0); 466 | m_color_rt->bind(0); 467 | 468 | glDrawArrays(GL_TRIANGLES, 0, 3); 469 | } 470 | 471 | // ----------------------------------------------------------------------------------------------------------------------------------- 472 | 473 | void update_object_uniforms(const ObjectUniforms& transform) 474 | { 475 | void* ptr = m_object_ubo->map(GL_WRITE_ONLY); 476 | memcpy(ptr, &transform, sizeof(ObjectUniforms)); 477 | m_object_ubo->unmap(); 478 | } 479 | 480 | // ----------------------------------------------------------------------------------------------------------------------------------- 481 | 482 | void update_global_uniforms(const GlobalUniforms& global) 483 | { 484 | void* ptr = m_global_ubo->map(GL_WRITE_ONLY); 485 | memcpy(ptr, &global, sizeof(GlobalUniforms)); 486 | m_global_ubo->unmap(); 487 | } 488 | 489 | // ----------------------------------------------------------------------------------------------------------------------------------- 490 | 491 | void update_transforms(dw::Camera* camera) 492 | { 493 | // Update camera matrices. 494 | m_global_uniforms.view = camera->m_view; 495 | m_global_uniforms.projection = camera->m_projection; 496 | 497 | glm::mat4 cubemap_view = glm::mat4(glm::mat3(m_global_uniforms.view)); 498 | glm::mat4 view_proj = camera->m_projection * cubemap_view; 499 | 500 | m_global_uniforms.inv_view = glm::inverse(cubemap_view); 501 | m_global_uniforms.inv_projection = glm::inverse(camera->m_projection); 502 | m_global_uniforms.inv_view_projection = glm::inverse(view_proj); 503 | m_global_uniforms.view_pos = glm::vec4(camera->m_position, 0.0f); 504 | } 505 | 506 | // ----------------------------------------------------------------------------------------------------------------------------------- 507 | 508 | void update_camera() 509 | { 510 | dw::Camera* current = m_main_camera.get(); 511 | 512 | if (m_debug_mode) 513 | current = m_debug_camera.get(); 514 | 515 | float forward_delta = m_heading_speed * m_delta; 516 | float right_delta = m_sideways_speed * m_delta; 517 | 518 | current->set_translation_delta(current->m_forward, forward_delta); 519 | current->set_translation_delta(current->m_right, right_delta); 520 | 521 | m_camera_x = m_mouse_delta_x * m_camera_sensitivity; 522 | m_camera_y = m_mouse_delta_y * m_camera_sensitivity; 523 | 524 | if (m_mouse_look) 525 | { 526 | // Activate Mouse Look 527 | current->set_rotatation_delta(glm::vec3((float)(m_camera_y), 528 | (float)(m_camera_x), 529 | (float)(0.0f))); 530 | } 531 | else 532 | { 533 | current->set_rotatation_delta(glm::vec3((float)(0), 534 | (float)(0), 535 | (float)(0))); 536 | } 537 | 538 | current->update(); 539 | 540 | update_transforms(current); 541 | } 542 | 543 | // ----------------------------------------------------------------------------------------------------------------------------------- 544 | 545 | private: 546 | // General GPU resources. 547 | std::unique_ptr m_mesh_vs; 548 | std::unique_ptr m_mesh_fs; 549 | std::unique_ptr m_mesh_program; 550 | std::unique_ptr m_object_ubo; 551 | std::unique_ptr m_global_ubo; 552 | 553 | std::unique_ptr m_color_rt; 554 | std::unique_ptr m_depth_rt; 555 | std::unique_ptr m_fbo; 556 | 557 | std::unique_ptr m_fullscreen_vs; 558 | std::unique_ptr m_fullscreen_fs; 559 | std::unique_ptr m_fullscreen_program; 560 | 561 | std::unique_ptr m_sky_vs; 562 | std::unique_ptr m_sky_fs; 563 | std::unique_ptr m_sky_program; 564 | 565 | // Camera. 566 | std::unique_ptr m_main_camera; 567 | std::unique_ptr m_debug_camera; 568 | 569 | // Uniforms. 570 | ObjectUniforms m_mesh_transforms; 571 | GlobalUniforms m_global_uniforms; 572 | 573 | // Mesh 574 | dw::Mesh* m_mesh; 575 | 576 | // Camera controls. 577 | bool m_show_gui = true; 578 | bool m_mouse_look = false; 579 | bool m_debug_mode = false; 580 | float m_heading_speed = 0.0f; 581 | float m_sideways_speed = 0.0f; 582 | float m_camera_sensitivity = 0.05f; 583 | float m_camera_speed = 0.06f; 584 | float m_camera_x = 0.0f; 585 | float m_camera_y = 0.0f; 586 | float m_exposure = 1.0f; 587 | float m_sun_angle = 0.0f; 588 | int m_sky_model = 0; 589 | glm::vec3 m_direction = glm::vec3(0.0f, 0.0f, 1.0f); 590 | 591 | BrunetonSkyModel m_bruneton_model; 592 | PreethamSkyModel m_preetham_model; 593 | HosekWilkieSkyModel m_hosek_wilkie_model; 594 | }; 595 | 596 | DW_DECLARE_MAIN(SkyModels) 597 | -------------------------------------------------------------------------------- /src/preetham_sky_model.cpp: -------------------------------------------------------------------------------- 1 | #include "preetham_sky_model.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define GLM_ENABLE_EXPERIMENTAL 8 | #include 9 | 10 | #define _USE_MATH_DEFINES 11 | #include 12 | 13 | // ----------------------------------------------------------------------------------------------------------------------------------- 14 | 15 | float zenith_chromacity(const glm::vec4 & c0, const glm::vec4 & c1, const glm::vec4 & c2, float sunTheta, float turbidity) 16 | { 17 | glm::vec4 thetav = glm::vec4(sunTheta * sunTheta * sunTheta, sunTheta * sunTheta, sunTheta, 1); 18 | return glm::dot(glm::vec3(turbidity * turbidity, turbidity, 1), glm::vec3(glm::dot(thetav, c0), glm::dot(thetav, c1), glm::dot(thetav, c2))); 19 | } 20 | 21 | // ----------------------------------------------------------------------------------------------------------------------------------- 22 | 23 | float zenith_luminance(float sunTheta, float turbidity) 24 | { 25 | float chi = (4.f / 9.f - turbidity / 120) * (M_PI - 2 * sunTheta); 26 | return (4.0453 * turbidity - 4.9710) * tan(chi) - 0.2155 * turbidity + 2.4192; 27 | } 28 | 29 | // ----------------------------------------------------------------------------------------------------------------------------------- 30 | 31 | float perez(float theta, float gamma, float A, float B, float C, float D, float E) 32 | { 33 | return (1.f + A * exp(B / (cos(theta) + 0.01))) * (1.f + C * exp(D * gamma) + E * cos(gamma) * cos(gamma)); 34 | } 35 | 36 | // ----------------------------------------------------------------------------------------------------------------------------------- 37 | 38 | PreethamSkyModel::PreethamSkyModel() 39 | { 40 | 41 | } 42 | 43 | // ----------------------------------------------------------------------------------------------------------------------------------- 44 | 45 | PreethamSkyModel::~PreethamSkyModel() 46 | { 47 | 48 | } 49 | 50 | // ----------------------------------------------------------------------------------------------------------------------------------- 51 | 52 | bool PreethamSkyModel::initialize() 53 | { 54 | return true; 55 | } 56 | 57 | // ----------------------------------------------------------------------------------------------------------------------------------- 58 | 59 | void PreethamSkyModel::update() 60 | { 61 | assert(m_turbidity >= 1); 62 | 63 | const float sunTheta = std::acos(glm::clamp(m_direction.y, 0.f, 1.f)); 64 | 65 | // A.2 Skylight Distribution Coefficients and Zenith Values: compute Perez distribution coefficients 66 | A = glm::vec3(-0.0193, -0.0167, 0.1787) * m_turbidity + glm::vec3(-0.2592, -0.2608, -1.4630); 67 | B = glm::vec3(-0.0665, -0.0950, -0.3554) * m_turbidity + glm::vec3( 0.0008, 0.0092, 0.4275); 68 | C = glm::vec3(-0.0004, -0.0079, -0.0227) * m_turbidity + glm::vec3( 0.2125, 0.2102, 5.3251); 69 | D = glm::vec3(-0.0641, -0.0441, 0.1206) * m_turbidity + glm::vec3(-0.8989, -1.6537, -2.5771); 70 | E = glm::vec3(-0.0033, -0.0109, -0.0670) * m_turbidity + glm::vec3( 0.0452, 0.0529, 0.3703); 71 | 72 | // A.2 Skylight Distribution Coefficients and Zenith Values: compute zenith color 73 | Z.x = zenith_chromacity(glm::vec4(0.00166, -0.00375, 0.00209, 0), glm::vec4(-0.02903, 0.06377, -0.03202, 0.00394), glm::vec4(0.11693, -0.21196, 0.06052, 0.25886), sunTheta, m_turbidity); 74 | Z.y = zenith_chromacity(glm::vec4(0.00275, -0.00610, 0.00317, 0), glm::vec4(-0.04214, 0.08970, -0.04153, 0.00516), glm::vec4(0.15346, -0.26756, 0.06670, 0.26688), sunTheta, m_turbidity); 75 | Z.z = zenith_luminance(sunTheta, m_turbidity); 76 | Z.z *= 1000; // conversion from kcd/m^2 to cd/m^2 77 | 78 | // 3.2 Skylight Model: pre-divide zenith color by distribution denominator 79 | Z.x /= perez(0, sunTheta, A.x, B.x, C.x, D.x, E.x); 80 | Z.y /= perez(0, sunTheta, A.y, B.y, C.y, D.y, E.y); 81 | Z.z /= perez(0, sunTheta, A.z, B.z, C.z, D.z, E.z); 82 | 83 | // For low dynamic range simulation, normalize luminance to have a fixed value for sun 84 | if (m_normalized_sun_y) Z.z = m_normalized_sun_y / perez(sunTheta, 0, A.z, B.z, C.z, D.z, E.z); 85 | } 86 | 87 | // ----------------------------------------------------------------------------------------------------------------------------------- 88 | 89 | void PreethamSkyModel::set_render_uniforms(dw::Program* program) 90 | { 91 | program->set_uniform("u_Direction", m_direction); 92 | program->set_uniform("p_A", A); 93 | program->set_uniform("p_B", B); 94 | program->set_uniform("p_C", C); 95 | program->set_uniform("p_D", D); 96 | program->set_uniform("p_E", E); 97 | program->set_uniform("p_Z", Z); 98 | } 99 | 100 | // ----------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /src/preetham_sky_model.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sky_model.h" 4 | 5 | // A Practical Analytic Model for Daylight (A. J. Preetham, Peter Shirley, Brian Smits) 6 | class PreethamSkyModel : public SkyModel 7 | { 8 | public: 9 | PreethamSkyModel(); 10 | ~PreethamSkyModel(); 11 | 12 | bool initialize() override; 13 | void update() override; 14 | void set_render_uniforms(dw::Program* program) override; 15 | 16 | private: 17 | glm::vec3 A, B, C, D, E; 18 | glm::vec3 Z; 19 | }; -------------------------------------------------------------------------------- /src/shader/fullscreen_fs.glsl: -------------------------------------------------------------------------------- 1 | 2 | out vec4 PS_OUT_Color; 3 | 4 | in vec2 PS_IN_TexCoord; 5 | 6 | uniform sampler2D s_Texture; 7 | uniform float exposure; 8 | 9 | vec3 reinhard(vec3 L) 10 | { 11 | L = L * exposure; 12 | return L / (1 + L); 13 | } 14 | 15 | void main() 16 | { 17 | vec3 color = reinhard(texture(s_Texture, PS_IN_TexCoord).rgb); 18 | PS_OUT_Color = vec4(pow(color, vec3(1.0/2.2)), 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /src/shader/fullscreen_vs.glsl: -------------------------------------------------------------------------------- 1 | // Using a fullscreen triangle for post-processing. 2 | // https://www.saschawillems.de/?page_id=2122 3 | // https://michaldrobot.com/2014/04/01/gcn-execution-patterns-in-full-screen-passes/ 4 | 5 | out vec2 PS_IN_TexCoord; 6 | 7 | void main() 8 | { 9 | PS_IN_TexCoord = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2); 10 | gl_Position = vec4(PS_IN_TexCoord * 2.0f + -1.0f, 0.0f, 1.0f); 11 | } 12 | -------------------------------------------------------------------------------- /src/shader/mesh_fs.glsl: -------------------------------------------------------------------------------- 1 | 2 | out vec4 PS_OUT_Color; 3 | 4 | in vec3 PS_IN_FragPos; 5 | in vec3 PS_IN_Normal; 6 | 7 | uniform vec3 direction; 8 | 9 | void main() 10 | { 11 | vec3 diffuse = vec3(0.5); 12 | vec3 color = dot(PS_IN_Normal, -direction) * diffuse; 13 | 14 | PS_OUT_Color = vec4(color, 1.0); 15 | } 16 | -------------------------------------------------------------------------------- /src/shader/mesh_vs.glsl: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 VS_IN_Position; 2 | layout (location = 1) in vec2 VS_IN_Texcoord; 3 | layout (location = 2) in vec3 VS_IN_Normal; 4 | layout (location = 3) in vec3 VS_IN_Tangent; 5 | layout (location = 4) in vec3 VS_IN_Bitangent; 6 | 7 | const int MAX_BONES = 128; 8 | 9 | layout (std140) uniform u_GlobalUBO 10 | { 11 | mat4 view; 12 | mat4 projection; 13 | mat4 inv_view; 14 | mat4 inv_projection; 15 | mat4 inv_view_projection; 16 | vec4 view_pos; 17 | }; 18 | 19 | layout (std140) uniform u_ObjectUBO 20 | { 21 | mat4 model; 22 | }; 23 | 24 | 25 | out vec3 PS_IN_FragPos; 26 | out vec3 PS_IN_Normal; 27 | 28 | void main() 29 | { 30 | vec4 world_pos = model * vec4(VS_IN_Position, 1.0f); 31 | PS_IN_FragPos = world_pos.xyz; 32 | 33 | mat3 model_mat = mat3(model); 34 | 35 | PS_IN_Normal = normalize(model_mat * VS_IN_Normal); 36 | 37 | gl_Position = projection * view * world_pos; 38 | } 39 | -------------------------------------------------------------------------------- /src/shader/sky_fs.glsl: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | out vec4 PS_OUT_Color; 6 | 7 | in vec3 PS_IN_TexCoord; 8 | 9 | uniform vec3 u_Direction; 10 | uniform vec3 camera_pos; 11 | uniform int sky_model; 12 | 13 | void main() 14 | { 15 | vec3 dir = normalize(PS_IN_TexCoord); 16 | 17 | if (sky_model == 0) 18 | { 19 | float sun = step(cos(M_PI / 360.0), dot(dir, SUN_DIR)); 20 | 21 | vec3 sunColor = vec3(sun,sun,sun) * SUN_INTENSITY; 22 | 23 | vec3 extinction; 24 | vec3 inscatter = SkyRadiance(camera_pos, dir, extinction); 25 | vec3 col = sunColor * extinction + inscatter; 26 | 27 | PS_OUT_Color = vec4(col, 1.0); 28 | } 29 | else if (sky_model == 1) 30 | { 31 | vec3 col = preetham_sky_rgb(dir, u_Direction); 32 | 33 | PS_OUT_Color = vec4(col, 1.0); 34 | } 35 | else 36 | { 37 | vec3 col = hosek_wilkie_sky_rgb(dir, u_Direction); 38 | 39 | PS_OUT_Color = vec4(col, 1.0); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/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 | 204 | // single scattered sunlight between two points 205 | // camera=observer 206 | // point=point on the ground 207 | // sundir=unit vector towards the sun 208 | // return scattered light and extinction coefficient 209 | 210 | vec3 result = vec3(0, 0, 0); 211 | extinction = vec3(1, 1, 1); 212 | 213 | vec3 viewdir = _point - camera; 214 | float d = length(viewdir); 215 | viewdir = viewdir / d; 216 | float r = length(camera); 217 | 218 | if (r < 0.9 * Rg) 219 | { 220 | camera.y += Rg; 221 | _point.y += Rg; 222 | r = length(camera); 223 | } 224 | float rMu = dot(camera, viewdir); 225 | float mu = rMu / r; 226 | float r0 = r; 227 | float mu0 = mu; 228 | _point -= viewdir * clamp(shaftWidth, 0.0, d); 229 | 230 | float deltaSq = sqrt(rMu * rMu - r * r + Rt*Rt); 231 | float din = max(-rMu - deltaSq, 0.0); 232 | 233 | if (din > 0.0 && din < d) 234 | { 235 | camera += din * viewdir; 236 | rMu += din; 237 | mu = rMu / Rt; 238 | r = Rt; 239 | d -= din; 240 | } 241 | 242 | if (r <= Rt) 243 | { 244 | float nu = dot(viewdir, SUN_DIR); 245 | float muS = dot(camera, SUN_DIR) / r; 246 | 247 | vec4 inScatter; 248 | 249 | if (r < Rg + 600.0) 250 | { 251 | // avoids imprecision problems in aerial perspective near ground 252 | float f = (Rg + 600.0) / r; 253 | r = r * f; 254 | rMu = rMu * f; 255 | _point = _point * f; 256 | } 257 | 258 | float r1 = length(_point); 259 | float rMu1 = dot(_point, viewdir); 260 | float mu1 = rMu1 / r1; 261 | float muS1 = dot(_point, SUN_DIR) / r1; 262 | 263 | if (mu > 0.0) 264 | extinction = min(Transmittance(r, mu) / Transmittance(r1, mu1), 1.0); 265 | else 266 | extinction = min(Transmittance(r1, -mu1) / Transmittance(r, -mu), 1.0); 267 | 268 | const float EPS = 0.004; 269 | float lim = -sqrt(1.0 - (Rg / r) * (Rg / r)); 270 | 271 | if (abs(mu - lim) < EPS) 272 | { 273 | float a = ((mu - lim) + EPS) / (2.0 * EPS); 274 | 275 | mu = lim - EPS; 276 | r1 = sqrt(r * r + d * d + 2.0 * r * d * mu); 277 | mu1 = (r * mu + d) / r1; 278 | 279 | vec4 inScatter0 = Texture4D(s_Inscatter, r, mu, muS, nu); 280 | vec4 inScatter1 = Texture4D(s_Inscatter, r1, mu1, muS1, nu); 281 | vec4 inScatterA = max(inScatter0 - inScatter1 * extinction.rgbr, 0.0); 282 | 283 | mu = lim + EPS; 284 | r1 = sqrt(r * r + d * d + 2.0 * r * d * mu); 285 | mu1 = (r * mu + d) / r1; 286 | 287 | inScatter0 = Texture4D(s_Inscatter, r, mu, muS, nu); 288 | inScatter1 = Texture4D(s_Inscatter, r1, mu1, muS1, nu); 289 | vec4 inScatterB = max(inScatter0 - inScatter1 * extinction.rgbr, 0.0); 290 | 291 | inScatter = mix(inScatterA, inScatterB, a); 292 | } 293 | else 294 | { 295 | vec4 inScatter0 = Texture4D(s_Inscatter, r, mu, muS, nu); 296 | vec4 inScatter1 = Texture4D(s_Inscatter, r1, mu1, muS1, nu); 297 | inScatter = max(inScatter0 - inScatter1 * extinction.rgbr, 0.0); 298 | } 299 | 300 | // avoids imprecision problems in Mie scattering when sun is below horizon 301 | inScatter.w *= smoothstep(0.00, 0.02, muS); 302 | 303 | vec3 inScatterM = GetMie(inScatter); 304 | float phase = PhaseFunctionR(nu); 305 | float phaseM = PhaseFunctionM(nu); 306 | result = inScatter.rgb * phase + inScatterM * phaseM; 307 | } 308 | 309 | return result * SUN_INTENSITY; 310 | 311 | } -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/copy_inscatter_1_cs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | * Modified and ported to Unity by Justin Hawkins 2014 57 | */ 58 | 59 | // copies deltaS into S (line 5 in algorithm 4.1) 60 | 61 | #define NUM_THREADS 8 62 | 63 | // ------------------------------------------------------------------ 64 | // INPUTS ----------------------------------------------------------- 65 | // ------------------------------------------------------------------ 66 | 67 | layout (local_size_x = NUM_THREADS, local_size_y = NUM_THREADS, local_size_z = 1) in; 68 | 69 | // ------------------------------------------------------------------ 70 | // INPUT ------------------------------------------------------------ 71 | // ------------------------------------------------------------------ 72 | 73 | layout (binding = 0, rgba32f) uniform image3D i_InscatterWrite; 74 | 75 | // ------------------------------------------------------------------ 76 | // UNIFORMS --------------------------------------------------------- 77 | // ------------------------------------------------------------------ 78 | 79 | uniform sampler3D s_DeltaSRRead; 80 | uniform sampler3D s_DeltaSMRead; 81 | 82 | uniform int u_Layer; 83 | 84 | // ------------------------------------------------------------------ 85 | // MAIN ------------------------------------------------------------- 86 | // ------------------------------------------------------------------ 87 | 88 | void main() 89 | { 90 | vec4 ray = texelFetch(s_DeltaSRRead, ivec3(gl_GlobalInvocationID.xy, u_Layer), 0); 91 | vec4 mie = texelFetch(s_DeltaSMRead, ivec3(gl_GlobalInvocationID.xy, u_Layer), 0); 92 | 93 | // store only red component of single Mie scattering (cf. 'Angular precision') 94 | imageStore(i_InscatterWrite, ivec3(gl_GlobalInvocationID.xy, u_Layer), vec4(ray.rgb, mie.r)); 95 | } 96 | 97 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/copy_inscatter_n_cs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | * Modified and ported to Unity by Justin Hawkins 2014 57 | */ 58 | 59 | // copies deltaS into S (line 5 in algorithm 4.1) 60 | 61 | #include 62 | 63 | #define NUM_THREADS 8 64 | 65 | // ------------------------------------------------------------------ 66 | // INPUTS ----------------------------------------------------------- 67 | // ------------------------------------------------------------------ 68 | 69 | layout (local_size_x = NUM_THREADS, local_size_y = NUM_THREADS, local_size_z = 1) in; 70 | 71 | // ------------------------------------------------------------------ 72 | // INPUT ------------------------------------------------------------ 73 | // ------------------------------------------------------------------ 74 | 75 | layout (binding = 0, rgba32f) uniform image3D i_InscatterWrite; 76 | 77 | // ------------------------------------------------------------------ 78 | // UNIFORMS --------------------------------------------------------- 79 | // ------------------------------------------------------------------ 80 | 81 | uniform sampler3D s_InscatterRead; 82 | uniform sampler3D s_DeltaSRead; 83 | 84 | uniform int u_Layer; 85 | 86 | // ------------------------------------------------------------------ 87 | // MAIN ------------------------------------------------------------- 88 | // ------------------------------------------------------------------ 89 | 90 | void main() 91 | { 92 | vec4 dhdH; 93 | float mu, muS, nu, r; 94 | vec2 coords = vec2(gl_GlobalInvocationID.xy) + 0.5; 95 | 96 | GetLayer(u_Layer, r, dhdH); 97 | GetMuMuSNu(coords, r, dhdH, mu, muS, nu); 98 | 99 | ivec3 idx = ivec3(gl_GlobalInvocationID.xy, u_Layer); 100 | 101 | vec4 value = texelFetch(s_InscatterRead, idx, 0) + vec4(texelFetch(s_DeltaSRead, idx, 0).rgb / PhaseFunctionR(nu), 0.0); 102 | 103 | imageStore(i_InscatterWrite, idx, value); 104 | } 105 | 106 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/copy_irradiance_cs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | * Modified and ported to Unity by Justin Hawkins 2014 57 | */ 58 | 59 | // copies deltaS into S (line 5 in algorithm 4.1) 60 | 61 | #define NUM_THREADS 8 62 | 63 | // ------------------------------------------------------------------ 64 | // INPUTS ----------------------------------------------------------- 65 | // ------------------------------------------------------------------ 66 | 67 | layout (local_size_x = NUM_THREADS, local_size_y = NUM_THREADS, local_size_z = 1) in; 68 | 69 | // ------------------------------------------------------------------ 70 | // INPUT ------------------------------------------------------------ 71 | // ------------------------------------------------------------------ 72 | 73 | layout (binding = 0, rgba32f) uniform image2D i_IrradianceWrite; 74 | 75 | // ------------------------------------------------------------------ 76 | // UNIFORMS --------------------------------------------------------- 77 | // ------------------------------------------------------------------ 78 | 79 | uniform sampler2D s_DeltaERead; 80 | uniform sampler2D s_IrradianceRead; 81 | 82 | uniform float u_K; 83 | 84 | // ------------------------------------------------------------------ 85 | // MAIN ------------------------------------------------------------- 86 | // ------------------------------------------------------------------ 87 | 88 | void main() 89 | { 90 | ivec2 coord = ivec2(gl_GlobalInvocationID.xy); 91 | vec4 value = texelFetch(s_IrradianceRead, coord, 0) + u_K * texelFetch(s_DeltaERead, coord, 0); 92 | imageStore(i_IrradianceWrite, coord, value); 93 | } 94 | 95 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/inscatter_1_cs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | * Modified and ported to Unity by Justin Hawkins 2014 57 | */ 58 | 59 | // copies deltaS into S (line 5 in algorithm 4.1) 60 | 61 | #include 62 | 63 | // ------------------------------------------------------------------ 64 | // INPUTS ----------------------------------------------------------- 65 | // ------------------------------------------------------------------ 66 | 67 | layout (local_size_x = NUM_THREADS, local_size_y = NUM_THREADS, local_size_z = 1) in; 68 | 69 | // ------------------------------------------------------------------ 70 | // INPUT ------------------------------------------------------------ 71 | // ------------------------------------------------------------------ 72 | 73 | layout (binding = 0, rgba32f) uniform image3D i_DeltaSRWrite; 74 | layout (binding = 1, rgba32f) uniform image3D i_DeltaSMWrite; 75 | 76 | // ------------------------------------------------------------------ 77 | // UNIFORMS --------------------------------------------------------- 78 | // ------------------------------------------------------------------ 79 | 80 | uniform int u_Layer; 81 | 82 | // ------------------------------------------------------------------ 83 | // FUNCTIONS -------------------------------------------------------- 84 | // ------------------------------------------------------------------ 85 | 86 | void Integrand(float r, float mu, float muS, float nu, float t, out vec3 ray, out vec3 mie) 87 | { 88 | ray = vec3(0,0,0); 89 | mie = vec3(0,0,0); 90 | float ri = sqrt(r * r + t * t + 2.0 * r * mu * t); 91 | float muSi = (nu * t + muS * r) / ri; 92 | ri = max(Rg, ri); 93 | if (muSi >= -sqrt(1.0 - Rg * Rg / (ri * ri))) 94 | { 95 | vec3 ti = Transmittance(r, mu, t) * Transmittance(ri, muSi); 96 | ray = exp(-(ri - Rg) / HR) * ti; 97 | mie = exp(-(ri - Rg) / HM) * ti; 98 | } 99 | } 100 | 101 | // ------------------------------------------------------------------ 102 | 103 | void Inscatter(float r, float mu, float muS, float nu, out vec3 ray, out vec3 mie) 104 | { 105 | ray = vec3(0,0,0); 106 | mie = vec3(0,0,0); 107 | float dx = Limit(r, mu) / float(INSCATTER_INTEGRAL_SAMPLES); 108 | float xi = 0.0; 109 | vec3 rayi; 110 | vec3 miei; 111 | Integrand(r, mu, muS, nu, 0.0, rayi, miei); 112 | 113 | for (int i = 1; i <= INSCATTER_INTEGRAL_SAMPLES; ++i) 114 | { 115 | float xj = float(i) * dx; 116 | vec3 rayj; 117 | vec3 miej; 118 | Integrand(r, mu, muS, nu, xj, rayj, miej); 119 | 120 | ray += (rayi + rayj) / 2.0 * dx; 121 | mie += (miei + miej) / 2.0 * dx; 122 | xi = xj; 123 | rayi = rayj; 124 | miei = miej; 125 | } 126 | 127 | ray *= betaR.xyz; 128 | mie *= betaMSca.xyz; 129 | } 130 | 131 | // ------------------------------------------------------------------ 132 | // MAIN ------------------------------------------------------------- 133 | // ------------------------------------------------------------------ 134 | 135 | void main() 136 | { 137 | vec3 ray; 138 | vec3 mie; 139 | vec4 dhdH; 140 | float mu, muS, nu, r; 141 | vec2 coords = vec2(gl_GlobalInvocationID.xy) + 0.5; 142 | 143 | GetLayer(u_Layer, r, dhdH); 144 | GetMuMuSNu(coords, r, dhdH, mu, muS, nu); 145 | 146 | Inscatter(r, mu, muS, nu, ray, mie); 147 | 148 | // store separately Rayleigh and Mie contributions, WITHOUT the phase function factor 149 | // (cf 'Angular precision') 150 | imageStore(i_DeltaSRWrite, ivec3(gl_GlobalInvocationID.xy, u_Layer), vec4(ray,0)); 151 | imageStore(i_DeltaSMWrite, ivec3(gl_GlobalInvocationID.xy, u_Layer), vec4(mie,0)); 152 | } 153 | 154 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/inscatter_n_cs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | * Modified and ported to Unity by Justin Hawkins 2014 57 | */ 58 | 59 | // copies deltaS into S (line 5 in algorithm 4.1) 60 | 61 | #include 62 | 63 | // ------------------------------------------------------------------ 64 | // INPUTS ----------------------------------------------------------- 65 | // ------------------------------------------------------------------ 66 | 67 | layout (local_size_x = NUM_THREADS, local_size_y = NUM_THREADS, local_size_z = 1) in; 68 | 69 | // ------------------------------------------------------------------ 70 | // INPUT ------------------------------------------------------------ 71 | // ------------------------------------------------------------------ 72 | 73 | layout (binding = 0, rgba32f) uniform image3D i_DeltaSRWrite; 74 | 75 | // ------------------------------------------------------------------ 76 | // UNIFORMS --------------------------------------------------------- 77 | // ------------------------------------------------------------------ 78 | 79 | uniform sampler3D s_DeltaJRead; 80 | 81 | uniform int u_Layer; 82 | 83 | // ------------------------------------------------------------------ 84 | // FUNCTIONS -------------------------------------------------------- 85 | // ------------------------------------------------------------------ 86 | 87 | vec3 Integrand(float r, float mu, float muS, float nu, float t) 88 | { 89 | float ri = sqrt(r * r + t * t + 2.0 * r * mu * t); 90 | float mui = (r * mu + t) / ri; 91 | float muSi = (nu * t + muS * r) / ri; 92 | return Texture4D(s_DeltaJRead, ri, mui, muSi, nu).rgb * Transmittance(r, mu, t); 93 | } 94 | 95 | // ------------------------------------------------------------------ 96 | 97 | vec3 Inscatter(float r, float mu, float muS, float nu) 98 | { 99 | vec3 raymie = vec3(0,0,0); 100 | float dx = Limit(r, mu) / float(INSCATTER_INTEGRAL_SAMPLES); 101 | float xi = 0.0; 102 | vec3 raymiei = Integrand(r, mu, muS, nu, 0.0); 103 | 104 | for (int i = 1; i <= INSCATTER_INTEGRAL_SAMPLES; ++i) 105 | { 106 | float xj = float(i) * dx; 107 | vec3 raymiej = Integrand(r, mu, muS, nu, xj); 108 | raymie += (raymiei + raymiej) / 2.0 * dx; 109 | xi = xj; 110 | raymiei = raymiej; 111 | } 112 | 113 | return raymie; 114 | } 115 | 116 | // ------------------------------------------------------------------ 117 | // MAIN ------------------------------------------------------------- 118 | // ------------------------------------------------------------------ 119 | 120 | void main() 121 | { 122 | vec4 dhdH; 123 | float mu, muS, nu, r; 124 | vec2 coords = vec2(gl_GlobalInvocationID.xy) + 0.5; 125 | 126 | GetLayer(u_Layer, r, dhdH); 127 | GetMuMuSNu(coords, r, dhdH, mu, muS, nu); 128 | 129 | imageStore(i_DeltaSRWrite, ivec3(gl_GlobalInvocationID.xy, u_Layer), vec4(Inscatter(r, mu, muS, nu), 0)); 130 | } 131 | 132 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/inscatter_s_cs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | * Modified and ported to Unity by Justin Hawkins 2014 57 | */ 58 | 59 | // copies deltaS into S (line 5 in algorithm 4.1) 60 | 61 | #include 62 | 63 | // ------------------------------------------------------------------ 64 | // INPUTS ----------------------------------------------------------- 65 | // ------------------------------------------------------------------ 66 | 67 | layout (local_size_x = NUM_THREADS, local_size_y = NUM_THREADS, local_size_z = 1) in; 68 | 69 | // ------------------------------------------------------------------ 70 | // INPUT ------------------------------------------------------------ 71 | // ------------------------------------------------------------------ 72 | 73 | layout (binding = 0, rgba32f) uniform image3D i_DeltaJWrite; 74 | 75 | // ------------------------------------------------------------------ 76 | // UNIFORMS --------------------------------------------------------- 77 | // ------------------------------------------------------------------ 78 | 79 | uniform sampler2D s_DeltaERead; 80 | uniform sampler3D s_DeltaSRRead; 81 | uniform sampler3D s_DeltaSMRead; 82 | 83 | uniform int u_Layer; 84 | 85 | // ------------------------------------------------------------------ 86 | // FUNCTIONS -------------------------------------------------------- 87 | // ------------------------------------------------------------------ 88 | 89 | 90 | void Inscatter(float r, float mu, float muS, float nu, out vec3 raymie) 91 | { 92 | float dphi = M_PI / float(INSCATTER_SPHERICAL_INTEGRAL_SAMPLES); 93 | float dtheta = M_PI / float(INSCATTER_SPHERICAL_INTEGRAL_SAMPLES); 94 | 95 | r = clamp(r, Rg, Rt); 96 | mu = clamp(mu, -1.0, 1.0); 97 | muS = clamp(muS, -1.0, 1.0); 98 | float var = sqrt(1.0 - mu * mu) * sqrt(1.0 - muS * muS); 99 | nu = clamp(nu, muS * mu - var, muS * mu + var); 100 | 101 | float cthetamin = -sqrt(1.0 - (Rg / r) * (Rg / r)); 102 | 103 | vec3 v = vec3(sqrt(1.0 - mu * mu), 0.0, mu); 104 | float sx = v.x == 0.0 ? 0.0 : (nu - muS * mu) / v.x; 105 | vec3 s = vec3(sx, sqrt(max(0.0, 1.0 - sx * sx - muS * muS)), muS); 106 | 107 | raymie = vec3(0,0,0); 108 | 109 | // integral over 4.PI around x with two nested loops over w directions (theta,phi) -- Eq (7) 110 | for (int itheta = 0; itheta < INSCATTER_SPHERICAL_INTEGRAL_SAMPLES; ++itheta) 111 | { 112 | float theta = (float(itheta) + 0.5) * dtheta; 113 | float ctheta = cos(theta); 114 | 115 | float greflectance = 0.0; 116 | float dground = 0.0; 117 | vec3 gtransp = vec3(0,0,0); 118 | 119 | if (ctheta < cthetamin) 120 | { // if ground visible in direction w 121 | // compute transparency gtransp between x and ground 122 | greflectance = AVERAGE_GROUND_REFLECTANCE / M_PI; 123 | dground = -r * ctheta - sqrt(r * r * (ctheta * ctheta - 1.0) + Rg * Rg); 124 | gtransp = Transmittance(Rg, -(r * ctheta + dground) / Rg, dground); 125 | } 126 | 127 | for (int iphi = 0; iphi < 2 * INSCATTER_SPHERICAL_INTEGRAL_SAMPLES; ++iphi) 128 | { 129 | float phi = (float(iphi) + 0.5) * dphi; 130 | float dw = dtheta * dphi * sin(theta); 131 | vec3 w = vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), ctheta); 132 | 133 | float nu1 = dot(s, w); 134 | float nu2 = dot(v, w); 135 | float pr2 = PhaseFunctionR(nu2); 136 | float pm2 = PhaseFunctionM(nu2); 137 | 138 | // compute irradiance received at ground in direction w (if ground visible) =deltaE 139 | vec3 gnormal = (vec3(0.0, 0.0, r) + dground * w) / Rg; 140 | vec3 girradiance = Irradiance(s_DeltaERead, Rg, dot(gnormal, s)); 141 | 142 | vec3 raymie1; // light arriving at x from direction w 143 | 144 | // first term = light reflected from the ground and attenuated before reaching x, =T.alpha/PI.deltaE 145 | raymie1 = greflectance * girradiance * gtransp; 146 | 147 | // second term = inscattered light, =deltaS 148 | if (first == 1) 149 | { 150 | // first iteration is special because Rayleigh and Mie were stored separately, 151 | // without the phase functions factors; they must be reintroduced here 152 | float pr1 = PhaseFunctionR(nu1); 153 | float pm1 = PhaseFunctionM(nu1); 154 | vec3 ray1 = Texture4D(s_DeltaSRRead, r, w.z, muS, nu1).rgb; 155 | vec3 mie1 = Texture4D(s_DeltaSMRead, r, w.z, muS, nu1).rgb; 156 | raymie1 += ray1 * pr1 + mie1 * pm1; 157 | } 158 | else 159 | { 160 | raymie1 += Texture4D(s_DeltaSRRead, r, w.z, muS, nu1).rgb; 161 | } 162 | 163 | // light coming from direction w and scattered in direction v 164 | // = light arriving at x from direction w (raymie1) * SUM(scattering coefficient * phaseFunction) 165 | // see Eq (7) 166 | raymie += raymie1 * (betaR.xyz * exp(-(r - Rg) / HR) * pr2 + betaMSca.xyz * exp(-(r - Rg) / HM) * pm2) * dw; 167 | } 168 | } 169 | 170 | // output raymie = J[T.alpha/PI.deltaE + deltaS] (line 7 in algorithm 4.1) 171 | } 172 | 173 | // ------------------------------------------------------------------ 174 | // MAIN ------------------------------------------------------------- 175 | // ------------------------------------------------------------------ 176 | 177 | void main() 178 | { 179 | vec3 raymie; 180 | vec4 dhdH; 181 | float mu, muS, nu, r; 182 | vec2 coords = vec2(gl_GlobalInvocationID.xy) + 0.5; 183 | 184 | GetLayer(u_Layer, r, dhdH); 185 | GetMuMuSNu(coords, r, dhdH, mu, muS, nu); 186 | 187 | Inscatter(r, mu, muS, nu, raymie); 188 | 189 | imageStore(i_DeltaJWrite, ivec3(gl_GlobalInvocationID.xy, u_Layer), vec4(raymie, 0.0)); 190 | } 191 | 192 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/irradiance_1_cs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | * Modified and ported to Unity by Justin Hawkins 2014 57 | */ 58 | 59 | // copies deltaS into S (line 5 in algorithm 4.1) 60 | 61 | #include 62 | 63 | // ------------------------------------------------------------------ 64 | // INPUTS ----------------------------------------------------------- 65 | // ------------------------------------------------------------------ 66 | 67 | layout (local_size_x = NUM_THREADS, local_size_y = NUM_THREADS, local_size_z = 1) in; 68 | 69 | // ------------------------------------------------------------------ 70 | // INPUT ------------------------------------------------------------ 71 | // ------------------------------------------------------------------ 72 | 73 | layout (binding = 0, rgba32f) uniform image2D i_DeltaEWrite; 74 | 75 | // ------------------------------------------------------------------ 76 | // MAIN ------------------------------------------------------------- 77 | // ------------------------------------------------------------------ 78 | 79 | void main() 80 | { 81 | float r, muS; 82 | vec2 coords = vec2(gl_GlobalInvocationID.xy) + 0.5; 83 | 84 | GetIrradianceRMuS(coords, r, muS); 85 | 86 | imageStore(i_DeltaEWrite, ivec2(gl_GlobalInvocationID.xy), vec4(Transmittance(r, muS) * max(muS, 0.0), 0.0)); 87 | } 88 | 89 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/irradiance_n_cs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | * Modified and ported to Unity by Justin Hawkins 2014 57 | */ 58 | 59 | // copies deltaS into S (line 5 in algorithm 4.1) 60 | 61 | #include 62 | 63 | // ------------------------------------------------------------------ 64 | // INPUTS ----------------------------------------------------------- 65 | // ------------------------------------------------------------------ 66 | 67 | layout (local_size_x = NUM_THREADS, local_size_y = NUM_THREADS, local_size_z = 1) in; 68 | 69 | // ------------------------------------------------------------------ 70 | // INPUT ------------------------------------------------------------ 71 | // ------------------------------------------------------------------ 72 | 73 | layout (binding = 0, rgba32f) uniform image2D i_DeltaEWrite; 74 | 75 | // ------------------------------------------------------------------ 76 | // UNIFORMS --------------------------------------------------------- 77 | // ------------------------------------------------------------------ 78 | 79 | uniform sampler3D s_DeltaSRRead; 80 | uniform sampler3D s_DeltaSMRead; 81 | 82 | // ------------------------------------------------------------------ 83 | // MAIN ------------------------------------------------------------- 84 | // ------------------------------------------------------------------ 85 | 86 | void main() 87 | { 88 | float r, muS; 89 | vec2 coords = vec2(gl_GlobalInvocationID.xy) + 0.5; 90 | 91 | GetIrradianceRMuS(coords, r, muS); 92 | 93 | vec3 s = vec3(sqrt(max(1.0 - muS * muS, 0.0)), 0.0, muS); 94 | 95 | vec3 result = vec3(0,0,0); 96 | // integral over 2.PI around x with two nested loops over w directions (theta,phi) -- Eq (15) 97 | 98 | float dphi = M_PI / float(IRRADIANCE_INTEGRAL_SAMPLES); 99 | float dtheta = M_PI / float(IRRADIANCE_INTEGRAL_SAMPLES); 100 | 101 | for (int iphi = 0; iphi < 2 * IRRADIANCE_INTEGRAL_SAMPLES; ++iphi) { 102 | 103 | float phi = (float(iphi) + 0.5) * dphi; 104 | 105 | for (int itheta = 0; itheta < IRRADIANCE_INTEGRAL_SAMPLES / 2; ++itheta) { 106 | 107 | float theta = (float(itheta) + 0.5) * dtheta; 108 | 109 | float dw = dtheta * dphi * sin(theta); 110 | 111 | vec3 w = vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta)); 112 | 113 | float nu = dot(s, w); 114 | 115 | if (first == 1) 116 | { 117 | // first iteration is special because Rayleigh and Mie were stored separately, 118 | // without the phase functions factors; they must be reintroduced here 119 | float pr1 = PhaseFunctionR(nu); 120 | float pm1 = PhaseFunctionM(nu); 121 | vec3 ray1 = Texture4D(s_DeltaSRRead, r, w.z, muS, nu).rgb; 122 | vec3 mie1 = Texture4D(s_DeltaSMRead, r, w.z, muS, nu).rgb; 123 | result += (ray1 * pr1 + mie1 * pm1) * w.z * dw; 124 | } 125 | else { 126 | result += Texture4D(s_DeltaSRRead, r, w.z, muS, nu).rgb * w.z * dw; 127 | 128 | } 129 | } 130 | } 131 | 132 | imageStore(i_DeltaEWrite, ivec2(gl_GlobalInvocationID.xy), vec4(result, 1.0)); 133 | } 134 | 135 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/precompute_common.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | */ 57 | 58 | //Not sure if compute shaders were designed to use cginc files. 59 | //It does work but had issues with changes here being updated to shaders. 60 | 61 | #define NUM_THREADS 8 62 | 63 | // ---------------------------------------------------------------------------- 64 | // PHYSICAL MODEL PARAMETERS 65 | // ---------------------------------------------------------------------------- 66 | 67 | uniform float Rg; 68 | uniform float Rt; 69 | uniform float RL; 70 | uniform float HR; 71 | uniform float HM; 72 | uniform float mieG; 73 | uniform float AVERAGE_GROUND_REFLECTANCE; 74 | uniform vec4 betaR; 75 | uniform vec4 betaMSca; 76 | uniform vec4 betaMEx; 77 | 78 | // ---------------------------------------------------------------------------- 79 | // CONSTANT PARAMETERS 80 | // ---------------------------------------------------------------------------- 81 | 82 | uniform int first; 83 | uniform int TRANSMITTANCE_H; 84 | uniform int TRANSMITTANCE_W; 85 | uniform int SKY_W; 86 | uniform int SKY_H; 87 | uniform int RES_R; 88 | uniform int RES_MU; 89 | uniform int RES_MU_S; 90 | uniform int RES_NU; 91 | 92 | // ---------------------------------------------------------------------------- 93 | // NUMERICAL INTEGRATION PARAMETERS 94 | // ---------------------------------------------------------------------------- 95 | 96 | #define TRANSMITTANCE_INTEGRAL_SAMPLES 500 97 | #define INSCATTER_INTEGRAL_SAMPLES 50 98 | #define IRRADIANCE_INTEGRAL_SAMPLES 32 99 | #define INSCATTER_SPHERICAL_INTEGRAL_SAMPLES 16 100 | 101 | #define M_PI 3.141592657 102 | 103 | // ---------------------------------------------------------------------------- 104 | // PARAMETERIZATION OPTIONS 105 | // ---------------------------------------------------------------------------- 106 | 107 | #define TRANSMITTANCE_NON_LINEAR 108 | #define INSCATTER_NON_LINEAR 109 | 110 | // ---------------------------------------------------------------------------- 111 | // PARAMETERIZATION FUNCTIONS 112 | // ---------------------------------------------------------------------------- 113 | 114 | uniform sampler2D s_TransmittanceRead; 115 | 116 | vec4 SamplePoint(sampler3D tex, vec3 uv, vec3 size) 117 | { 118 | uv = clamp(uv, 0.0, 1.0); 119 | uv = uv * (size-1.0); 120 | return texelFetch(tex, ivec3(uv + 0.5), 0); 121 | } 122 | 123 | float mod(float x, float y) { return x - y * floor(x/y); } 124 | 125 | vec2 GetTransmittanceUV(float r, float mu) 126 | { 127 | float uR, uMu; 128 | #ifdef TRANSMITTANCE_NON_LINEAR 129 | uR = sqrt((r - Rg) / (Rt - Rg)); 130 | uMu = atan((mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5; 131 | #else 132 | uR = (r - Rg) / (Rt - Rg); 133 | uMu = (mu + 0.15) / (1.0 + 0.15); 134 | #endif 135 | return vec2(uMu, uR); 136 | } 137 | 138 | void GetTransmittanceRMu(vec2 coord, out float r, out float muS) 139 | { 140 | r = coord.y / float(TRANSMITTANCE_H); 141 | muS = coord.x / float(TRANSMITTANCE_W); 142 | #ifdef TRANSMITTANCE_NON_LINEAR 143 | r = Rg + (r * r) * (Rt - Rg); 144 | muS = -0.15 + tan(1.5 * muS) / tan(1.5) * (1.0 + 0.15); 145 | #else 146 | r = Rg + r * (Rt - Rg); 147 | muS = -0.15 + muS * (1.0 + 0.15); 148 | #endif 149 | } 150 | 151 | vec2 GetIrradianceUV(float r, float muS) 152 | { 153 | float uR = (r - Rg) / (Rt - Rg); 154 | float uMuS = (muS + 0.2) / (1.0 + 0.2); 155 | return vec2(uMuS, uR); 156 | } 157 | 158 | void GetIrradianceRMuS(vec2 coord, out float r, out float muS) 159 | { 160 | r = Rg + (coord.y - 0.5) / (float(SKY_H) - 1.0) * (Rt - Rg); 161 | muS = -0.2 + (coord.x - 0.5) / (float(SKY_W) - 1.0) * (1.0 + 0.2); 162 | } 163 | 164 | vec4 Texture4D(sampler3D tex, float r, float mu, float muS, float nu) 165 | { 166 | float H = sqrt(Rt * Rt - Rg * Rg); 167 | float rho = sqrt(r * r - Rg * Rg); 168 | #ifdef INSCATTER_NON_LINEAR 169 | float rmu = r * mu; 170 | float delta = rmu * rmu - r * r + Rg * Rg; 171 | vec4 cst = rmu < 0.0 && delta > 0.0 ? vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(RES_MU)) : vec4(-1.0, H * H, H, 0.5 + 0.5 / float(RES_MU)); 172 | float uR = 0.5 / float(RES_R) + rho / H * (1.0 - 1.0 / float(RES_R)); 173 | float uMu = cst.w + (rmu * cst.x + sqrt(delta + cst.y)) / (rho + cst.z) * (0.5 - 1.0 / float(RES_MU)); 174 | // paper formula 175 | //float uMuS = 0.5 / float(RES_MU_S) + max((1.0 - exp(-3.0 * muS - 0.6)) / (1.0 - exp(-3.6)), 0.0) * (1.0 - 1.0 / float(RES_MU_S)); 176 | // better formula 177 | float uMuS = 0.5 / float(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 / float(RES_MU_S)); 178 | #else 179 | float uR = 0.5 / float(RES_R) + rho / H * (1.0 - 1.0 / float(RES_R)); 180 | float uMu = 0.5 / float(RES_MU) + (mu + 1.0) / 2.0 * (1.0 - 1.0 / float(RES_MU)); 181 | float uMuS = 0.5 / float(RES_MU_S) + max(muS + 0.2, 0.0) / 1.2 * (1.0 - 1.0 / float(RES_MU_S)); 182 | #endif 183 | float _lerp = (nu + 1.0) / 2.0 * (float(RES_NU) - 1.0); 184 | float uNu = floor(_lerp); 185 | _lerp = _lerp - uNu; 186 | 187 | vec3 size = vec3(RES_MU_S*RES_NU,RES_MU,RES_R); 188 | 189 | return SamplePoint(tex, vec3((uNu + uMuS) / float(RES_NU), uMu, uR), size) * (1.0 - _lerp) + 190 | SamplePoint(tex, vec3((uNu + uMuS + 1.0) / float(RES_NU), uMu, uR), size) * _lerp; 191 | 192 | } 193 | 194 | void GetMuMuSNu(vec2 coord, float r, vec4 dhdH, out float mu, out float muS, out float nu) 195 | { 196 | float x = coord.x - 0.5; 197 | float y = coord.y - 0.5; 198 | #ifdef INSCATTER_NON_LINEAR 199 | if (y < float(RES_MU) / 2.0) 200 | { 201 | float d = 1.0 - y / (float(RES_MU) / 2.0 - 1.0); 202 | d = min(max(dhdH.z, d * dhdH.w), dhdH.w * 0.999); 203 | mu = (Rg * Rg - r * r - d * d) / (2.0 * r * d); 204 | mu = min(mu, -sqrt(1.0 - (Rg / r) * (Rg / r)) - 0.001); 205 | } 206 | else 207 | { 208 | float d = (y - float(RES_MU) / 2.0) / (float(RES_MU) / 2.0 - 1.0); 209 | d = min(max(dhdH.x, d * dhdH.y), dhdH.y * 0.999); 210 | mu = (Rt * Rt - r * r - d * d) / (2.0 * r * d); 211 | } 212 | muS = mod(x, float(RES_MU_S)) / (float(RES_MU_S) - 1.0); 213 | // paper formula 214 | //muS = -(0.6 + log(1.0 - muS * (1.0 - exp(-3.6)))) / 3.0; 215 | // better formula 216 | muS = tan((2.0 * muS - 1.0 + 0.26) * 1.1) / tan(1.26 * 1.1); 217 | nu = -1.0 + floor(x / float(RES_MU_S)) / (float(RES_NU) - 1.0) * 2.0; 218 | #else 219 | mu = -1.0 + 2.0 * y / (float(RES_MU) - 1.0); 220 | muS = mod(x, float(RES_MU_S)) / (float(RES_MU_S) - 1.0); 221 | muS = -0.2 + muS * 1.2; 222 | nu = -1.0 + floor(x / float(RES_MU_S)) / (float(RES_NU) - 1.0) * 2.0; 223 | #endif 224 | } 225 | 226 | void GetLayer(int layer, out float r, out vec4 dhdH) 227 | { 228 | r = float(layer) / (RES_R - 1.0); 229 | r = r * r; 230 | r = sqrt(Rg * Rg + r * (Rt * Rt - Rg * Rg)) + (layer == 0 ? 0.01 : (layer == RES_R - 1 ? -0.001 : 0.0)); 231 | 232 | float dmin = Rt - r; 233 | float dmax = sqrt(r * r - Rg * Rg) + sqrt(Rt * Rt - Rg * Rg); 234 | float dminp = r - Rg; 235 | float dmaxp = sqrt(r * r - Rg * Rg); 236 | 237 | dhdH = vec4(dmin, dmax, dminp, dmaxp); 238 | } 239 | 240 | // ---------------------------------------------------------------------------- 241 | // UTILITY FUNCTIONS 242 | // ---------------------------------------------------------------------------- 243 | 244 | // nearest intersection of ray r,mu with ground or top atmosphere boundary 245 | // mu=cos(ray zenith angle at ray origin) 246 | float Limit(float r, float mu) 247 | { 248 | float dout = -r * mu + sqrt(r * r * (mu * mu - 1.0) + RL * RL); 249 | float delta2 = r * r * (mu * mu - 1.0) + Rg * Rg; 250 | 251 | if (delta2 >= 0.0) 252 | { 253 | float din = -r * mu - sqrt(delta2); 254 | if (din >= 0.0) 255 | { 256 | dout = min(dout, din); 257 | } 258 | } 259 | 260 | return dout; 261 | } 262 | 263 | // transmittance(=transparency) of atmosphere for infinite ray (r,mu) 264 | // (mu=cos(view zenith angle)), intersections with ground ignored 265 | vec3 Transmittance(float r, float mu) 266 | { 267 | vec2 uv = GetTransmittanceUV(r, mu); 268 | return textureLod(s_TransmittanceRead, uv, 0).rgb; 269 | } 270 | 271 | // transmittance(=transparency) of atmosphere between x and x0 272 | // assume segment x,x0 not intersecting ground 273 | // d = distance between x and x0, mu=cos(zenith angle of [x,x0) ray at x) 274 | vec3 Transmittance(float r, float mu, float d) 275 | { 276 | vec3 result; 277 | float r1 = sqrt(r * r + d * d + 2.0 * r * mu * d); 278 | float mu1 = (r * mu + d) / r1; 279 | if (mu > 0.0) { 280 | result = min(Transmittance(r, mu) / Transmittance(r1, mu1), 1.0); 281 | } else { 282 | result = min(Transmittance(r1, -mu1) / Transmittance(r, -mu), 1.0); 283 | } 284 | return result; 285 | } 286 | 287 | vec3 Irradiance(sampler2D tex, float r, float muS) 288 | { 289 | vec2 uv = GetIrradianceUV(r, muS); 290 | return textureLod(tex, uv, 0).rgb; 291 | } 292 | 293 | // Rayleigh phase function 294 | float PhaseFunctionR(float mu) 295 | { 296 | return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu); 297 | } 298 | 299 | // Mie phase function 300 | float PhaseFunctionM(float mu) 301 | { 302 | return 1.5 * 1.0 / (4.0 * M_PI) * (1.0 - mieG*mieG) * pow(max(0.0, 1.0 + (mieG*mieG) - 2.0*mieG*mu), -3.0/2.0) * (1.0 + mu * mu) / (2.0 + mieG*mieG); 303 | } -------------------------------------------------------------------------------- /src/shader/sky_models/bruneton/transmittance_cs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | * Proland: a procedural landscape rendering library. 3 | * Copyright (c) 2008-2011 INRIA 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | /* 20 | * Proland is distributed under a dual-license scheme. 21 | * You can obtain a specific license from Inria: proland-licensing@inria.fr. 22 | */ 23 | 24 | /** 25 | * Precomputed Atmospheric Scattering 26 | * Copyright (c) 2008 INRIA 27 | * All rights reserved. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions 31 | * are met: 32 | * 1. Redistributions of source code must retain the above copyright 33 | * notice, this list of conditions and the following disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above copyright 35 | * notice, this list of conditions and the following disclaimer in the 36 | * documentation and/or other materials provided with the distribution. 37 | * 3. Neither the name of the copyright holders nor the names of its 38 | * contributors may be used to endorse or promote products derived from 39 | * this software without specific prior written permission. 40 | * 41 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 45 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 48 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 51 | * THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | /** 55 | * Author: Eric Bruneton 56 | * Modified and ported to Unity by Justin Hawkins 2014 57 | */ 58 | 59 | // copies deltaS into S (line 5 in algorithm 4.1) 60 | 61 | #include 62 | 63 | // ------------------------------------------------------------------ 64 | // INPUTS ----------------------------------------------------------- 65 | // ------------------------------------------------------------------ 66 | 67 | layout (local_size_x = NUM_THREADS, local_size_y = NUM_THREADS, local_size_z = 1) in; 68 | 69 | // ------------------------------------------------------------------ 70 | // INPUT ------------------------------------------------------------ 71 | // ------------------------------------------------------------------ 72 | 73 | layout (binding = 0, rgba32f) uniform image2D i_TransmittanceWrite; 74 | 75 | // ------------------------------------------------------------------ 76 | // FUNCTIONS -------------------------------------------------------- 77 | // ------------------------------------------------------------------ 78 | 79 | float OpticalDepth(float H, float r, float mu) 80 | { 81 | float result = 0.0; 82 | float dx = Limit(r, mu) / float(TRANSMITTANCE_INTEGRAL_SAMPLES); 83 | float xi = 0.0; 84 | float yi = exp(-(r - Rg) / H); 85 | 86 | for (int i = 1; i <= TRANSMITTANCE_INTEGRAL_SAMPLES; ++i) 87 | { 88 | float xj = float(i) * dx; 89 | float yj = exp(-(sqrt(r * r + xj * xj + 2.0 * xj * r * mu) - Rg) / H); 90 | result += (yi + yj) / 2.0 * dx; 91 | xi = xj; 92 | yi = yj; 93 | } 94 | 95 | return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? 1e9 : result; 96 | } 97 | 98 | // ------------------------------------------------------------------ 99 | // MAIN ------------------------------------------------------------- 100 | // ------------------------------------------------------------------ 101 | 102 | void main() 103 | { 104 | float r, muS; 105 | GetTransmittanceRMu(vec2(gl_GlobalInvocationID.xy), r, muS); 106 | 107 | vec4 depth = betaR * OpticalDepth(HR, r, muS) + betaMEx * OpticalDepth(HM, r, muS); 108 | 109 | imageStore(i_TransmittanceWrite, ivec2(gl_GlobalInvocationID.xy), exp(-depth)); // Eq (5); 110 | } 111 | 112 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/hosek_wilkie/atmosphere.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // UNIFORMS --------------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | uniform vec3 A, B, C, D, E, F, G, H, I, Z; 6 | 7 | // ------------------------------------------------------------------ 8 | // FUNCTIONS -------------------------------------------------------- 9 | // ------------------------------------------------------------------ 10 | 11 | vec3 hosek_wilkie(float cos_theta, float gamma, float cos_gamma) 12 | { 13 | vec3 chi = (1 + cos_gamma * cos_gamma) / pow(1 + H * H - 2 * cos_gamma * H, vec3(1.5)); 14 | return (1 + A * exp(B / (cos_theta + 0.01))) * (C + D * exp(E * gamma) + F * (cos_gamma * cos_gamma) + G * chi + I * sqrt(cos_theta)); 15 | } 16 | 17 | // ------------------------------------------------------------------ 18 | 19 | vec3 hosek_wilkie_sky_rgb(vec3 v, vec3 sun_dir) 20 | { 21 | float cos_theta = clamp(v.y, 0, 1); 22 | float cos_gamma = clamp(dot(v, sun_dir), 0, 1); 23 | float gamma_ = acos(cos_gamma); 24 | 25 | vec3 R = Z * hosek_wilkie(cos_theta, gamma_, cos_gamma); 26 | return R; 27 | } 28 | 29 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_models/preetham/atmosphere.glsl: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------ 2 | // UNIFORMS --------------------------------------------------------- 3 | // ------------------------------------------------------------------ 4 | 5 | uniform vec3 p_A, p_B, p_C, p_D, p_E, p_Z; 6 | 7 | // ------------------------------------------------------------------ 8 | // FUNCTIONS -------------------------------------------------------- 9 | // ------------------------------------------------------------------ 10 | 11 | vec3 perez(float cos_theta, float gamma, float cos_gamma, vec3 A, vec3 B, vec3 C, vec3 D, vec3 E) 12 | { 13 | return (1 + A * exp(B / (cos_theta + 0.01))) * (1 + C * exp(D * gamma) + E * cos_gamma * cos_gamma); 14 | } 15 | 16 | // ------------------------------------------------------------------ 17 | 18 | vec3 preetham_sky_rgb(vec3 v, vec3 sun_dir) 19 | { 20 | float cos_theta = clamp(v.y, 0, 1); 21 | float cos_gamma = dot(v, sun_dir); 22 | float gamma = acos(cos_gamma); 23 | 24 | vec3 R_xyY = p_Z * perez(cos_theta, gamma, cos_gamma, p_A, p_B, p_C, p_D, p_E); 25 | 26 | vec3 R_XYZ = vec3(R_xyY.x, R_xyY.y, 1 - R_xyY.x - R_xyY.y) * R_xyY.z / R_xyY.y; 27 | 28 | // Radiance 29 | float r = dot(vec3( 3.240479, -1.537150, -0.498535), R_XYZ); 30 | float g = dot(vec3(-0.969256, 1.875992, 0.041556), R_XYZ); 31 | float b = dot(vec3( 0.055648, -0.204043, 1.057311), R_XYZ); 32 | 33 | return vec3(r, g, b); 34 | } 35 | 36 | // ------------------------------------------------------------------ -------------------------------------------------------------------------------- /src/shader/sky_vs.glsl: -------------------------------------------------------------------------------- 1 | // Using a fullscreen triangle for post-processing. 2 | // https://www.saschawillems.de/?page_id=2122 3 | // https://michaldrobot.com/2014/04/01/gcn-execution-patterns-in-full-screen-passes/ 4 | 5 | layout (std140) uniform u_GlobalUBO 6 | { 7 | mat4 view; 8 | mat4 projection; 9 | mat4 inv_view; 10 | mat4 inv_projection; 11 | mat4 inv_view_projection; 12 | vec4 view_pos; 13 | }; 14 | 15 | 16 | out vec3 PS_IN_TexCoord; 17 | 18 | // void main() 19 | // { 20 | // vec2 pos = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2); 21 | // gl_Position = vec4(pos * 2.0f + -1.0f, 1.0f, 1.0f); 22 | 23 | // vec4 clip_pos = vec4(gl_Position.xy, -1.0, 1.0); 24 | // vec4 view_pos = inv_projection * clip_pos; 25 | 26 | // vec3 dir = vec3(inv_view * vec4(view_pos.x, view_pos.y, -1.0, 0.0)); 27 | // dir = normalize(dir); 28 | 29 | // PS_IN_TexCoord = dir; 30 | // } 31 | 32 | void main(void) 33 | { 34 | const vec3 vertices[4] = vec3[4](vec3(-1.0f, -1.0f, 1.0f), 35 | vec3( 1.0f, -1.0f, 1.0f), 36 | vec3(-1.0f, 1.0f, 1.0f), 37 | vec3( 1.0f, 1.0f, 1.0f)); 38 | 39 | 40 | vec4 clip_pos = vec4(vertices[gl_VertexID].xy, -1.0, 1.0); 41 | vec4 view_pos = inv_view_projection * clip_pos; 42 | 43 | vec3 dir = vec3(view_pos);//vec3(inv_view * vec4(view_pos.x, view_pos.y, -1.0, 0.0)); 44 | dir = normalize(dir); 45 | 46 | PS_IN_TexCoord = dir; 47 | 48 | gl_Position = vec4(vertices[gl_VertexID], 1.0f); 49 | } -------------------------------------------------------------------------------- /src/sky_model.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class SkyModel 6 | { 7 | public: 8 | virtual bool initialize() = 0; 9 | virtual void update() = 0; 10 | virtual void set_render_uniforms(dw::Program* program) = 0; 11 | 12 | inline glm::vec3 direction() { return m_direction; } 13 | inline void set_direction(glm::vec3 dir) { m_direction = -dir; } 14 | 15 | inline float turbidity() { return m_turbidity; } 16 | inline void set_turbidity(float t) { m_turbidity = t; } 17 | 18 | protected: 19 | glm::vec3 m_direction; 20 | float m_normalized_sun_y = 1.15f; 21 | float m_albedo = 0.1f; 22 | float m_turbidity = 4.0f; 23 | }; --------------------------------------------------------------------------------