diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..540b00747eee74a94be3c987d1ac4c8595738a09 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,20 @@ +Alexander Gauggel +Artur Wasmut +Josch Morgenstern +Katharina Krämer +Lars Hoerttrich +Leonie Franken +Mara Vogt +Mark O. Mints +Sebastian Gaida +Simeon Hermann +Susanne Dötsch +Tobias Frisch +Trevor Hollmann +Vanessa Karolek + + + + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a0858b970dead0233261c4f3c126a0bf64732f7..5f82b94af2a98dfb6700fb098a6b2a84adf7b9a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,9 @@ endif() # configure everything to use the required dependencies include(${vkcv_config}/Libraries.cmake) +# set macro to enable vulkan debug labels +list(APPEND vkcv_definitions VULKAN_DEBUG_LABELS) + # set the compile definitions aka preprocessor variables add_compile_definitions(${vkcv_definitions}) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..c1f3c5685b29d78b26dcc8c9e454b74c33f73ba5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Universität Koblenz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 245a6283eb22c67844b01fe09dcc01d7c1274e14..b89dbae2f9af909ab2f1319994e9bb00fb87f98e 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -351,6 +351,33 @@ namespace vkcv const std::vector<MeshShaderDrawcall>& drawcalls, const std::vector<ImageHandle>& renderTargets, const WindowHandle& windowHandle); + + + /** + * Records the rtx ray generation to the @p cmdStreamHandle. + * Currently only supports @p closestHit, @p rayGen and @c miss shaderstages @c. + * @param cmdStreamHandle The command stream handle which receives relevant commands for drawing. + * @param rtxPipeline The raytracing pipeline from the RTXModule. + * @param rtxPipelineLayout The raytracing pipeline layout from the RTXModule. + * @param rgenRegion The shader binding table region for ray generation shaders. + * @param rmissRegion The shader binding table region for ray miss shaders. + * @param rchitRegion The shader binding table region for ray closest hit shaders. + * @param rcallRegion The shader binding table region for callable shaders. + * @param descriptorSetUsages The descriptor set usages. + * @param pushConstants The push constants. + * @param windowHandle The window handle defining in which window to render. + */ + void recordRayGenerationToCmdStream( + CommandStreamHandle cmdStreamHandle, + vk::Pipeline rtxPipeline, + vk::PipelineLayout rtxPipelineLayout, + vk::StridedDeviceAddressRegionKHR rgenRegion, + vk::StridedDeviceAddressRegionKHR rmissRegion, + vk::StridedDeviceAddressRegionKHR rchitRegion, + vk::StridedDeviceAddressRegionKHR rcallRegion, + const std::vector<DescriptorSetUsage>& descriptorSetUsages, + const PushConstants& pushConstants, + const WindowHandle windowHandle); void recordComputeDispatchToCmdStream( CommandStreamHandle cmdStream, diff --git a/include/vkcv/DescriptorConfig.hpp b/include/vkcv/DescriptorConfig.hpp index 905ff6791e2cef5fdb972e900c16b7bf7999ed37..becdb9f843aa254fed6f05dec0c18686fac497d6 100644 --- a/include/vkcv/DescriptorConfig.hpp +++ b/include/vkcv/DescriptorConfig.hpp @@ -19,7 +19,8 @@ namespace vkcv IMAGE_SAMPLED, IMAGE_STORAGE, UNIFORM_BUFFER_DYNAMIC, - STORAGE_BUFFER_DYNAMIC + STORAGE_BUFFER_DYNAMIC, + ACCELERATION_STRUCTURE_KHR }; /** @@ -44,6 +45,8 @@ namespace vkcv return vk::DescriptorType::eSampledImage; case DescriptorType::IMAGE_STORAGE: return vk::DescriptorType::eStorageImage; + case DescriptorType::ACCELERATION_STRUCTURE_KHR: + return vk::DescriptorType::eAccelerationStructureKHR; default: return vk::DescriptorType::eMutableVALVE; } diff --git a/include/vkcv/DescriptorWrites.hpp b/include/vkcv/DescriptorWrites.hpp index ff72a91160d46d7ff98bacc24c9bc25ce0b2ce02..f4f9729a193c9da4cfc4ccc869337314e8a71ccb 100644 --- a/include/vkcv/DescriptorWrites.hpp +++ b/include/vkcv/DescriptorWrites.hpp @@ -38,11 +38,20 @@ namespace vkcv { SamplerHandle sampler; }; + /** + * @brief Only used for RTX. Used to bind the Acceleration Structure. + */ + struct AccelerationDescriptorWrite { + inline AccelerationDescriptorWrite(uint32_t binding) : binding(binding) {}; + uint32_t binding; + }; + struct DescriptorWrites { std::vector<SampledImageDescriptorWrite> sampledImageWrites; std::vector<StorageImageDescriptorWrite> storageImageWrites; std::vector<BufferDescriptorWrite> uniformBufferWrites; std::vector<BufferDescriptorWrite> storageBufferWrites; std::vector<SamplerDescriptorWrite> samplerWrites; + std::vector<AccelerationDescriptorWrite> accelerationWrites; }; } \ No newline at end of file diff --git a/include/vkcv/FeatureManager.hpp b/include/vkcv/FeatureManager.hpp index 214357f8a77c2166d09d217fbe159a9fe9f4c873..2f932f6e25c12e80f42d762f82a73f9a5265b793 100644 --- a/include/vkcv/FeatureManager.hpp +++ b/include/vkcv/FeatureManager.hpp @@ -78,7 +78,43 @@ namespace vkcv { [[nodiscard]] bool checkSupport(const vk::PhysicalDeviceMeshShaderFeaturesNV& features, bool required) const; + + /** + * @brief Currently used for RTX. Checks support of the @p vk::PhysicalDeviceVulkan12Features. + * @param features The features. + * @param required True, if the @p features are required, else false. + * @return @p True, if the @p features are supported, else @p false. + */ + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceVulkan12Features& features, bool required) const; + + /** + * @brief Currently used for RTX. Checks support of the @p vk::PhysicalDeviceVulkan11Features. + * @param features The features. + * @param required True, if the @p features are required, else false. + * @return @p True, if the @p features are supported, else @p false. + */ + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceVulkan11Features& features, bool required) const; + /** + * @brief Only used for RTX. Checks support of the @p vk::PhysicalDeviceAccelerationStructureFeaturesKHR. + * @param features The features. + * @param required True, if the @p features are required, else false. + * @return @p True, if the @p features are supported, else @p false. + */ + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceAccelerationStructureFeaturesKHR& features, bool required) const; + + /** + * @brief Only used for RTX. Checks support of the @p vk::PhysicalDeviceRayTracingPipelineFeaturesKHR. + * @param features The features. + * @param required True, if the @p features are required, else false. + * @return @p True, if the @p features are supported, else @p false. + */ + [[nodiscard]] + bool checkSupport(const vk::PhysicalDeviceRayTracingPipelineFeaturesKHR& features, bool required) const; + vk::BaseOutStructure* findFeatureStructure(vk::StructureType type) const; public: diff --git a/include/vkcv/ShaderStage.hpp b/include/vkcv/ShaderStage.hpp index 52ba5a7e56ed40efda96c27dfd92734880b88f18..0baaaf5b57fcc510159b8620e3119e4749467093 100644 --- a/include/vkcv/ShaderStage.hpp +++ b/include/vkcv/ShaderStage.hpp @@ -12,7 +12,13 @@ namespace vkcv { FRAGMENT = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eFragment), COMPUTE = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eCompute), TASK = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eTaskNV), - MESH = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eMeshNV) + MESH = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eMeshNV), + RAY_GEN = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eRaygenKHR), // RTX + RAY_ANY_HIT = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eAnyHitKHR), // RTX + RAY_CLOSEST_HIT = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eClosestHitKHR), // RTX + RAY_MISS = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eMissKHR), // RTX + RAY_INTERSECTION = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eIntersectionKHR), // RTX + RAY_CALLABLE = static_cast<VkShaderStageFlags>(vk::ShaderStageFlagBits::eCallableKHR) // RTX }; using ShaderStages = vk::Flags<ShaderStage>; diff --git a/modules/camera/include/vkcv/camera/CameraManager.hpp b/modules/camera/include/vkcv/camera/CameraManager.hpp index 409f9196599be02e4215f3924c1102f0b8c72899..c0777b09544893aa38cf11396c1cf60bd800a837 100644 --- a/modules/camera/include/vkcv/camera/CameraManager.hpp +++ b/modules/camera/include/vkcv/camera/CameraManager.hpp @@ -117,7 +117,7 @@ namespace vkcv::camera { * @brief The constructor of the #CameraManager. * @param[in] window The window. */ - CameraManager(Window &window); + explicit CameraManager(Window &window); /** * @brief The destructor of the #CameraManager. Destroying the #CameraManager leads to deletion of all stored diff --git a/modules/camera/src/vkcv/camera/Camera.cpp b/modules/camera/src/vkcv/camera/Camera.cpp index 87d09aa9a6e3e7dc80d5de9a95f3e1e3b72e9205..25b2a7339a46de8ced171c8ee9c10f962c3c0399 100644 --- a/modules/camera/src/vkcv/camera/Camera.cpp +++ b/modules/camera/src/vkcv/camera/Camera.cpp @@ -164,4 +164,4 @@ namespace vkcv::camera { setAngles(glm::radians(getPitch()), glm::radians(yaw)); } -} \ No newline at end of file +} diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp index 16067aebedfda8793a0096803ba5344275bcbbcd..c639118f5a4482eb9db2cee46057e5662b472181 100644 --- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp @@ -56,6 +56,18 @@ namespace vkcv::shader { return EShLangTaskNV; case ShaderStage::MESH: return EShLangMeshNV; + case ShaderStage::RAY_GEN: // for RTX + return EShLangRayGen; + case ShaderStage::RAY_CLOSEST_HIT: // for RTX + return EShLangClosestHit; + case ShaderStage::RAY_MISS: // for RTX + return EShLangMiss; + case ShaderStage::RAY_INTERSECTION: // for RTX + return EShLangIntersect; + case ShaderStage::RAY_ANY_HIT: // for RTX + return EShLangAnyHit; + case ShaderStage::RAY_CALLABLE: // for RTX + return EShLangCallable; default: return EShLangCount; } @@ -214,6 +226,16 @@ namespace vkcv::shader { } glslang::TShader shader (language); + + // configure environment for rtx shaders by adjusting versions of Vulkan and SPIR-V, else rtx shader cannot be compiled. + if((shaderStage == ShaderStage::RAY_GEN) || (shaderStage == ShaderStage::RAY_ANY_HIT) + || (shaderStage == ShaderStage::RAY_CLOSEST_HIT) || (shaderStage == ShaderStage::RAY_MISS) + || (shaderStage == ShaderStage::RAY_INTERSECTION) || (shaderStage == ShaderStage::RAY_CALLABLE)){ + + shader.setEnvClient(glslang::EShClientVulkan,glslang::EShTargetVulkan_1_2); + shader.setEnvTarget(glslang::EShTargetSpv,glslang::EShTargetSpv_1_4); + } + glslang::TProgram program; std::string source (shaderSource); diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index 3ff8c5d2256b4257c61f67f2329de0442005e94c..9cf1ff1c9327114d28871f11694a2fb88bc00735 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -4,8 +4,12 @@ add_subdirectory(first_triangle) add_subdirectory(first_mesh) add_subdirectory(first_scene) add_subdirectory(particle_simulation) +add_subdirectory(rtx_ambient_occlusion) +add_subdirectory(sph) add_subdirectory(voxelization) add_subdirectory(mesh_shader) add_subdirectory(indirect_draw) add_subdirectory(bindless_textures) +add_subdirectory(saf_r) add_subdirectory(indirect_dispatch) +add_subdirectory(path_tracer) \ No newline at end of file diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 5ef277dfedbfa823a2b6fa55c5a6303117ddaa52..0871631827b87539bbe9b0050420088e199a39af 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -101,7 +101,7 @@ int main(int argc, const char** argv) { // since we only use one descriptor set (namely, desc set 0), directly address it // recreate copies of the bindings and the handles (to check whether they are properly reused instead of actually recreated) - std::unordered_map<uint32_t, vkcv::DescriptorBinding> set0Bindings = firstMeshProgram.getReflectedDescriptors().at(0); + const vkcv::DescriptorBindings& set0Bindings = firstMeshProgram.getReflectedDescriptors().at(0); auto set0BindingsExplicitCopy = set0Bindings; vkcv::DescriptorSetLayoutHandle setLayoutHandle = core.createDescriptorSetLayout(set0Bindings); diff --git a/projects/indirect_dispatch/assets/shaders/motionVectorMinMax.comp b/projects/indirect_dispatch/assets/shaders/motionVectorMinMax.comp index 4ad350b0d5300aa63a66d7aceb00ea0b642d07ee..06b1b98f37579ae33406691bf19999d42ab7eb83 100644 --- a/projects/indirect_dispatch/assets/shaders/motionVectorMinMax.comp +++ b/projects/indirect_dispatch/assets/shaders/motionVectorMinMax.comp @@ -12,6 +12,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; void main(){ ivec2 outImageRes = imageSize(outMotionMax); + ivec2 inImageRes = textureSize(sampler2D(inMotion, textureSampler), 0); ivec2 motionTileCoord = ivec2(gl_GlobalInvocationID.xy); if(any(greaterThanEqual(motionTileCoord, outImageRes))) @@ -28,6 +29,14 @@ void main(){ for(int x = 0; x < motionTileSize; x++){ for(int y = 0; y < motionTileSize; y++){ ivec2 sampleCoord = motionBufferBaseCoord + ivec2(x, y); + + bool sampleIsOutsideImage = false; + sampleIsOutsideImage = sampleIsOutsideImage || any(greaterThanEqual(sampleCoord, inImageRes)); + sampleIsOutsideImage = sampleIsOutsideImage || any(lessThan(sampleCoord, ivec2(0))); + + if(sampleIsOutsideImage) + continue; + vec2 motionSample = texelFetch(sampler2D(inMotion, textureSampler), sampleCoord, 0).rg; float velocitySample = length(motionSample); diff --git a/projects/indirect_dispatch/assets/shaders/motionVectorMinMaxNeighbourhood.comp b/projects/indirect_dispatch/assets/shaders/motionVectorMinMaxNeighbourhood.comp index 4d6e7c0af6115e816ba087570e5585ffde23b1e6..3f836341a97a683efe88f41416d541624be03a0e 100644 --- a/projects/indirect_dispatch/assets/shaders/motionVectorMinMaxNeighbourhood.comp +++ b/projects/indirect_dispatch/assets/shaders/motionVectorMinMaxNeighbourhood.comp @@ -12,6 +12,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; void main(){ ivec2 outImageRes = imageSize(outMotionMaxNeighbourhood); + ivec2 inImageRes = textureSize(sampler2D(inMotionMax, textureSampler), 0); ivec2 motionTileCoord = ivec2(gl_GlobalInvocationID.xy); if(any(greaterThanEqual(motionTileCoord, outImageRes))) @@ -27,6 +28,13 @@ void main(){ for(int y = -1; y <= 1; y++){ ivec2 sampleCoord = motionTileCoord + ivec2(x, y); + bool sampleIsOutsideImage = false; + sampleIsOutsideImage = sampleIsOutsideImage || any(greaterThanEqual(sampleCoord, inImageRes)); + sampleIsOutsideImage = sampleIsOutsideImage || any(lessThan(sampleCoord, ivec2(0))); + + if(sampleIsOutsideImage) + continue; + vec2 motionSampleMax = texelFetch(sampler2D(inMotionMax, textureSampler), sampleCoord, 0).rg; float velocitySampleMax = length(motionSampleMax); diff --git a/projects/indirect_dispatch/assets/shaders/motionVectorVisualisation.comp b/projects/indirect_dispatch/assets/shaders/motionVectorVisualisation.comp index 1cfb09c87e8288b8ea80c6ddfbe5f0d4918b7f2e..fdceb575feaf24e7114bbcf223585a28955f45b8 100644 --- a/projects/indirect_dispatch/assets/shaders/motionVectorVisualisation.comp +++ b/projects/indirect_dispatch/assets/shaders/motionVectorVisualisation.comp @@ -21,7 +21,10 @@ void main(){ if(any(greaterThanEqual(coord, outImageRes))) return; - vec2 motionVector = texelFetch(sampler2D(inMotion, textureSampler), coord / motionTileSize, 0).rg; + vec2 uv = (coord + 0.5) / vec2(outImageRes); + ivec2 inTextureRes = textureSize(sampler2D(inMotion, textureSampler), 0); + + vec2 motionVector = texelFetch(sampler2D(inMotion, textureSampler), ivec2(uv * inTextureRes), 0).rg; vec2 motionVectorNormalized = clamp(motionVector / range, -1, 1); vec2 color = motionVectorNormalized * 0.5 + 0.5; diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp index d4afc61c7421bd45c773bbdbc3da796b868869d2..532cef11db5b2bb8b5d741f6505507ff23fa4163 100644 --- a/projects/indirect_dispatch/src/App.cpp +++ b/projects/indirect_dispatch/src/App.cpp @@ -28,7 +28,7 @@ App::App() : VK_MAKE_VERSION(0, 0, 1), { vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer }, { VK_KHR_SWAPCHAIN_EXTENSION_NAME })), - m_windowHandle(m_core.createWindow(m_applicationName, m_windowWidth, m_windowHeight, false)), + m_windowHandle(m_core.createWindow(m_applicationName, m_windowWidth, m_windowHeight, true)), m_cameraManager(m_core.getWindow(m_windowHandle)){} bool App::initialize() { diff --git a/projects/indirect_draw/.gitignore b/projects/indirect_draw/.gitignore index 071dd05c8a5ba569a5a5676358e67166f94790ff..92714f6a3381225d29daff0d99efe51e12b40970 100644 --- a/projects/indirect_draw/.gitignore +++ b/projects/indirect_draw/.gitignore @@ -1 +1 @@ -draw_indirect \ No newline at end of file +indirect_draw \ No newline at end of file diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp index bdc280a28513ddb6216e6e02a769c8261ebcd506..88e7005f2912bb448980bd4c1219245481f1559a 100644 --- a/projects/indirect_draw/src/main.cpp +++ b/projects/indirect_draw/src/main.cpp @@ -123,7 +123,7 @@ void interleaveScene(vkcv::asset::Scene scene, glm::vec3 max_pos(-std::numeric_limits<float>::max()); glm::vec3 min_pos(std::numeric_limits<float>::max()); - for(auto i = 0; i < verticesCount; i++) + for(size_t i = 0; i < verticesCount; i++) { const size_t positionOffset = positionAttribute.offset + positionStride * i; const size_t normalOffset = normalAttribute.offset + normalStride * i; @@ -230,7 +230,7 @@ void compileMeshForIndirectDraw(vkcv::Core &core, } else if(vertexGroup.indexBuffer.type == vkcv::asset::IndexType::UINT16) { - for(auto i = 0; i < vertexGroup.indexBuffer.data.size(); i = i+2) + for (size_t i = 0; i < vertexGroup.indexBuffer.data.size(); i += 2) { uint16_t index16 = *reinterpret_cast<const uint16_t*>(&vertexGroup.indexBuffer.data[i]); uint32_t index32 = static_cast<uint32_t>(index16); diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp index ddbe6195e66e78504d4bccb32b3b09ff680ab414..ae3c6795a66cdc81297986acb224a63055d02c44 100644 --- a/projects/particle_simulation/src/main.cpp +++ b/projects/particle_simulation/src/main.cpp @@ -22,7 +22,7 @@ int main(int argc, const char **argv) { {vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute}, { VK_KHR_SWAPCHAIN_EXTENSION_NAME } ); - vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); vkcv::Window& window = core.getWindow(windowHandle); vkcv::camera::CameraManager cameraManager(window); @@ -61,7 +61,7 @@ int main(int argc, const char **argv) { shaderPathFragment = "shaders/shader_space.frag"; } else if (strcmp(argv[i], "--water") == 0) { - shaderPathCompute = "shaders/shader_water.comp"; + shaderPathCompute = "shaders/shader_water1.comp"; shaderPathFragment = "shaders/shader_water.frag"; } else if (strcmp(argv[i], "--gravity") == 0) { diff --git a/projects/path_tracer/.gitignore b/projects/path_tracer/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..24a57cda822232aa24d513fab3901ff7db36adb1 --- /dev/null +++ b/projects/path_tracer/.gitignore @@ -0,0 +1 @@ +path_tracer \ No newline at end of file diff --git a/projects/path_tracer/CMakeLists.txt b/projects/path_tracer/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b8edc208c70a5e8e74c6c28221f783a68a3ec6c --- /dev/null +++ b/projects/path_tracer/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.16) +project(path_tracer) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(path_tracer + src/main.cpp) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(path_tracer PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(path_tracer PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(path_tracer PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(path_tracer SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(path_tracer vkcv vkcv_testing vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_shader_compiler vkcv_gui) diff --git a/projects/path_tracer/shaders/clearImage.comp b/projects/path_tracer/shaders/clearImage.comp new file mode 100644 index 0000000000000000000000000000000000000000..97998e945112d166be7d00df98ee44ea8322a633 --- /dev/null +++ b/projects/path_tracer/shaders/clearImage.comp @@ -0,0 +1,17 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +layout(set=0, binding=0, rgba32f) uniform image2D outImage; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main(){ + + ivec2 outImageRes = imageSize(outImage); + ivec2 coord = ivec2(gl_GlobalInvocationID.xy); + + if(any(greaterThanEqual(coord, outImageRes))) + return; + + imageStore(outImage, coord, vec4(0)); +} \ No newline at end of file diff --git a/projects/path_tracer/shaders/combineImages.comp b/projects/path_tracer/shaders/combineImages.comp new file mode 100644 index 0000000000000000000000000000000000000000..d1a4e85caf175dfc3125afd847d7458ddec2fef1 --- /dev/null +++ b/projects/path_tracer/shaders/combineImages.comp @@ -0,0 +1,21 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +layout(set=0, binding=0, rgba32f) uniform image2D newImage; +layout(set=0, binding=1, rgba32f) uniform image2D meanImage; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main(){ + + ivec2 outImageRes = imageSize(meanImage); + ivec2 coord = ivec2(gl_GlobalInvocationID.xy); + + if(any(greaterThanEqual(coord, outImageRes))) + return; + + vec4 colorNew = imageLoad(newImage, coord); + vec4 colorMean = imageLoad(meanImage, coord); + + imageStore(meanImage, coord, colorNew + colorMean); +} \ No newline at end of file diff --git a/projects/path_tracer/shaders/path_tracer.comp b/projects/path_tracer/shaders/path_tracer.comp new file mode 100644 index 0000000000000000000000000000000000000000..f08bdfd123ede964befe5feed4ba9f438dc0a498 --- /dev/null +++ b/projects/path_tracer/shaders/path_tracer.comp @@ -0,0 +1,430 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +const float pi = 3.1415926535897932384626433832795; +const float hitBias = 0.0001; // used to offset hits to avoid self intersection +const float denomMin = 0.001; + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +struct Material { + vec3 emission; + float ks; // specular percentage + vec3 albedo; + float r; // roughness + vec3 f0; + float padding; +}; + +struct Sphere{ + vec3 center; + float radius; + int materialIndex; + float padding[3]; +}; + +struct Plane{ + vec3 center; + int materialIndex; + vec3 N; + float padding1; + vec2 extent; + vec2 padding2; +}; + +layout(std430, binding = 0) buffer spheres{ + Sphere inSpheres[]; +}; + +layout(std430, binding = 1) buffer planes{ + Plane inPlanes[]; +}; + +layout(std430, binding = 2) buffer materials{ + Material inMaterials[]; +}; + +layout(set=0, binding = 3, rgba32f) uniform image2D outImage; + +layout( push_constant ) uniform constants{ + mat4 viewToWorld; + vec3 skyColor; + int sphereCount; + int planeCount; + int frameIndex; +}; + +// ---- Intersection functions ---- + +struct Ray{ + vec3 origin; + vec3 direction; +}; + +struct Intersection{ + bool hit; + float distance; + vec3 pos; + vec3 N; + Material material; +}; + +// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection +Intersection raySphereIntersect(Ray ray, Sphere sphere){ + + Intersection intersection; + intersection.hit = false; + + vec3 L = sphere.center - ray.origin; + float tca = dot(L, ray.direction); + float d2 = dot(L, L) - tca * tca; + + if (d2 > sphere.radius * sphere.radius){ + return intersection; + } + float thc = float(sqrt(sphere.radius * sphere.radius - d2)); + float t0 = tca - thc; + float t1 = tca + thc; + + if (t0 < 0) + t0 = t1; + + if (t0 < 0) + return intersection; + + intersection.hit = true; + intersection.distance = t0; + intersection.pos = ray.origin + ray.direction * intersection.distance; + intersection.N = normalize(intersection.pos - sphere.center); + intersection.material = inMaterials[sphere.materialIndex]; + + return intersection; +} + +struct Basis{ + vec3 right; + vec3 up; + vec3 forward; +}; + +Basis buildBasisAroundNormal(vec3 N){ + Basis basis; + basis.up = N; + basis.right = abs(basis.up.x) < 0.99 ? vec3(1, 0, 0) : vec3(0, 0, 1); + basis.forward = normalize(cross(basis.up, basis.right)); + basis.right = cross(basis.up, basis.forward); + return basis; +} + +// see: https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-plane-and-ray-disk-intersection +Intersection rayPlaneIntersect(Ray ray, Plane plane){ + + Intersection intersection; + intersection.hit = false; + + vec3 toPlane = plane.center - ray.origin; + float denom = dot(ray.direction, plane.N); + if(abs(denom) < 0.001) + return intersection; + + intersection.distance = dot(toPlane, plane.N) / denom; + + if(intersection.distance < 0) + return intersection; + + intersection.pos = ray.origin + ray.direction * intersection.distance; + + vec3 centerToIntersection = intersection.pos - plane.center; + Basis planeBasis = buildBasisAroundNormal(plane.N); + float projectedRight = dot(centerToIntersection, planeBasis.right); + float projectedUp = dot(centerToIntersection, planeBasis.forward); + + intersection.hit = abs(projectedRight) <= plane.extent.x && abs(projectedUp) <= plane.extent.y; + intersection.N = plane.N; + intersection.material = inMaterials[plane.materialIndex]; + + return intersection; +} + +Intersection sceneIntersect(Ray ray) { + float minDistance = 100000; // lets start with something big + + Intersection intersection; + intersection.hit = false; + + for (int i = 0; i < sphereCount; i++) { + Intersection sphereIntersection = raySphereIntersect(ray, inSpheres[i]); + if (sphereIntersection.hit && sphereIntersection.distance < minDistance) { + intersection = sphereIntersection; + minDistance = intersection.distance; + } + } + for (int i = 0; i < planeCount; i++){ + Intersection planeIntersection = rayPlaneIntersect(ray, inPlanes[i]); + if (planeIntersection.hit && planeIntersection.distance < minDistance) { + intersection = planeIntersection; + minDistance = intersection.distance; + } + } + return intersection; +} + +vec3 biasHitPosition(vec3 hitPos, vec3 rayDirection, vec3 N){ + // return hitPos + N * hitBias; // works as long as no refraction/transmission is used and camera is outside sphere + return hitPos + sign(dot(rayDirection, N)) * N * hitBias; +} + +// ---- noise/hash functions for pseudorandom variables ---- + +// extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences +vec2 r2Sequence(uint n){ + n = n % 42000; + const float g = 1.32471795724474602596; + return fract(vec2( + n / g, + n / (g*g))); +} + +// random() and helpers from: https://www.shadertoy.com/view/XlycWh +float g_seed = 0; + +uint base_hash(uvec2 p) { + p = 1103515245U*((p >> 1U)^(p.yx)); + uint h32 = 1103515245U*((p.x)^(p.y>>3U)); + return h32^(h32 >> 16); +} + +vec2 hash2(inout float seed) { + uint n = base_hash(floatBitsToUint(vec2(seed+=.1,seed+=.1))); + uvec2 rz = uvec2(n, n*48271U); + return vec2(rz.xy & uvec2(0x7fffffffU))/float(0x7fffffff); +} + +void initRandom(ivec2 coord){ + g_seed = float(base_hash(coord)/float(0xffffffffU)+frameIndex); +} + +vec2 random(){ + return hash2(g_seed); +} + +// ---- shading ---- + +vec3 lambertBRDF(vec3 albedo){ + return albedo / pi; +} + +vec3 computeDiffuseBRDF(Material material){ + return lambertBRDF(material.albedo); +} + +float distributionGGX(float r, float NoH){ + float r2 = r*r; + float denom = pi * pow(NoH*NoH * (r2-1) + 1, 2); + return r2 / max(denom, denomMin); +} + +float geometryGGXSmith(float r, float NoL){ + float r2 = r*r; + float denom = NoL + sqrt(r2 + (1-r2) * NoL*NoL); + return 2 * NoL / max(denom, denomMin); +} + +float geometryGGX(float r, float NoV, float NoL){ + return geometryGGXSmith(r, NoV) * geometryGGXSmith(r, NoL); +} + +vec3 fresnelSchlick(vec3 f0, float NoH){ + return f0 + (1 - f0) * pow(1 - NoH, 5); +} + +vec3 computeSpecularBRDF(vec3 f0, float r, float NoV, float NoL, float NoH){ + float denom = 4 * NoV * NoL; + float D = distributionGGX(r, NoH); + float G = geometryGGX(r, NoV, NoL); + vec3 F = fresnelSchlick(f0, NoH); + return D * F * G / max(denom, denomMin); +} + +// ---- pathtracing and main ---- + +// distributions: https://link.springer.com/content/pdf/10.1007/978-1-4842-4427-2_16.pdf +float cosineDistributionPDF(float NoL){ + return NoL / pi; +} + +vec3 sampleCosineDistribution(vec2 xi){ + float phi = 2 * pi * xi.y; + return vec3( + sqrt(xi.x) * cos(phi), + sqrt(1 - xi.x), + sqrt(xi.x) * sin(phi)); +} + +float uniformDistributionPDF(){ + return 1.f / (2 * pi); +} + +vec3 sampleUniformDistribution(vec2 xi){ + float phi = 2 * pi * xi.y; + return vec3( + sqrt(xi.x) * cos(phi), + 1 - xi.x, + sqrt(xi.x) * sin(phi)); +} + +float ggxDistributionPDF(float r, float NoH){ + return distributionGGX(r, NoH) * NoH; +} + +float ggxDistributionPDFReflected(float r, float NoH, float NoV){ + float jacobian = 0.25 / max(NoV, denomMin); + return ggxDistributionPDF(r, NoH) * jacobian; +} + +vec3 sampleGGXDistribution(vec2 xi, float r){ + float phi = 2 * pi * xi.y; + float cosTheta = sqrt((1 - xi.x) / ((r*r - 1) * xi.x + 1)); + float sinTheta = sqrt(1 - cosTheta*cosTheta); + return vec3( + cos(phi) * sinTheta, + cosTheta, + sin(phi) * sinTheta); +} + +vec3 sampleTangentToWorldSpace(vec3 tangentSpaceSample, vec3 N){ + Basis tangentBasis = buildBasisAroundNormal(N); + return + tangentBasis.right * tangentSpaceSample.x + + tangentBasis.up * tangentSpaceSample.y + + tangentBasis.forward * tangentSpaceSample.z; +} + +vec3 castRay(Ray ray) { + + vec3 throughput = vec3(1); + vec3 color = vec3(0); + + const int maxDepth = 10; + for(int i = 0; i < maxDepth; i++){ + + Intersection intersection = sceneIntersect(ray); + + vec3 hitLighting = vec3(0); + vec3 brdf = vec3(1); + + // V is where the ray came from and will lead back to the camera (over multiple bounces) + vec3 V = -normalize(ray.direction); + vec3 R = reflect(-V, intersection.N); + float NoV = max(dot(intersection.N, V), 0); + + intersection.material.r *= intersection.material.r; // remapping for perceuptual linearity + intersection.material.r = max(intersection.material.r, 0.01); + + float kd = 1 - intersection.material.ks; + bool sampleDiffuse = random().x < kd; + + vec3 sampleTangentSpace; + float pdf; + if(sampleDiffuse){ + sampleTangentSpace = sampleCosineDistribution(random()); + ray.direction = sampleTangentToWorldSpace(sampleTangentSpace, intersection.N); + + float NoL = max(dot(intersection.N, ray.direction), 0); + pdf = cosineDistributionPDF(NoL); + } + else{ + #define IMPORTANCE + + #ifdef IMPORTANCE + sampleTangentSpace = sampleGGXDistribution(random(), intersection.material.r); + ray.direction = sampleTangentToWorldSpace(sampleTangentSpace, R); + vec3 L = normalize(ray.direction); + pdf = ggxDistributionPDFReflected(intersection.material.r, max(sampleTangentSpace.y, 0.01), max(dot(intersection.N, V), 0.01)); + #else + sampleTangentSpace = sampleUniformDistribution(random()); + ray.direction = sampleTangentToWorldSpace(sampleTangentSpace, intersection.N); + pdf = uniformDistributionPDF(); + #endif + } + + ray.origin = biasHitPosition(intersection.pos, ray.direction, intersection.N); + + // L is where the ray is going, as that is the direction where light will from + vec3 L = normalize(ray.direction); + vec3 H = normalize(L + V); + + float NoL = max(dot(intersection.N, L), 0); + float NoH = max(dot(intersection.N, H), 0); + + if(intersection.hit){ + vec3 diffuseBRDF = computeDiffuseBRDF(intersection.material); + + vec3 specularBRDF = computeSpecularBRDF(intersection.material.f0, intersection.material.r, NoV, NoL, NoH); + brdf = mix(diffuseBRDF, specularBRDF, intersection.material.ks); + + + hitLighting = intersection.material.emission * max(sign(NoV), 0); // objects only emit in direction of normal + } + else{ + hitLighting = skyColor; + } + + color += hitLighting * throughput; + throughput *= brdf * NoL / max(pdf, denomMin); + + if(!intersection.hit) + break; + } + + return color; +} + +// coord must be in pixel coordinates, but already shifted to pixel center +vec3 computeCameraRay(vec2 coord){ + + ivec2 outImageRes = imageSize(outImage); + float fovDegree = 45; + float fov = fovDegree * pi / 180; + + vec2 uv = coord / vec2(outImageRes); + vec2 ndc = 2 * uv - 1; + + float tanFovHalf = tan(fov / 2.f); + float aspectRatio = outImageRes.x / float(outImageRes.y); + float x = ndc.x * tanFovHalf * aspectRatio; + float y = -ndc.y * tanFovHalf; + + // view direction goes through pixel on image plane with z=1 + vec3 directionViewSpace = normalize(vec3(x, y, 1)); + vec3 directionWorldSpace = mat3(viewToWorld) * directionViewSpace; + return directionWorldSpace; +} + +void main(){ + ivec2 coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixelSize = 1.f / coord; + initRandom(coord); + + Ray cameraRay; + cameraRay.origin = viewToWorld[3].xyz; + vec2 coordCentered = coord + 0.5; + + vec3 color = vec3(0); + + const int samplesPerPixel = 1; + for(int i = 0; i < samplesPerPixel; i++){ + vec2 jitter = r2Sequence(i + frameIndex) - 0.5; + cameraRay.direction = computeCameraRay(coordCentered + jitter); + color += castRay(cameraRay); + } + color /= samplesPerPixel; + + vec4 final = vec4(color, 1); + + // occasional NaNs in reflection, should be fixed properly + if(any(isnan(color))) + final = vec4(0); + + imageStore(outImage, coord, final); +} \ No newline at end of file diff --git a/projects/path_tracer/shaders/presentImage.comp b/projects/path_tracer/shaders/presentImage.comp new file mode 100644 index 0000000000000000000000000000000000000000..a52159c0c6173779b091e5d4153b15b0a6361780 --- /dev/null +++ b/projects/path_tracer/shaders/presentImage.comp @@ -0,0 +1,23 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +layout(set=0, binding=0, rgba32f) uniform image2D inImage; +layout(set=0, binding=1, rgba8) uniform image2D outImage; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main(){ + + ivec2 outImageRes = imageSize(outImage); + ivec2 coord = ivec2(gl_GlobalInvocationID.xy); + + if(any(greaterThanEqual(coord, outImageRes))) + return; + + vec4 colorRaw = imageLoad(inImage, coord); + vec3 colorNormalized = colorRaw.rgb / colorRaw.a; + vec3 colorTonemapped = colorNormalized / (1 + dot(colorNormalized, vec3(0.71, 0.21, 0.08))); // reinhard tonemapping + vec3 colorGammaCorrected = pow(colorTonemapped, vec3(1.f / 2.2)); + + imageStore(outImage, coord, vec4(colorGammaCorrected, 0)); +} \ No newline at end of file diff --git a/projects/path_tracer/src/main.cpp b/projects/path_tracer/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6da36cd6ad03bb7e54e7a57bbf7d4d992607ed52 --- /dev/null +++ b/projects/path_tracer/src/main.cpp @@ -0,0 +1,456 @@ +#include <vkcv/Core.hpp> +#include <vkcv/camera/CameraManager.hpp> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> +#include "vkcv/gui/GUI.hpp" +#include <chrono> +#include <vector> + +int main(int argc, const char** argv) { + + // structs must match shader version + struct Material { + Material(const glm::vec3& emission, const glm::vec3& albedo, float ks, float roughness, const glm::vec3& f0) + : emission(emission), albedo(albedo), ks(ks), roughness(roughness), f0(f0){} + + glm::vec3 emission; + float ks; + glm::vec3 albedo; + float roughness; + glm::vec3 f0; + float padding; + }; + + struct Sphere { + Sphere(const glm::vec3& c, const float& r, const int m) : center(c), radius(r), materialIndex(m) {} + + glm::vec3 center; + float radius; + uint32_t materialIndex; + float padding[3]; + }; + + struct Plane { + Plane(const glm::vec3& c, const glm::vec3& n, const glm::vec2 e, int m) + : center(c), normal(n), extent(e), materialIndex(m) {} + + glm::vec3 center; + uint32_t materialIndex; + glm::vec3 normal; + float padding1; + glm::vec2 extent; + glm::vec2 padding3; + }; + + const char* applicationName = "Path Tracer"; + + vkcv::Core core = vkcv::Core::create( + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, + { "VK_KHR_swapchain" } + ); + + const int initialWidth = 1280; + const int initialHeight = 720; + + vkcv::WindowHandle windowHandle = core.createWindow( + applicationName, + initialWidth, + initialHeight, + true + ); + + // images + vkcv::ImageHandle outputImage = core.createImage( + vk::Format::eR32G32B32A32Sfloat, + initialWidth, + initialHeight, + 1, + false, + true).getHandle(); + + vkcv::ImageHandle meanImage = core.createImage( + vk::Format::eR32G32B32A32Sfloat, + initialWidth, + initialHeight, + 1, + false, + true).getHandle(); + + vkcv::shader::GLSLCompiler compiler; + + // path tracing shader + vkcv::ShaderProgram traceShaderProgram{}; + + compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/path_tracer.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + traceShaderProgram.addShader(shaderStage, path); + }); + + const vkcv::DescriptorBindings& traceDescriptorBindings = traceShaderProgram.getReflectedDescriptors().at(0); + vkcv::DescriptorSetLayoutHandle traceDescriptorSetLayout = core.createDescriptorSetLayout(traceDescriptorBindings); + vkcv::DescriptorSetHandle traceDescriptorSet = core.createDescriptorSet(traceDescriptorSetLayout); + + // image combine shader + vkcv::ShaderProgram imageCombineShaderProgram{}; + + compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/combineImages.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + imageCombineShaderProgram.addShader(shaderStage, path); + }); + + const vkcv::DescriptorBindings& imageCombineDescriptorBindings = imageCombineShaderProgram.getReflectedDescriptors().at(0); + vkcv::DescriptorSetLayoutHandle imageCombineDescriptorSetLayout = core.createDescriptorSetLayout(imageCombineDescriptorBindings); + vkcv::DescriptorSetHandle imageCombineDescriptorSet = core.createDescriptorSet(imageCombineDescriptorSetLayout); + vkcv::ComputePipelineHandle imageCombinePipeline = core.createComputePipeline({ + imageCombineShaderProgram, + { core.getDescriptorSetLayout(imageCombineDescriptorSetLayout).vulkanHandle } + }); + + vkcv::DescriptorWrites imageCombineDescriptorWrites; + imageCombineDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(0, outputImage), + vkcv::StorageImageDescriptorWrite(1, meanImage) + }; + core.writeDescriptorSet(imageCombineDescriptorSet, imageCombineDescriptorWrites); + + // image present shader + vkcv::ShaderProgram presentShaderProgram{}; + + compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/presentImage.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + presentShaderProgram.addShader(shaderStage, path); + }); + + const vkcv::DescriptorBindings& presentDescriptorBindings = presentShaderProgram.getReflectedDescriptors().at(0); + vkcv::DescriptorSetLayoutHandle presentDescriptorSetLayout = core.createDescriptorSetLayout(presentDescriptorBindings); + vkcv::DescriptorSetHandle presentDescriptorSet = core.createDescriptorSet(presentDescriptorSetLayout); + vkcv::ComputePipelineHandle presentPipeline = core.createComputePipeline({ + presentShaderProgram, + { core.getDescriptorSetLayout(presentDescriptorSetLayout).vulkanHandle } + }); + + // clear shader + vkcv::ShaderProgram clearShaderProgram{}; + + compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/clearImage.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + clearShaderProgram.addShader(shaderStage, path); + }); + + const vkcv::DescriptorBindings& imageClearDescriptorBindings = clearShaderProgram.getReflectedDescriptors().at(0); + vkcv::DescriptorSetLayoutHandle imageClearDescriptorSetLayout = core.createDescriptorSetLayout(imageClearDescriptorBindings); + vkcv::DescriptorSetHandle imageClearDescriptorSet = core.createDescriptorSet(imageClearDescriptorSetLayout); + vkcv::ComputePipelineHandle imageClearPipeline = core.createComputePipeline({ + clearShaderProgram, + { core.getDescriptorSetLayout(imageClearDescriptorSetLayout).vulkanHandle } + }); + + vkcv::DescriptorWrites imageClearDescriptorWrites; + imageClearDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(0, meanImage) + }; + core.writeDescriptorSet(imageClearDescriptorSet, imageClearDescriptorWrites); + + // buffers + typedef std::pair<std::string, Material> MaterialSetting; + + std::vector<MaterialSetting> materialSettings; + materialSettings.emplace_back(MaterialSetting("white", Material(glm::vec3(0), glm::vec3(0.65), 0, 0.25, glm::vec3(0.04)))); + materialSettings.emplace_back(MaterialSetting("red", Material(glm::vec3(0), glm::vec3(0.5, 0.0, 0.0), 0, 0.25, glm::vec3(0.04)))); + materialSettings.emplace_back(MaterialSetting("green", Material(glm::vec3(0), glm::vec3(0.0, 0.5, 0.0), 0, 0.25, glm::vec3(0.04)))); + materialSettings.emplace_back(MaterialSetting("light", Material(glm::vec3(20), glm::vec3(0), 0, 0.25, glm::vec3(0.04)))); + materialSettings.emplace_back(MaterialSetting("sphere", Material(glm::vec3(0), glm::vec3(0.65), 1, 0.25, glm::vec3(0.04)))); + materialSettings.emplace_back(MaterialSetting("ground", Material(glm::vec3(0), glm::vec3(0.65), 0, 0.25, glm::vec3(0.04)))); + + const uint32_t whiteMaterialIndex = 0; + const uint32_t redMaterialIndex = 1; + const uint32_t greenMaterialIndex = 2; + const uint32_t lightMaterialIndex = 3; + const uint32_t sphereMaterialIndex = 4; + const uint32_t groundMaterialIndex = 5; + + std::vector<Sphere> spheres; + spheres.emplace_back(Sphere(glm::vec3(0, -1.5, 0), 0.5, sphereMaterialIndex)); + + std::vector<Plane> planes; + planes.emplace_back(Plane(glm::vec3( 0, -2, 0), glm::vec3( 0, 1, 0), glm::vec2(2), groundMaterialIndex)); + planes.emplace_back(Plane(glm::vec3( 0, 2, 0), glm::vec3( 0, -1, 0), glm::vec2(2), whiteMaterialIndex)); + planes.emplace_back(Plane(glm::vec3( 2, 0, 0), glm::vec3(-1, 0, 0), glm::vec2(2), redMaterialIndex)); + planes.emplace_back(Plane(glm::vec3(-2, 0, 0), glm::vec3( 1, 0, 0), glm::vec2(2), greenMaterialIndex)); + planes.emplace_back(Plane(glm::vec3( 0, 0, 2), glm::vec3( 0, 0, -1), glm::vec2(2), whiteMaterialIndex)); + planes.emplace_back(Plane(glm::vec3( 0, 1.9, 0), glm::vec3( 0, -1, 0), glm::vec2(1), lightMaterialIndex)); + + vkcv::Buffer<Sphere> sphereBuffer = core.createBuffer<Sphere>( + vkcv::BufferType::STORAGE, + spheres.size()); + sphereBuffer.fill(spheres); + + vkcv::Buffer<Plane> planeBuffer = core.createBuffer<Plane>( + vkcv::BufferType::STORAGE, + planes.size()); + planeBuffer.fill(planes); + + vkcv::Buffer<Material> materialBuffer = core.createBuffer<Material>( + vkcv::BufferType::STORAGE, + materialSettings.size()); + + vkcv::DescriptorWrites traceDescriptorWrites; + traceDescriptorWrites.storageBufferWrites = { + vkcv::BufferDescriptorWrite(0, sphereBuffer.getHandle()), + vkcv::BufferDescriptorWrite(1, planeBuffer.getHandle()), + vkcv::BufferDescriptorWrite(2, materialBuffer.getHandle())}; + traceDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(3, outputImage)}; + core.writeDescriptorSet(traceDescriptorSet, traceDescriptorWrites); + + vkcv::ComputePipelineHandle tracePipeline = core.createComputePipeline({ + traceShaderProgram, + { core.getDescriptorSetLayout(traceDescriptorSetLayout).vulkanHandle } + }); + + if (!tracePipeline) + { + vkcv_log(vkcv::LogLevel::ERROR, "Could not create graphics pipeline. Exiting."); + return EXIT_FAILURE; + } + + vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -2)); + + auto startTime = std::chrono::system_clock::now(); + float time = 0; + int frameIndex = 0; + bool clearMeanImage = true; + bool updateMaterials = true; + + float cameraPitchPrevious = 0; + float cameraYawPrevious = 0; + glm::vec3 cameraPositionPrevious = glm::vec3(0); + + uint32_t widthPrevious = initialWidth; + uint32_t heightPrevious = initialHeight; + + vkcv::gui::GUI gui(core, windowHandle); + + bool renderUI = true; + core.getWindow(windowHandle).e_key.add([&renderUI](int key, int scancode, int action, int mods) { + if (key == GLFW_KEY_I && action == GLFW_PRESS) { + renderUI = !renderUI; + } + }); + + glm::vec3 skyColor = glm::vec3(0.2, 0.7, 0.8); + float skyColorMultiplier = 1; + + while (vkcv::Window::hasOpenWindow()) + { + vkcv::Window::pollEvents(); + + uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem + if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { + continue; + } + + if (swapchainWidth != widthPrevious || swapchainHeight != heightPrevious) { + + // resize images + outputImage = core.createImage( + vk::Format::eR32G32B32A32Sfloat, + swapchainWidth, + swapchainHeight, + 1, + false, + true).getHandle(); + + meanImage = core.createImage( + vk::Format::eR32G32B32A32Sfloat, + swapchainWidth, + swapchainHeight, + 1, + false, + true).getHandle(); + + // update descriptor sets + traceDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(3, outputImage) }; + core.writeDescriptorSet(traceDescriptorSet, traceDescriptorWrites); + + vkcv::DescriptorWrites imageCombineDescriptorWrites; + imageCombineDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(0, outputImage), + vkcv::StorageImageDescriptorWrite(1, meanImage) + }; + core.writeDescriptorSet(imageCombineDescriptorSet, imageCombineDescriptorWrites); + + vkcv::DescriptorWrites imageClearDescriptorWrites; + imageClearDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(0, meanImage) + }; + core.writeDescriptorSet(imageClearDescriptorSet, imageClearDescriptorWrites); + + widthPrevious = swapchainWidth; + heightPrevious = swapchainHeight; + + clearMeanImage = true; + } + + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - startTime); + startTime = end; + + time += 0.000001f * static_cast<float>(deltatime.count()); + + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + + const vkcv::CommandStreamHandle cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + uint32_t fullscreenDispatchCount[3] = { + static_cast<uint32_t> (std::ceil(swapchainWidth / 8.f)), + static_cast<uint32_t> (std::ceil(swapchainHeight / 8.f)), + 1 }; + + if (updateMaterials) { + std::vector<Material> materials; + for (const auto& settings : materialSettings) { + materials.push_back(settings.second); + } + materialBuffer.fill(materials); + updateMaterials = false; + clearMeanImage = true; + } + + float cameraPitch; + float cameraYaw; + cameraManager.getActiveCamera().getAngles(cameraPitch, cameraYaw); + + if (glm::abs(cameraPitch - cameraPitchPrevious) > 0.01 || glm::abs(cameraYaw - cameraYawPrevious) > 0.01) + clearMeanImage = true; // camera rotated + + cameraPitchPrevious = cameraPitch; + cameraYawPrevious = cameraYaw; + + glm::vec3 cameraPosition = cameraManager.getActiveCamera().getPosition(); + + if(glm::distance(cameraPosition, cameraPositionPrevious) > 0.0001) + clearMeanImage = true; // camera moved + + cameraPositionPrevious = cameraPosition; + + if (clearMeanImage) { + core.prepareImageForStorage(cmdStream, meanImage); + + core.recordComputeDispatchToCmdStream(cmdStream, + imageClearPipeline, + fullscreenDispatchCount, + { vkcv::DescriptorSetUsage(0, core.getDescriptorSet(imageClearDescriptorSet).vulkanHandle) }, + vkcv::PushConstants(0)); + + clearMeanImage = false; + } + + // path tracing + struct RaytracingPushConstantData { + glm::mat4 viewToWorld; + glm::vec3 skyColor; + int32_t sphereCount; + int32_t planeCount; + int32_t frameIndex; + }; + + RaytracingPushConstantData raytracingPushData; + raytracingPushData.viewToWorld = glm::inverse(cameraManager.getActiveCamera().getView()); + raytracingPushData.skyColor = skyColor * skyColorMultiplier; + raytracingPushData.sphereCount = spheres.size(); + raytracingPushData.planeCount = planes.size(); + raytracingPushData.frameIndex = frameIndex; + + vkcv::PushConstants pushConstantsCompute(sizeof(RaytracingPushConstantData)); + pushConstantsCompute.appendDrawcall(raytracingPushData); + + uint32_t traceDispatchCount[3] = { + static_cast<uint32_t> (std::ceil(swapchainWidth / 16.f)), + static_cast<uint32_t> (std::ceil(swapchainHeight / 16.f)), + 1 }; + + core.prepareImageForStorage(cmdStream, outputImage); + + core.recordComputeDispatchToCmdStream(cmdStream, + tracePipeline, + traceDispatchCount, + { vkcv::DescriptorSetUsage(0,core.getDescriptorSet(traceDescriptorSet).vulkanHandle) }, + pushConstantsCompute); + + core.prepareImageForStorage(cmdStream, meanImage); + core.recordImageMemoryBarrier(cmdStream, outputImage); + + // combine images + core.recordComputeDispatchToCmdStream(cmdStream, + imageCombinePipeline, + fullscreenDispatchCount, + { vkcv::DescriptorSetUsage(0,core.getDescriptorSet(imageCombineDescriptorSet).vulkanHandle) }, + vkcv::PushConstants(0)); + + core.recordImageMemoryBarrier(cmdStream, meanImage); + + // present image + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + vkcv::DescriptorWrites presentDescriptorWrites; + presentDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(0, meanImage), + vkcv::StorageImageDescriptorWrite(1, swapchainInput) }; + core.writeDescriptorSet(presentDescriptorSet, presentDescriptorWrites); + + core.prepareImageForStorage(cmdStream, swapchainInput); + + core.recordComputeDispatchToCmdStream(cmdStream, + presentPipeline, + fullscreenDispatchCount, + { vkcv::DescriptorSetUsage(0,core.getDescriptorSet(presentDescriptorSet).vulkanHandle) }, + vkcv::PushConstants(0)); + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + if (renderUI) { + gui.beginGUI(); + + ImGui::Begin("Settings"); + + clearMeanImage |= ImGui::ColorEdit3("Sky color", &skyColor.x); + clearMeanImage |= ImGui::InputFloat("Sky color multiplier", &skyColorMultiplier); + + if (ImGui::CollapsingHeader("Materials")) { + + for (auto& setting : materialSettings) { + if (ImGui::CollapsingHeader(setting.first.c_str())) { + + const glm::vec3 emission = setting.second.emission; + float emissionStrength = glm::max(glm::max(glm::max(emission.x, emission.y), emission.z), 1.f); + glm::vec3 emissionColor = emission / emissionStrength; + + updateMaterials |= ImGui::ColorEdit3((std::string("Emission color ") + setting.first).c_str(), &emissionColor.x); + updateMaterials |= ImGui::InputFloat((std::string("Emission strength ") + setting.first).c_str(), &emissionStrength); + + setting.second.emission = emissionStrength * emissionColor; + + updateMaterials |= ImGui::ColorEdit3((std::string("Albedo color ") + setting.first).c_str(), &setting.second.albedo.x); + updateMaterials |= ImGui::ColorEdit3((std::string("F0 ") + setting.first).c_str(), &setting.second.f0.x); + updateMaterials |= ImGui::DragFloat(( std::string("ks ") + setting.first).c_str(), &setting.second.ks, 0.01, 0, 1); + updateMaterials |= ImGui::DragFloat(( std::string("roughness ") + setting.first).c_str(), &setting.second.roughness, 0.01, 0, 1); + + } + } + } + + ImGui::End(); + + gui.endGUI(); + } + + core.endFrame(windowHandle); + + frameIndex++; + } + return 0; +} diff --git a/projects/rtx_ambient_occlusion/.gitignore b/projects/rtx_ambient_occlusion/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..61b2ff94710af817f199d848e4253062c024a6bf --- /dev/null +++ b/projects/rtx_ambient_occlusion/.gitignore @@ -0,0 +1 @@ +rtx_ambient_occlusion \ No newline at end of file diff --git a/projects/rtx_ambient_occlusion/CMakeLists.txt b/projects/rtx_ambient_occlusion/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..414279c3fead126a7c7f581f0dc7c42c11158a9e --- /dev/null +++ b/projects/rtx_ambient_occlusion/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.16) +project(rtx_ambient_occlusion) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +set(rtx_source ${PROJECT_SOURCE_DIR}/src/RTX) + +set(rtx_sources + ${rtx_source}/RTX.hpp + ${rtx_source}/RTX.cpp + + ${rtx_source}/ASManager.hpp + ${rtx_source}/ASManager.cpp + + ${rtx_source}/RTXExtensions.hpp + ${rtx_source}/RTXExtensions.cpp + ) + +# adding source files to the project +add_executable(rtx_ambient_occlusion src/main.cpp src/teapot.hpp ${rtx_sources}) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(rtx_ambient_occlusion PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(rtx_ambient_occlusion PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(rtx_ambient_occlusion PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(rtx_ambient_occlusion SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_scene_include} ${vkcv_shader_compiler_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(rtx_ambient_occlusion vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_scene vkcv_shader_compiler) diff --git a/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit new file mode 100644 index 0000000000000000000000000000000000000000..b073916e4eaf992d5e6ae4186013478634263fbd --- /dev/null +++ b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rchit @@ -0,0 +1,48 @@ +#version 460 +#extension GL_EXT_ray_tracing : require +#extension GL_EXT_scalar_block_layout : require + +hitAttributeEXT vec2 attributes; + +layout(location = 0) rayPayloadInEXT Payload { + float hitSky; + vec3 worldPosition; + vec3 worldNormal; +} payload; + +layout(binding = 2, set = 0) uniform accelerationStructureEXT tlas; // top level acceleration structure + +layout(binding = 3, set = 0, scalar) buffer rtxVertices +{ + float vertices[]; +}; + +layout(binding = 4, set = 0, scalar) buffer rtxIndices +{ + uint indices[]; +}; + +void main() { + payload.worldPosition = vec3(1.0, 0.0, 0.5); + + ivec3 indicesVec = ivec3(indices[3 * gl_PrimitiveID + 0], indices[3 * gl_PrimitiveID + 1], indices[3 * gl_PrimitiveID + 2]); + + // current triangle + const vec3 v0 = vec3(vertices[3 * indicesVec.x + 0],vertices[3 * indicesVec.x + 1],vertices[3 * indicesVec.x + 2]); + const vec3 v1 = vec3(vertices[3 * indicesVec.y + 0],vertices[3 * indicesVec.y + 1],vertices[3 * indicesVec.y + 2]); + const vec3 v2 = vec3(vertices[3 * indicesVec.z + 0],vertices[3 * indicesVec.z + 1],vertices[3 * indicesVec.z + 2]); + + // use barycentric coordinates to compute intersection + const vec3 barycentrics = vec3(1.0 - attributes.x - attributes.y, attributes.xy); + const vec3 objectPosition = v0 * barycentrics.x + v1 * barycentrics.y + v2 * barycentrics.z; + + payload.worldPosition = gl_ObjectToWorldEXT * vec4(objectPosition, 1.0); + + const vec3 objectNormal = cross(v1 - v0, v2 - v0); + + payload.worldNormal = normalize((objectNormal * gl_WorldToObjectEXT).xyz); + + payload.worldNormal = faceforward(payload.worldNormal, gl_WorldRayDirectionEXT, payload.worldNormal); + + payload.hitSky = 0.0f; +} diff --git a/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rgen b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rgen new file mode 100644 index 0000000000000000000000000000000000000000..711070fcf1eec18253f331cbd133330791fa6be6 --- /dev/null +++ b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rgen @@ -0,0 +1,158 @@ +#version 460 +#extension GL_EXT_ray_tracing : require + +#define M_PI 3.1415926535897932384626433832795 + +// A location for a ray payload (we can have multiple of these) +layout(location = 0) rayPayloadEXT Payload { + float hitSky; + vec3 worldPosition; + vec3 worldNormal; +} payload; + +layout(binding = 0, set = 0, rgba16) uniform image2D outImg; // the output image -> maybe use 16 bit values? +layout(binding = 1, set = 0) uniform accelerationStructureEXT tlas; // top level acceleration structure + +layout( push_constant ) uniform constants { + vec4 camera_position; // as origin for ray generation + vec4 camera_right; // for computing ray direction + vec4 camera_up; // for computing ray direction + vec4 camera_forward; // for computing ray direction +} camera; + +// random() and helpers from: https://www.shadertoy.com/view/XlycWh +float g_seed = 0; + +uint base_hash(uvec2 p) { + p = 1103515245U*((p >> 1U)^(p.yx)); + uint h32 = 1103515245U*((p.x)^(p.y>>3U)); + return h32^(h32 >> 16); +} + +vec2 hash2(inout float seed) { + uint n = base_hash(floatBitsToUint(vec2(seed+=.1,seed+=.1))); + uvec2 rz = uvec2(n, n*48271U); + return vec2(rz.xy & uvec2(0x7fffffffU))/float(0x7fffffff); +} + +void initRandom(uvec2 coord){ + g_seed = float(base_hash(coord)/float(0xffffffffU)); +} + +vec2 random(){ + return hash2(g_seed); +} + +/** + * Traces the ray from the camera and provides the intersection information. + * @param[in,out] hitSky Defines if the ray has hit the sky + * @param[in,out] pos The position of intersection + * @param[in,out] norm The normal at the position of intersection + */ +void TraceCameraRay(out bool hitSky, out vec3 pos, out vec3 norm){ + // Use a camera model to generate a ray for this pixel. + vec2 uv = gl_LaunchIDEXT.xy + vec2(random()); // random breaks up aliasing + uv /= vec2(gl_LaunchSizeEXT.xy); + uv = (uv * 2.0 - 1.0) // normalize uv coordinates into Vulkan viewport space + * vec2(1.0, -1.0); // flips y-axis + const vec3 orig = camera.camera_position.xyz; + const vec3 dir = normalize(uv.x * camera.camera_right + uv.y * camera.camera_up + camera.camera_forward).xyz; + + // Trace a ray into the scene; get back data in the payload. + traceRayEXT(tlas, // Acceleration structure + gl_RayFlagsOpaqueEXT, // Ray flags, here saying "ignore intersection shaders" + 0xFF, // 8-bit instance mask, here saying "trace against all instances" + 0, // SBT record offset + 0, // SBT record stride for offset + 0, // Miss index + orig, // Ray origin + 0.0, // Minimum t-value + dir, // Ray direction + 1000.0, // Maximum t-value + 0); // Location of payload + + // Read the values from the payload: + hitSky = (payload.hitSky > 0.0); + pos = payload.worldPosition; + norm = payload.worldNormal; +} + +/** + * @brief Casts a shadow ray. Returns @p true, if the shadow ray hit the sky. + * @param[in] orig The point of origin of the shadow ray. + * @param[in] dir The direction of the shadow ray. + */ +float CastShadowRay(vec3 orig, vec3 dir){ + payload.hitSky = 0.0f; // Assume ray is occluded + traceRayEXT(tlas, // Acceleration structure + gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT | gl_RayFlagsTerminateOnFirstHitEXT, // Ray flags, here saying "ignore any hit shaders and closest hit shaders, and terminate the ray on the first found intersection" + 0xFF, // 8-bit instance mask, here saying "trace against all instances" + 0, // SBT record offset + 0, // SBT record stride for offset + 0, // Miss index + orig, // Ray origin + 0.0001, // Minimum t-value - avoid self intersection + dir, // Ray direction + 1000.0, // Maximum t-value + 0); // Location of payload + return payload.hitSky; +} + +vec3 sampleCosineDistribution(vec2 xi){ + float phi = 2 * M_PI * xi.y; + return vec3( + sqrt(xi.x) * cos(phi), + sqrt(1 - xi.x), + sqrt(xi.x) * sin(phi)); +} + +struct Basis{ + vec3 right; + vec3 up; + vec3 forward; +}; + +Basis buildBasisAroundNormal(vec3 N){ + Basis basis; + basis.up = N; + basis.right = abs(basis.up.x) < 0.99 ? vec3(1, 0, 0) : vec3(0, 0, 1); + basis.forward = normalize(cross(basis.up, basis.right)); + basis.right = cross(basis.up, basis.forward); + return basis; +} + +vec3 sampleTangentToWorldSpace(vec3 tangentSpaceSample, vec3 N){ + Basis tangentBasis = buildBasisAroundNormal(N); + return + tangentBasis.right * tangentSpaceSample.x + + tangentBasis.up * tangentSpaceSample.y + + tangentBasis.forward * tangentSpaceSample.z; +} + +void main(){ + uint rayCount = 64; // the amount of rays to be casted + + initRandom(gl_LaunchIDEXT.xy); + + uvec2 pixel = gl_LaunchIDEXT.xy; + bool pixelIsSky; // Does the pixel show the sky (not an object)? + vec3 pos, norm; // AO rays from where? + TraceCameraRay(pixelIsSky, pos, norm); + + if(pixelIsSky){ + // Don't compute ambient occlusion for the sky + imageStore(outImg, ivec2(pixel), vec4(0.8,0.8,0.8,1.0)); + return; + } + + // Compute ambient occlusion + float aoValue = 0.0; + for(uint i = 0; i < rayCount; i++){ + vec3 sampleTangentSpace = sampleCosineDistribution(random()); + vec3 sampleWorldSpace = sampleTangentToWorldSpace(sampleTangentSpace, norm); + aoValue += CastShadowRay(pos, sampleWorldSpace); + } + aoValue /= rayCount; + + imageStore(outImg, ivec2(pixel), vec4(vec3(aoValue), 1)); +} diff --git a/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rmiss b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rmiss new file mode 100644 index 0000000000000000000000000000000000000000..c107dbd03e6a8fdfdd84d2b8d280cb6264307c14 --- /dev/null +++ b/projects/rtx_ambient_occlusion/resources/shaders/ambientOcclusion.rmiss @@ -0,0 +1,12 @@ +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(location = 0) rayPayloadInEXT Payload { + float hitSky; + vec3 worldPosition; + vec3 worldNormal; +} payload; + +void main() { + payload.hitSky = 1.0f; +} diff --git a/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c09e669dc94b05235dbb2f6e5f0b40d274e1c182 --- /dev/null +++ b/projects/rtx_ambient_occlusion/src/RTX/ASManager.cpp @@ -0,0 +1,460 @@ +#include "ASManager.hpp" +#include <array> + +namespace vkcv::rtx { + + + ASManager::ASManager(vkcv::Core *core) : + m_core(core), + m_device(&(core->getContext().getDevice())){ + // INFO: Using RTX extensions implies that we cannot use the standard dispatcher from Vulkan because using RTX + // specific functions via vk::Device will result in validation errors. Instead we need to use a + // vk::DispatchLoaderDynamic which is used as dispatcher parameter of the device functions. + m_rtxDispatcher = vk::DispatchLoaderDynamic( (PFN_vkGetInstanceProcAddr) m_core->getContext().getInstance().getProcAddr("vkGetInstanceProcAddr") ); + m_rtxDispatcher.init(m_core->getContext().getInstance()); + + // TODO: Recursive call of buildBLAS for bigger scenes. Currently, the RTX module only supports one mesh. + } + + ASManager::~ASManager() noexcept { + m_rtxDispatcher = vk::DispatchLoaderDynamic( (PFN_vkGetInstanceProcAddr) m_core->getContext().getInstance().getProcAddr("vkGetInstanceProcAddr") ); + m_rtxDispatcher.init(m_core->getContext().getInstance()); + + // destroy every BLAS, its data containers and free used memory blocks + for (size_t i=0; i < m_bottomLevelAccelerationStructures.size(); i++) { + BottomLevelAccelerationStructure blas = m_bottomLevelAccelerationStructures[i]; + m_core->getContext().getDevice().destroyAccelerationStructureKHR(blas.vulkanHandle, nullptr, m_rtxDispatcher); + m_core->getContext().getDevice().destroy(blas.accelerationBuffer.vulkanHandle); + m_core->getContext().getDevice().destroy(blas.indexBuffer.vulkanHandle); + m_core->getContext().getDevice().destroy(blas.vertexBuffer.vulkanHandle); + + m_core->getContext().getDevice().freeMemory(blas.accelerationBuffer.deviceMemory); + m_core->getContext().getDevice().freeMemory(blas.indexBuffer.deviceMemory); + m_core->getContext().getDevice().freeMemory(blas.vertexBuffer.deviceMemory); + } + + // destroy the TLAS, its data containers and free used memory blocks + TopLevelAccelerationStructure tlas = m_topLevelAccelerationStructure; + m_core->getContext().getDevice().destroyAccelerationStructureKHR(tlas.vulkanHandle, nullptr, m_rtxDispatcher); + m_core->getContext().getDevice().destroy(tlas.tlasBuffer.vulkanHandle); + m_core->getContext().getDevice().destroy(tlas.gpuBufferInstances.vulkanHandle); + + m_core->getContext().getDevice().freeMemory(tlas.tlasBuffer.deviceMemory); + m_core->getContext().getDevice().freeMemory(tlas.gpuBufferInstances.deviceMemory); + } + + + + vk::CommandPool ASManager::createCommandPool() { + vk::CommandPool commandPool; + vk::CommandPoolCreateInfo commandPoolCreateInfo; + commandPoolCreateInfo.setQueueFamilyIndex(m_core->getContext().getQueueManager().getComputeQueues()[0].familyIndex); + vk::Result res = m_device->createCommandPool(&commandPoolCreateInfo, nullptr, &commandPool); + if (res != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "ASManager: command pool could not be created! (%s)", vk::to_string(res).c_str()); + } + return commandPool; + }; + + vk::CommandBuffer ASManager::createAndBeginCommandBuffer(vk::CommandPool commandPool) + { + vk::CommandBufferAllocateInfo commandBufferAllocateInfo{}; + commandBufferAllocateInfo.setLevel(vk::CommandBufferLevel::ePrimary); + commandBufferAllocateInfo.setCommandPool(commandPool); + commandBufferAllocateInfo.setCommandBufferCount(1); + vk::CommandBuffer commandBuffer; + vk::Result result = m_device->allocateCommandBuffers(&commandBufferAllocateInfo, &commandBuffer); + if (result != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "ASManager: command buffer for Acceleration Strucutre Build could not be allocated! (%s)", vk::to_string(result).c_str()); + } + + beginCommandBuffer(commandBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit); + return commandBuffer; + } + + void ASManager::submitCommandBuffer(vk::CommandPool commandPool, vk::CommandBuffer& commandBuffer) + { + commandBuffer.end(); + + vk::SubmitInfo submitInfo; + submitInfo.setCommandBufferCount(1); + submitInfo.setPCommandBuffers(&commandBuffer); + + vkcv::Queue queue = m_core->getContext().getQueueManager().getComputeQueues()[0]; + + queue.handle.submit(submitInfo); + queue.handle.waitIdle(); + + m_device->freeCommandBuffers(commandPool, 1, &commandBuffer); + m_device->destroyCommandPool(commandPool); + } + + vk::DeviceAddress ASManager::getBufferDeviceAddress(vk::Buffer buffer) + { + vk::BufferDeviceAddressInfo bufferDeviceAddressInfo(buffer); + return m_device->getBufferAddress(bufferDeviceAddressInfo); + } + + void ASManager::createBuffer(RTXBuffer& buffer) { + + vk::BufferCreateInfo bufferCreateInfo; + bufferCreateInfo.setFlags(vk::BufferCreateFlags()); + bufferCreateInfo.setUsage(buffer.bufferUsageFlagBits); + bufferCreateInfo.setSize(buffer.deviceSize); + + buffer.vulkanHandle = m_device->createBuffer(bufferCreateInfo); + vk::MemoryRequirements2 memoryRequirements2; + vk::MemoryDedicatedRequirements dedicatedRequirements; + vk::BufferMemoryRequirementsInfo2 bufferRequirements; + + bufferRequirements.setBuffer(buffer.vulkanHandle); + memoryRequirements2.pNext = &dedicatedRequirements; + m_device->getBufferMemoryRequirements2(&bufferRequirements, &memoryRequirements2); + + vk::PhysicalDeviceMemoryProperties physicalDeviceMemoryProperties = m_core->getContext().getPhysicalDevice().getMemoryProperties(); + + uint32_t memoryTypeIndex = -1; + for (int i = 0; i < physicalDeviceMemoryProperties.memoryTypeCount; i++) { + if ((memoryRequirements2.memoryRequirements.memoryTypeBits & (1 << i)) + && (physicalDeviceMemoryProperties.memoryTypes[i].propertyFlags & buffer.memoryPropertyFlagBits) == buffer.memoryPropertyFlagBits) { + memoryTypeIndex = i; + break; + } + } + + vk::MemoryAllocateInfo memoryAllocateInfo( + memoryRequirements2.memoryRequirements.size, // size of allocation in bytes + memoryTypeIndex // index identifying a memory type from the memoryTypes array of the vk::PhysicalDeviceMemoryProperties structure. + ); + vk::MemoryAllocateFlagsInfo allocateFlagsInfo( + vk::MemoryAllocateFlagBits::eDeviceAddress // vk::MemoryAllocateFlags + ); + memoryAllocateInfo.setPNext(&allocateFlagsInfo); // extend memory allocate info with allocate flag info + buffer.deviceMemory = m_device->allocateMemory(memoryAllocateInfo); + + uint32_t memoryOffset = 0; + m_device->bindBufferMemory(buffer.vulkanHandle, buffer.deviceMemory, memoryOffset); + + // only fill data in case of CPU buffer + if (buffer.bufferType == RTXBufferType::STAGING) { + void* mapped = m_device->mapMemory(buffer.deviceMemory, memoryOffset, buffer.deviceSize); + std::memcpy(mapped, buffer.data, buffer.deviceSize); + m_device->unmapMemory(buffer.deviceMemory); + } + } + + void ASManager::copyFromCPUToGPU(RTXBuffer& cpuBuffer, RTXBuffer& gpuBuffer) { + SubmitInfo submitInfo; + submitInfo.queueType = QueueType::Graphics; + + vk::CommandPool commandPool= createCommandPool(); + vk::CommandBuffer commandBuffer= createAndBeginCommandBuffer(commandPool); + vk::BufferCopy bufferCopy; + bufferCopy.size = cpuBuffer.deviceSize; + commandBuffer.copyBuffer(cpuBuffer.vulkanHandle, gpuBuffer.vulkanHandle, 1, &bufferCopy); + + submitCommandBuffer(commandPool,commandBuffer); + + m_device->destroyBuffer(cpuBuffer.vulkanHandle); + m_device->freeMemory(cpuBuffer.deviceMemory); + } + + void ASManager::buildBLAS(RTXBuffer vertexBuffer, uint32_t vertexCount, RTXBuffer indexBuffer, uint32_t indexCount) { + // TODO: organize hierarchical structure of multiple BLAS + + vk::DeviceAddress vertexBufferAddress = getBufferDeviceAddress(vertexBuffer.vulkanHandle); + vk::DeviceAddress indexBufferAddress = getBufferDeviceAddress(indexBuffer.vulkanHandle); + + // triangle mesh data + vk::AccelerationStructureGeometryTrianglesDataKHR asTriangles( + vk::Format::eR32G32B32Sfloat, // vertex format + vertexBufferAddress, // vertex buffer address (vk::DeviceOrHostAddressConstKHR) + 3 * sizeof(float), // vertex stride (vk::DeviceSize) + uint32_t(vertexCount - 1), // maxVertex (uint32_t) + vk::IndexType::eUint32, // indexType (vk::IndexType) --> INFO: UINT16 oder UINT32! + indexBufferAddress, // indexData (vk::DeviceOrHostAddressConstKHR) + {} // transformData (vk::DeviceOrHostAddressConstKHR) + ); + + // Geometry data + vk::AccelerationStructureGeometryKHR asGeometry( + vk::GeometryTypeKHR::eTriangles, // The geometry type, e.g. triangles, AABBs, instances + asTriangles, // the geometry data + vk::GeometryFlagBitsKHR::eOpaque // This flag disables any-hit shaders to increase ray tracing performance + ); + + // Ranges for data lists + vk::AccelerationStructureBuildRangeInfoKHR asRangeInfo( + uint32_t(indexCount / 3), // the primitiveCount (uint32_t) + 0, // primitiveOffset (uint32_t) + 0, // firstVertex (uint32_t) + 0 // transformOffset (uint32_t) + ); + + // Settings and array of geometries to build into BLAS + vk::AccelerationStructureBuildGeometryInfoKHR asBuildInfo( + vk::AccelerationStructureTypeKHR::eBottomLevel, // type of the AS: bottom vs. top + vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace, // some flags for different purposes, e.g. efficiency + vk::BuildAccelerationStructureModeKHR::eBuild, // AS mode: build vs. update + {}, // src AS (this seems to be for copying AS) + {}, // dst AS (this seems to be for copying AS) + 1, // the geometryCount. TODO: how many do we need? + &asGeometry // the next input entry would be a pointer to a pointer to geometries. Maybe geometryCount depends on the next entry? + ); + + // Calculate memory needed for AS + vk::AccelerationStructureBuildSizesInfoKHR asBuildSizesInfo; + m_device->getAccelerationStructureBuildSizesKHR( + vk::AccelerationStructureBuildTypeKHR::eDevice, // build on device instead of host + &asBuildInfo, // pointer to build info + &asRangeInfo.primitiveCount, // array of number of primitives per geometry + &asBuildSizesInfo, // output pointer to store sizes + m_rtxDispatcher + ); + + // create buffer for acceleration structure + RTXBuffer blasBuffer; + blasBuffer.bufferType = RTXBufferType::ACCELERATION; + blasBuffer.deviceSize = asBuildSizesInfo.accelerationStructureSize; + blasBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eAccelerationStructureStorageKHR + | vk::BufferUsageFlagBits::eShaderDeviceAddress + | vk::BufferUsageFlagBits::eStorageBuffer; + blasBuffer.memoryPropertyFlagBits = { vk::MemoryPropertyFlagBits::eDeviceLocal }; + + createBuffer(blasBuffer); + + // Create an empty AS object + vk::AccelerationStructureCreateInfoKHR asCreateInfo( + vk::AccelerationStructureCreateFlagsKHR(), // creation flags + blasBuffer.vulkanHandle, // allocated AS buffer. + 0, + asBuildSizesInfo.accelerationStructureSize, // size of the AS + asBuildInfo.type // type of the AS + ); + + // Create the intended AS object + vk::AccelerationStructureKHR blasKHR; + vk::Result res = m_device->createAccelerationStructureKHR( + &asCreateInfo, // AS create info + nullptr, // allocator callbacks + &blasKHR, // the AS + m_rtxDispatcher + ); + if (res != vk::Result::eSuccess) { + vkcv_log(vkcv::LogLevel::ERROR, "The Bottom Level Acceleration Structure could not be build! (%s)", vk::to_string(res).c_str()); + } + asBuildInfo.setDstAccelerationStructure(blasKHR); + + // Create temporary scratch buffer used for building the AS + RTXBuffer scratchBuffer; + scratchBuffer.bufferType = RTXBufferType::SCRATCH; + scratchBuffer.deviceSize = asBuildSizesInfo.buildScratchSize; + scratchBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eShaderDeviceAddress + | vk::BufferUsageFlagBits::eStorageBuffer; + scratchBuffer.memoryPropertyFlagBits = { vk::MemoryPropertyFlagBits::eDeviceLocal }; + + createBuffer(scratchBuffer); + + asBuildInfo.setScratchData(getBufferDeviceAddress(scratchBuffer.vulkanHandle)); + + // Pointer to rangeInfo, used later for build + vk::AccelerationStructureBuildRangeInfoKHR* pointerToRangeInfo = &asRangeInfo; + + vk::CommandPool commandPool = createCommandPool(); + vk::CommandBuffer commandBuffer = createAndBeginCommandBuffer(commandPool); + + commandBuffer.buildAccelerationStructuresKHR(1, &asBuildInfo, &pointerToRangeInfo, m_rtxDispatcher); + + submitCommandBuffer(commandPool, commandBuffer); + + m_core->getContext().getDevice().destroyBuffer(scratchBuffer.vulkanHandle, nullptr, m_rtxDispatcher); + m_core->getContext().getDevice().freeMemory(scratchBuffer.deviceMemory, nullptr, m_rtxDispatcher); + + BottomLevelAccelerationStructure blas = { + vertexBuffer, + indexBuffer, + blasBuffer, + blasKHR + }; + m_bottomLevelAccelerationStructures.push_back(blas); + } + + void ASManager::buildTLAS() { + // TODO: organize hierarchical structure of multiple BLAS + + // We need an the device address of each BLAS --> TODO: for loop for bigger scenes + vk::AccelerationStructureDeviceAddressInfoKHR addressInfo( + m_bottomLevelAccelerationStructures[0].vulkanHandle + ); + vk::DeviceAddress blasAddress = m_device->getAccelerationStructureAddressKHR(&addressInfo, m_rtxDispatcher); + + std::array<std::array<float, 4>, 3> transformMatrix = { + std::array<float, 4>{1.f, 0.f, 0.f, 0.f}, + std::array<float, 4>{0.f, 1.f, 0.f, 0.f}, + std::array<float, 4>{0.f, 0.f, 1.f, 0.f}, + }; + + vk::TransformMatrixKHR transformMatrixKhr( + transformMatrix // std::array<std::array<float,4>,3> const& + ); + + vk::AccelerationStructureInstanceKHR accelerationStructureInstanceKhr( + transformMatrixKhr, // vk::TransformMatrixKHR transform_ = {}, + 0, // uint32_t instanceCustomIndex, + 0xFF, //uint32_t mask_ = {}, + 0, // uint32_t instanceShaderBindingTableRecordOffset, + vk::GeometryInstanceFlagBitsKHR::eTriangleFacingCullDisable, // vk::GeometryInstanceFlagsKHR + blasAddress // uint64_t accelerationStructureReference (the device address of the BLAS) + ); + + // create a buffer of instances on the device and upload the array of instances to it + RTXBuffer stagingBufferInstances; + stagingBufferInstances.bufferType = RTXBufferType::STAGING; + stagingBufferInstances.deviceSize = sizeof(accelerationStructureInstanceKhr); + stagingBufferInstances.data = &accelerationStructureInstanceKhr; + stagingBufferInstances.bufferUsageFlagBits = vk::BufferUsageFlagBits::eShaderDeviceAddress + | vk::BufferUsageFlagBits::eTransferSrc; + stagingBufferInstances.memoryPropertyFlagBits = vk::MemoryPropertyFlagBits::eHostCoherent + | vk::MemoryPropertyFlagBits::eHostVisible; + + createBuffer(stagingBufferInstances); + + RTXBuffer bufferInstances; + bufferInstances.bufferType = RTXBufferType::GPU; + bufferInstances.deviceSize = sizeof(accelerationStructureInstanceKhr); + bufferInstances.bufferUsageFlagBits = vk::BufferUsageFlagBits::eShaderDeviceAddress + | vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eTransferSrc; + bufferInstances.memoryPropertyFlagBits = vk::MemoryPropertyFlagBits::eDeviceLocal; + + createBuffer(bufferInstances); + copyFromCPUToGPU(stagingBufferInstances, bufferInstances); // automatically deletes and frees memory of stagingBufferInstances + + vk::MemoryBarrier barrier; + barrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite); + barrier.setDstAccessMask(vk::AccessFlagBits::eAccelerationStructureWriteKHR); + vk::CommandPool commandPool = createCommandPool(); + vk::CommandBuffer commandBuffer = createAndBeginCommandBuffer(commandPool); + commandBuffer.pipelineBarrier( + vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eAccelerationStructureBuildKHR, + {},1,&barrier,0, nullptr,0,nullptr); + submitCommandBuffer(commandPool, commandBuffer); + + + // ranging information for TLAS build + vk::AccelerationStructureBuildRangeInfoKHR asRangeInfo( + 1, // primitiveCount -> number of instances + 0, // primitiveOffset + 0, // firstVertex + 0 //transformOffset + ); + + vk::DeviceAddress bufferInstancesAddress = getBufferDeviceAddress(bufferInstances.vulkanHandle); + + vk::AccelerationStructureGeometryInstancesDataKHR asInstances( + false, // vk::Bool32 arrayOfPointers + bufferInstancesAddress // vk::DeviceOrHostAddressConstKHR data_ = {} + ); + + // Geometry, in this case instances of BLAS + vk::AccelerationStructureGeometryKHR asGeometry( + vk::GeometryTypeKHR::eInstances, // vk::GeometryTypeKHR geometryType_ = vk::GeometryTypeKHR::eTriangles + asInstances, // vk::AccelerationStructureGeometryDataKHR geometry_ = {} + {} // vk::GeometryFlagsKHR flags_ = {} + ); + + // Finally, create the TLAS + vk::AccelerationStructureBuildGeometryInfoKHR asBuildInfo( + vk::AccelerationStructureTypeKHR::eTopLevel, // type of the AS: bottom vs. top + vk::BuildAccelerationStructureFlagBitsKHR::ePreferFastTrace, // some flags for different purposes, e.g. efficiency + vk::BuildAccelerationStructureModeKHR::eBuild, // AS mode: build vs. update + {}, // src AS (this seems to be for copying AS) + {}, // dst AS (this seems to be for copying AS) + 1, // the geometryCount. + &asGeometry // the next input entry would be a pointer to a pointer to geometries. Maybe geometryCount depends on the next entry? + ); + + // AS size and scratch space size, given by count of instances (1) + vk::AccelerationStructureBuildSizesInfoKHR asSizeInfo; + m_core->getContext().getDevice().getAccelerationStructureBuildSizesKHR( + vk::AccelerationStructureBuildTypeKHR::eDevice, + &asBuildInfo, + &asRangeInfo.primitiveCount, + &asSizeInfo, + m_rtxDispatcher + ); + + // Create buffer for the TLAS + RTXBuffer tlasBuffer; + tlasBuffer.bufferType = RTXBufferType::ACCELERATION; + tlasBuffer.deviceSize = asSizeInfo.accelerationStructureSize; + tlasBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eAccelerationStructureStorageKHR + | vk::BufferUsageFlagBits::eShaderDeviceAddress + | vk::BufferUsageFlagBits::eStorageBuffer; + + createBuffer(tlasBuffer); + + // Create empty TLAS object + vk::AccelerationStructureCreateInfoKHR asCreateInfo( + {}, // creation flags + tlasBuffer.vulkanHandle, // allocated AS buffer. + 0, + asSizeInfo.accelerationStructureSize, // size of the AS + asBuildInfo.type // type of the AS + ); + + vk::AccelerationStructureKHR tlas; + vk::Result res = m_device->createAccelerationStructureKHR(&asCreateInfo, nullptr, &tlas, m_rtxDispatcher); + if (res != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "Top Level Acceleration Structure could not be created! (%s)", vk::to_string(res).c_str()); + } + asBuildInfo.setDstAccelerationStructure(tlas); + + // Create temporary scratch buffer used for building the AS + RTXBuffer tlasScratchBuffer; // scratch buffer + tlasScratchBuffer.bufferType = RTXBufferType::ACCELERATION; + tlasScratchBuffer.deviceSize = asSizeInfo.buildScratchSize; + tlasScratchBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eShaderDeviceAddressKHR + | vk::BufferUsageFlagBits::eStorageBuffer; + + createBuffer(tlasScratchBuffer); + + vk::BufferDeviceAddressInfo tempBuildDataBufferDeviceAddressInfo(tlasScratchBuffer.vulkanHandle); + vk::DeviceAddress tempBuildBufferDataAddress = m_core->getContext().getDevice().getBufferAddressKHR(tempBuildDataBufferDeviceAddressInfo, m_rtxDispatcher); + asBuildInfo.setScratchData(tempBuildBufferDataAddress); + + // Pointer to rangeInfo, used later for build + vk::AccelerationStructureBuildRangeInfoKHR* pointerToRangeInfo = &asRangeInfo; + + // Build the TLAS. + + vk::CommandPool commandPool2 = createCommandPool(); + vk::CommandBuffer commandBuffer2 = createAndBeginCommandBuffer(commandPool2); + commandBuffer2.buildAccelerationStructuresKHR(1, &asBuildInfo, &pointerToRangeInfo, m_rtxDispatcher); + submitCommandBuffer(commandPool2, commandBuffer2); + + m_device->destroyBuffer(tlasScratchBuffer.vulkanHandle, nullptr, m_rtxDispatcher); + m_device->freeMemory(tlasScratchBuffer.deviceMemory, nullptr, m_rtxDispatcher); + + m_topLevelAccelerationStructure = { + bufferInstances, + tlasBuffer, + tlasScratchBuffer, + tlas + }; + } + + TopLevelAccelerationStructure ASManager::getTLAS() + { + return m_topLevelAccelerationStructure; + } + + BottomLevelAccelerationStructure ASManager::getBLAS(uint32_t id) + { + return m_bottomLevelAccelerationStructures[id]; + } + + const vk::DispatchLoaderDynamic& ASManager::getDispatcher() { + return m_rtxDispatcher; + } +} \ No newline at end of file diff --git a/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp b/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..42ef7fc03c58a223b510e2a41d710f463dba0c6b --- /dev/null +++ b/projects/rtx_ambient_occlusion/src/RTX/ASManager.hpp @@ -0,0 +1,188 @@ +#pragma once + +#include <vkcv/Core.hpp> + +namespace vkcv::rtx { + + /** + * @brief Used for @#RTXBuffer creation depending on the @#RTXBufferType. + */ + enum class RTXBufferType { + STAGING, + GPU, + ACCELERATION, + SHADER_BINDING, + SCRATCH + }; + + /** + * @brief Used as a container to handle buffer creation and destruction in RTX-specific use cases. + */ + struct RTXBuffer { + RTXBufferType bufferType; + void* data; + vk::DeviceSize deviceSize; + vk::DeviceMemory deviceMemory; + vk::BufferUsageFlags bufferUsageFlagBits; + vk::MemoryPropertyFlags memoryPropertyFlagBits; + vk::Buffer vulkanHandle; + }; + + /** + * @brief Used as a container to handle bottom-level acceleration structure (BLAS) construction and destruction. + */ + struct BottomLevelAccelerationStructure { + RTXBuffer vertexBuffer; + RTXBuffer indexBuffer; + RTXBuffer accelerationBuffer; + vk::AccelerationStructureKHR vulkanHandle; + }; + + /** + * @brief Used as a container to handle top-level acceleration structure (TLAS) construction and destruction. + */ + struct TopLevelAccelerationStructure { + RTXBuffer gpuBufferInstances; + RTXBuffer tlasBuffer; + RTXBuffer tempBuildDataBuffer; // scratch buffer + vk::AccelerationStructureKHR vulkanHandle; + }; + + /** + * @brief A class for managing acceleration structures (bottom, top). + */ + class ASManager { + private: + Core* m_core; + const vk::Device* m_device; + std::vector<BottomLevelAccelerationStructure> m_bottomLevelAccelerationStructures; + TopLevelAccelerationStructure m_topLevelAccelerationStructure; + vk::DispatchLoaderDynamic m_rtxDispatcher; + + /** + * Creates a command pool. + */ + vk::CommandPool createCommandPool(); + + /** + * @brief Takes a @p cmdPool, allocates a command buffer and starts recording it. + * @param cmdPool The command pool. + * @return The allocated command buffer. + */ + vk::CommandBuffer createAndBeginCommandBuffer( vk::CommandPool cmdPool); + + /** + * @brief Ends the @p commandBuffer,submits it and waits. Afterwards frees the @p commandBuffer. + * @param commandPool The command pool. + * @param commandBuffer The command buffer. + */ + void submitCommandBuffer(vk::CommandPool commandPool, vk::CommandBuffer& commandBuffer); + + /** + * @brief Gets the device address of a @p buffer. + * @param buffer The buffer. + * @return The device address of the @p buffer. + */ + vk::DeviceAddress getBufferDeviceAddress(vk::Buffer buffer); + + /** + * @brief Copies @p cpuBuffer data into a @p gpuBuffer. Typical use case is a staging buffer (namely, + * @p cpuBuffer) used to fill a @p gpuBuffer with @p vk::MemoryPropertyFlagBits::eDeviceLocal flag set. + * @p cpuBuffer is destroyed and freed after copying. + * @param cpuBuffer + * @param gpuBuffer + */ + void copyFromCPUToGPU(RTXBuffer &cpuBuffer, RTXBuffer &gpuBuffer); + + public: + + /** + * @brief Constructor of @#ASManager . + * @param core + */ + ASManager(vkcv::Core *core); + + /** + * @brief Default destructor of @#ASManager. + */ + ~ASManager(); + + /** + * @brief Returns a @#RTXBuffer object holding data of type @p T. + * @param data The input data of type @p T. + * @return A @#RTXBuffer object holding @p data of type @p T. + */ + template<class T> + RTXBuffer makeBufferFromData(std::vector<T>& data) { + + // first: Staging Buffer creation + RTXBuffer stagingBuffer; + stagingBuffer.bufferType = RTXBufferType::STAGING; + stagingBuffer.deviceSize = sizeof(T) * data.size(); + stagingBuffer.data = data.data(); + stagingBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eTransferSrc; + stagingBuffer.memoryPropertyFlagBits = vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible; + + createBuffer(stagingBuffer); + + // second: create AS Buffer + RTXBuffer targetBuffer; + targetBuffer.bufferType = RTXBufferType::GPU; + targetBuffer.deviceSize = sizeof(T) * data.size(); + targetBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR + | vk::BufferUsageFlagBits::eTransferDst + | vk::BufferUsageFlagBits::eStorageBuffer + | vk::BufferUsageFlagBits::eShaderDeviceAddress; + targetBuffer.memoryPropertyFlagBits = vk::MemoryPropertyFlagBits::eDeviceLocal; + + createBuffer(targetBuffer); + + // copy from CPU to GPU + copyFromCPUToGPU(stagingBuffer, targetBuffer); + + return targetBuffer; + }; + + /** + * @brief A helper function used by @#ASManager::makeBufferFromData. Creates a fully initialized @#RTXBuffer object + * from partially specified @p buffer. All missing data of @p buffer will be completed by this function. + * @param buffer The partially specified @#RTXBuffer holding that part of information which is required for + * successfully creating a @p vk::Buffer object. + */ + void createBuffer(RTXBuffer& buffer); + + /** + * @brief Build a Bottom Level Acceleration Structure (BLAS) object from given @p vertexBuffer and @p indexBuffer. + * @param[in] vertexBuffer The vertex data. + * @param[in] vertexCount The amount of vertices in @p vertexBuffer. + * @param[in] indexBuffer The index data. + * @param[in] indexCount The amount of indices in @p indexBuffer. + */ + void buildBLAS(RTXBuffer vertexBuffer, uint32_t vertexCount, RTXBuffer indexBuffer, uint32_t indexCount); + + /** + * @brief Build a Top Level Acceleration Structure (TLAS) object from the created + * @#ASManager::m_accelerationStructures objects. + */ + void buildTLAS(); + + /** + * @brief Returns the top-level acceleration structure (TLAS) buffer. + * @return A @#TopLevelAccelerationStructure object holding the TLAS. + */ + TopLevelAccelerationStructure getTLAS(); + + /** + * @brief Returns the bottom-level acceleration structure at @p id. + * @param id The ID used for indexing. + * @return The specified @#BottomLevelAccelerationStructure object. + */ + BottomLevelAccelerationStructure getBLAS(uint32_t id); + + /** + * @brief Returns the dispatcher member variable for access in the @#RTXModule. + * @return The dispatcher member variable. + */ + const vk::DispatchLoaderDynamic& getDispatcher(); + }; +} \ No newline at end of file diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59f3da21409993bf6a460000a49c2ed67cb6d178 --- /dev/null +++ b/projects/rtx_ambient_occlusion/src/RTX/RTX.cpp @@ -0,0 +1,331 @@ +#include "RTX.hpp" + +namespace vkcv::rtx { + + RTXModule::RTXModule(Core* core, ASManager* asManager, std::vector<float>& vertices, + std::vector<uint32_t>& indices, std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles){ + m_core = core; + m_asManager = asManager; + // build acceleration structures BLAS then TLAS --> see ASManager + RTXBuffer vertexBuffer = m_asManager->makeBufferFromData(vertices); + RTXBuffer indexBuffer = m_asManager->makeBufferFromData(indices); + m_asManager->buildBLAS(vertexBuffer, vertices.size(), indexBuffer,indices.size()); + m_asManager->buildTLAS(); + RTXDescriptors(descriptorSetHandles); + } + + + RTXModule::~RTXModule() + { + m_core->getContext().getDevice().destroy(m_pipeline); + m_core->getContext().getDevice().destroy(m_pipelineLayout); + m_core->getContext().getDevice().destroy(m_shaderBindingTableBuffer.vulkanHandle); + m_core->getContext().getDevice().freeMemory(m_shaderBindingTableBuffer.deviceMemory); + } + + void RTXModule::createShaderBindingTable(uint32_t shaderCount) { + vk::PhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingProperties; + + vk::PhysicalDeviceProperties2 physicalProperties; + physicalProperties.pNext = &rayTracingProperties; + + m_core->getContext().getPhysicalDevice().getProperties2(&physicalProperties); + + vk::DeviceSize shaderBindingTableSize = rayTracingProperties.shaderGroupHandleSize * shaderCount; + + + m_shaderBindingTableBuffer.bufferType = RTXBufferType::SHADER_BINDING; + m_shaderBindingTableBuffer.bufferUsageFlagBits = vk::BufferUsageFlagBits::eShaderBindingTableKHR | vk::BufferUsageFlagBits::eShaderDeviceAddressKHR; + m_shaderBindingTableBuffer.memoryPropertyFlagBits = vk::MemoryPropertyFlagBits::eHostVisible; + m_shaderBindingTableBuffer.deviceSize = shaderBindingTableSize; + + m_asManager->createBuffer(m_shaderBindingTableBuffer); + + void* shaderHandleStorage = (void*)malloc(sizeof(uint8_t) * shaderBindingTableSize); + + if (m_core->getContext().getDevice().getRayTracingShaderGroupHandlesKHR(m_pipeline, 0, shaderCount, shaderBindingTableSize, + shaderHandleStorage, m_asManager->getDispatcher()) != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "Could not retrieve shader binding table group handles."); + } + + m_shaderGroupBaseAlignment = rayTracingProperties.shaderGroupBaseAlignment; + uint8_t* mapped = (uint8_t*) m_core->getContext().getDevice().mapMemory(m_shaderBindingTableBuffer.deviceMemory, 0, shaderBindingTableSize); + for (int i = 0; i < shaderCount; i++) { + memcpy(mapped, (uint8_t*)shaderHandleStorage + (i * rayTracingProperties.shaderGroupHandleSize), rayTracingProperties.shaderGroupHandleSize); + mapped += m_shaderGroupBaseAlignment; + } + + m_core->getContext().getDevice().unmapMemory(m_shaderBindingTableBuffer.deviceMemory); + free(shaderHandleStorage); + } + + ShaderBindingTableRegions RTXModule::createRegions() { + // Define offsets for the RTX shaders. RayGen is the first allocated shader. Each following shader is + // shifted by shaderGroupBaseAlignment. + // Offset Calculation: offset = count of previous shaders * m_shaderGroupBaseAlignment + // Regions are hard coded + vk::DeviceSize rayGenOffset = 0; //First Shader group -> offset 0 * m_shaderGroupBaseAlignment =0 + vk::DeviceSize missOffset = m_shaderGroupBaseAlignment;//Second group, offset = 1 * m_shaderGroupBaseAlignment + vk::DeviceSize closestHitOffset = 2 * m_shaderGroupBaseAlignment; //Third group, offset = 2 * m_shaderGroupBaseAlignment + vk::DeviceSize shaderBindingTableSize = m_shaderGroupBaseAlignment * 3; // 3 hardcoded to rtx-shader count + + auto m_rtxDispatcher = vk::DispatchLoaderDynamic((PFN_vkGetInstanceProcAddr)m_core->getContext().getInstance().getProcAddr("vkGetInstanceProcAddr")); + m_rtxDispatcher.init(m_core->getContext().getInstance()); + + + // Create regions for the shader binding table buffer which are used for vk::CommandBuffer::traceRaysKHR + vk::StridedDeviceAddressRegionKHR rgenRegion; + vk::BufferDeviceAddressInfoKHR shaderBindingTableAddressInfo(m_shaderBindingTableBuffer.vulkanHandle); + rgenRegion.deviceAddress = m_core->getContext().getDevice().getBufferAddressKHR(shaderBindingTableAddressInfo, m_rtxDispatcher) + rayGenOffset; + rgenRegion.setStride(shaderBindingTableSize); + rgenRegion.setSize(shaderBindingTableSize); + vk::StridedDeviceAddressRegionKHR rmissRegion; + rmissRegion.deviceAddress = m_core->getContext().getDevice().getBufferAddressKHR(shaderBindingTableAddressInfo, m_rtxDispatcher) + missOffset; + rmissRegion.setStride(shaderBindingTableSize); + rmissRegion.setSize(shaderBindingTableSize); + vk::StridedDeviceAddressRegionKHR rchitRegion; + rchitRegion.deviceAddress = m_core->getContext().getDevice().getBufferAddressKHR(shaderBindingTableAddressInfo, m_rtxDispatcher) + closestHitOffset; + rchitRegion.setStride(shaderBindingTableSize); + rchitRegion.setSize(shaderBindingTableSize); + vk::StridedDeviceAddressRegionKHR rcallRegion = {}; + + return ShaderBindingTableRegions{ rgenRegion, rmissRegion, rchitRegion, rcallRegion }; + } + + + void RTXModule::RTXDescriptors(std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles) + { + //TLAS-Descriptor-Write + TopLevelAccelerationStructure tlas = m_asManager->getTLAS(); + RTXBuffer tlasBuffer = tlas.tlasBuffer; + vk::WriteDescriptorSetAccelerationStructureKHR AccelerationDescriptor = {}; + AccelerationDescriptor.accelerationStructureCount = 1; + const TopLevelAccelerationStructure constTLAS = tlas; + AccelerationDescriptor.pAccelerationStructures = &constTLAS.vulkanHandle; + + vk::WriteDescriptorSet tlasWrite; + tlasWrite.setPNext(&AccelerationDescriptor); + tlasWrite.setDstSet(m_core->getDescriptorSet(descriptorSetHandles[0]).vulkanHandle); + tlasWrite.setDstBinding(1); + tlasWrite.setDstArrayElement(0); + tlasWrite.setDescriptorCount(1); + tlasWrite.setDescriptorType(vk::DescriptorType::eAccelerationStructureKHR); + m_core->getContext().getDevice().updateDescriptorSets(tlasWrite, nullptr); + tlasWrite.setDstBinding(2); + m_core->getContext().getDevice().updateDescriptorSets(tlasWrite, nullptr); + + //INDEX & VERTEX BUFFER + BottomLevelAccelerationStructure blas = m_asManager->getBLAS(0);//HARD CODED + + //VERTEX BUFFER + vk::DescriptorBufferInfo vertexInfo = {}; + vertexInfo.setBuffer(blas.vertexBuffer.vulkanHandle); + vertexInfo.setOffset(0); + vertexInfo.setRange(blas.vertexBuffer.deviceSize); //maybe check if size is correct + + vk::WriteDescriptorSet vertexWrite; + vertexWrite.setDstSet(m_core->getDescriptorSet(descriptorSetHandles[0]).vulkanHandle); + vertexWrite.setDstBinding(3); + vertexWrite.setDescriptorCount(1); + vertexWrite.setDescriptorType(vk::DescriptorType::eStorageBuffer); + vertexWrite.setPBufferInfo(&vertexInfo); + m_core->getContext().getDevice().updateDescriptorSets(vertexWrite, nullptr); + + //INDEXBUFFER + vk::DescriptorBufferInfo indexInfo = {}; + indexInfo.setBuffer(blas.indexBuffer.vulkanHandle); + indexInfo.setOffset(0); + indexInfo.setRange(blas.indexBuffer.deviceSize); //maybe check if size is correct + + vk::WriteDescriptorSet indexWrite; + indexWrite.setDstSet(m_core->getDescriptorSet(descriptorSetHandles[0]).vulkanHandle); + indexWrite.setDstBinding(4); + indexWrite.setDescriptorCount(1); + indexWrite.setDescriptorType(vk::DescriptorType::eStorageBuffer); + indexWrite.setPBufferInfo(&indexInfo); + m_core->getContext().getDevice().updateDescriptorSets(indexWrite, nullptr); + } + + void RTXModule::createRTXPipelineAndLayout(uint32_t pushConstantSize, std::vector<DescriptorSetLayoutHandle> descriptorSetLayouts, ShaderProgram &rtxShader) { + // -- process vkcv::ShaderProgram into vk::ShaderModule + std::vector<char> rayGenShaderCode = rtxShader.getShader(ShaderStage::RAY_GEN).shaderCode; + + vk::ShaderModuleCreateInfo rayGenShaderModuleInfo( + vk::ShaderModuleCreateFlags(), // vk::ShaderModuleCreateFlags flags_, + rayGenShaderCode.size(), // size_t codeSize + (const uint32_t*)rayGenShaderCode.data() // const uint32_t* pCode + ); + vk::ShaderModule rayGenShaderModule = m_core->getContext().getDevice().createShaderModule(rayGenShaderModuleInfo); + if (!rayGenShaderModule) { + vkcv_log(LogLevel::ERROR, "The Ray Generation Shader Module could not be created!"); + } + + std::vector<char> rayMissShaderCode = rtxShader.getShader(ShaderStage::RAY_MISS).shaderCode; + vk::ShaderModuleCreateInfo rayMissShaderModuleInfo( + vk::ShaderModuleCreateFlags(), // vk::ShaderModuleCreateFlags flags_, + rayMissShaderCode.size(), //size_t codeSize + (const uint32_t*)rayMissShaderCode.data() // const uint32_t* pCode + ); + + vk::ShaderModule rayMissShaderModule = m_core->getContext().getDevice().createShaderModule(rayMissShaderModuleInfo); + if (!rayMissShaderModule) { + vkcv_log(LogLevel::ERROR, "The Ray Miss Shader Module could not be created!"); + } + + std::vector<char> rayClosestHitShaderCode = rtxShader.getShader(ShaderStage::RAY_CLOSEST_HIT).shaderCode; + vk::ShaderModuleCreateInfo rayClosestHitShaderModuleInfo( + vk::ShaderModuleCreateFlags(), // vk::ShaderModuleCreateFlags flags_, + rayClosestHitShaderCode.size(), //size_t codeSize + (const uint32_t*)rayClosestHitShaderCode.data() // const uint32_t* pCode_ + ); + vk::ShaderModule rayClosestHitShaderModule = m_core->getContext().getDevice().createShaderModule(rayClosestHitShaderModuleInfo); + if (!rayClosestHitShaderModule) { + vkcv_log(LogLevel::ERROR, "The Ray Closest Hit Shader Module could not be created!"); + } + + // -- PipelineShaderStages + + // ray generation + vk::PipelineShaderStageCreateInfo rayGenShaderStageInfo( + vk::PipelineShaderStageCreateFlags(), // vk::PipelineShaderStageCreateFlags flags_ = {} + vk::ShaderStageFlagBits::eRaygenKHR, // vk::ShaderStageFlagBits stage_ = vk::ShaderStageFlagBits::eVertex, + rayGenShaderModule, // vk::ShaderModule module_ = {}, + "main" // const char* pName_ = {}, + ); + + // ray miss + vk::PipelineShaderStageCreateInfo rayMissShaderStageInfo( + vk::PipelineShaderStageCreateFlags(), // vk::PipelineShaderStageCreateFlags flags_ = {} + vk::ShaderStageFlagBits::eMissKHR, // vk::ShaderStageFlagBits stage_ = vk::ShaderStageFlagBits::eVertex, + rayMissShaderModule, // vk::ShaderModule module_ = {}, + "main" // const char* pName_ = {}, + ); + + // ray closest hit + vk::PipelineShaderStageCreateInfo rayClosestHitShaderStageInfo( + vk::PipelineShaderStageCreateFlags(), // vk::PipelineShaderStageCreateFlags flags_ = {} + vk::ShaderStageFlagBits::eClosestHitKHR, // vk::ShaderStageFlagBits stage_ = vk::ShaderStageFlagBits::eVertex, + rayClosestHitShaderModule, // vk::ShaderModule module_ = {}, + "main" // const char* pName_ = {}, + ); + + std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { // HARD CODED. TODO: Support more shader stages. + rayGenShaderStageInfo, rayMissShaderStageInfo, rayClosestHitShaderStageInfo + }; + + // -- PipelineLayouts + + std::vector<vk::RayTracingShaderGroupCreateInfoKHR> shaderGroups(shaderStages.size()); + // Ray Gen + shaderGroups[0] = vk::RayTracingShaderGroupCreateInfoKHR( + vk::RayTracingShaderGroupTypeKHR::eGeneral, // vk::RayTracingShaderGroupTypeKHR type_ = vk::RayTracingShaderGroupTypeKHR::eGeneral + 0, // uint32_t generalShader_ = {} + VK_SHADER_UNUSED_KHR, // uint32_t closestHitShader_ = {} + VK_SHADER_UNUSED_KHR, // uint32_t anyHitShader_ = {} + VK_SHADER_UNUSED_KHR, // uint32_t intersectionShader_ = {} + nullptr // const void* pShaderGroupCaptureReplayHandle_ = {} + ); + // Ray Miss + shaderGroups[1] = vk::RayTracingShaderGroupCreateInfoKHR( + vk::RayTracingShaderGroupTypeKHR::eGeneral, // vk::RayTracingShaderGroupTypeKHR type_ = vk::RayTracingShaderGroupTypeKHR::eGeneral + 1, // uint32_t generalShader_ = {} + VK_SHADER_UNUSED_KHR, // uint32_t closestHitShader_ = {} + VK_SHADER_UNUSED_KHR, // uint32_t anyHitShader_ = {} + VK_SHADER_UNUSED_KHR, // uint32_t intersectionShader_ = {} + nullptr // const void* pShaderGroupCaptureReplayHandle_ = {} + ); + // Ray Closest Hit + shaderGroups[2] = vk::RayTracingShaderGroupCreateInfoKHR( + vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup, // vk::RayTracingShaderGroupTypeKHR type_ = vk::RayTracingShaderGroupTypeKHR::eGeneral + VK_SHADER_UNUSED_KHR, // uint32_t generalShader_ = {} + 2, // uint32_t closestHitShader_ = {} + VK_SHADER_UNUSED_KHR, // uint32_t anyHitShader_ = {} + VK_SHADER_UNUSED_KHR, // uint32_t intersectionShader_ = {} + nullptr // const void* pShaderGroupCaptureReplayHandle_ = {} + ); + + std::vector<vk::DescriptorSetLayout> descriptorSetLayoutsVulkan; + for (size_t i=0; i<descriptorSetLayouts.size(); i++) { + descriptorSetLayoutsVulkan.push_back(m_core->getDescriptorSetLayout(descriptorSetLayouts[i]).vulkanHandle); + } + + vk::PushConstantRange pushConstant( + vk::ShaderStageFlagBits::eRaygenKHR | vk::ShaderStageFlagBits::eClosestHitKHR | vk::ShaderStageFlagBits::eMissKHR, // vk::ShaderStageFlags stageFlags_ = {}, + 0, // uint32_t offset_ = {}, + pushConstantSize // uint32_t size_ = {} + ); + + vk::PipelineLayoutCreateInfo rtxPipelineLayoutCreateInfo( + vk::PipelineLayoutCreateFlags(), // vk::PipelineLayoutCreateFlags flags_ = {} + (uint32_t) descriptorSetLayoutsVulkan.size(), // uint32_t setLayoutCount_ = {} HARD CODED (2) + descriptorSetLayoutsVulkan.data(), // const vk::DescriptorSetLayout* pSetLayouts_ = {} + 1, // 0, // uint32_t pushConstantRangeCount_ = {} + &pushConstant // nullptr // const vk::PushConstantRange* pPushConstantRanges_ = {} + ); + + m_pipelineLayout = m_core->getContext().getDevice().createPipelineLayout(rtxPipelineLayoutCreateInfo); + if (!m_pipelineLayout) { + vkcv_log(LogLevel::ERROR, "The RTX Pipeline Layout could not be created!"); + } + + vk::PipelineLibraryCreateInfoKHR rtxPipelineLibraryCreateInfo( + 0, // uint32_t libraryCount_ = {} + nullptr // const vk::Pipeline* pLibraries_ = {} + ); + + // -- RTX Pipeline + + vk::RayTracingPipelineCreateInfoKHR rtxPipelineInfo( + vk::PipelineCreateFlags(), // vk::PipelineCreateFlags flags_ = {} + (uint32_t) shaderStages.size(), // uint32_t stageCount_ = {} + shaderStages.data(), // const vk::PipelineShaderStageCreateInfo* pStages_ = {} + (uint32_t) shaderGroups.size(), // uint32_t groupCount_ = {} + shaderGroups.data(), // const vk::RayTracingShaderGroupCreateInfoKHR* pGroups_ = {} + 16, // uint32_t maxPipelineRayRecursionDepth_ = {} + &rtxPipelineLibraryCreateInfo, // const vk::PipelineLibraryCreateInfoKHR* pLibraryInfo_ = {} + nullptr, // const vk::RayTracingPipelineInterfaceCreateInfoKHR* pLibraryInterface_ = {} + nullptr, // const vk::PipelineDynamicStateCreateInfo* pDynamicState_ = {} + m_pipelineLayout // vk::PipelineLayout layout_ = {} + ); + + auto pipelineResult = m_core->getContext().getDevice().createRayTracingPipelineKHR( + vk::DeferredOperationKHR(), + vk::PipelineCache(), + rtxPipelineInfo, + nullptr, + m_asManager->getDispatcher() + ); + + if (pipelineResult.result != vk::Result::eSuccess) { + vkcv_log(LogLevel::ERROR, "The RTX Pipeline could not be created!"); + } + + m_pipeline = pipelineResult.value; + + m_core->getContext().getDevice().destroy(rayGenShaderModule); + m_core->getContext().getDevice().destroy(rayMissShaderModule); + m_core->getContext().getDevice().destroy(rayClosestHitShaderModule); + + // TODO: add possibility of more than one shader per stage + createShaderBindingTable(shaderStages.size()); + } + + vk::Pipeline RTXModule::getPipeline() { + return m_pipeline; + } + + vk::Buffer RTXModule::getShaderBindingTableBuffer() + { + return m_shaderBindingTableBuffer.vulkanHandle; + } + + vk::DeviceSize RTXModule::getShaderGroupBaseAlignment() + { + return m_shaderGroupBaseAlignment; + } + + vk::PipelineLayout RTXModule::getPipelineLayout() { + return m_pipelineLayout; + } + +} \ No newline at end of file diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp b/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ece4ac8e6707039ab3fe166750140a8040aed924 --- /dev/null +++ b/projects/rtx_ambient_occlusion/src/RTX/RTX.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include <vector> +#include "vulkan/vulkan.hpp" +#include <vkcv/Core.hpp> +#include "ASManager.hpp" + +namespace vkcv::rtx { + + //struct that holds all shader binding table regions + struct ShaderBindingTableRegions { + vk::StridedDeviceAddressRegionKHR rgenRegion; + vk::StridedDeviceAddressRegionKHR rmissRegion; + vk::StridedDeviceAddressRegionKHR rchitRegion; + vk::StridedDeviceAddressRegionKHR rcallRegion; + }; + + class RTXModule { + private: + + Core* m_core; + ASManager* m_asManager; + vk::Pipeline m_pipeline; + vk::PipelineLayout m_pipelineLayout; + RTXBuffer m_shaderBindingTableBuffer; + vk::DeviceSize m_shaderGroupBaseAlignment; + + public: + + /** + * @brief Initializes the @#RTXModule with scene data. + * @param core The reference to the @#Core. + * @param asManager The reference to the @#ASManager. + * @param vertices The vertex data of the scene. + * @param indices The index data of the scene. + * @param descriptorSetHandles The descriptor set handles for RTX. + */ + RTXModule(Core* core, ASManager* asManager, std::vector<float>& vertices, + std::vector<uint32_t>& indices, std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles); + + /** + * @brief Default #RTXModule destructor. + */ + ~RTXModule(); + + /** + * @brief Returns the RTX pipeline. + * @return The RTX pipeline. + */ + vk::Pipeline getPipeline(); + + /** + * @brief Returns the shader binding table buffer. + * @return The shader binding table buffer. + */ + vk::Buffer getShaderBindingTableBuffer(); + + /** + * @brief Returns the shader group base alignment for partitioning the shader binding table buffer. + * @return The shader group base alignment. + */ + vk::DeviceSize getShaderGroupBaseAlignment(); + + /** + * @brief Returns the RTX pipeline layout. + * @return The RTX pipeline layout. + */ + vk::PipelineLayout getPipelineLayout(); + + /** + * @brief Sets the shader group base alignment and creates the shader binding table by allocating a shader + * binding table buffer. The allocation depends on @p shaderCount and the shader group base alignment. + * @param shaderCount The amount of shaders to be used for RTX. + */ + void createShaderBindingTable(uint32_t shaderCount); + + /** + * @brief Divides the shader binding table into regions for each shader type + * (ray generation, ray miss, ray closest hit, callable) and returns them as a struct. + * @return The struct holding all four regions of type vk::StridedDeviceAddressRegionKHR. + */ + ShaderBindingTableRegions createRegions(); + + /** + * @brief Creates Descriptor-Writes for RTX + * @param descriptorSetHandles The descriptorSetHandles for RTX. + */ + void RTXDescriptors(std::vector<vkcv::DescriptorSetHandle>& descriptorSetHandles); + + /** + * @brief Creates the RTX pipeline and the RTX pipeline layout. Currently, only RayGen, RayClosestHit and + * RayMiss are supported. + * @param pushConstantSize The size of the push constant used in the RTX shaders. + * @param descriptorSetLayouts The descriptor set layout handles. + * @param rtxShader The RTX shader program. + */ + void createRTXPipelineAndLayout(uint32_t pushConstantSize, std::vector<DescriptorSetLayoutHandle> descriptorSetLayouts, ShaderProgram &rtxShader); + }; + +} diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTXExtensions.cpp b/projects/rtx_ambient_occlusion/src/RTX/RTXExtensions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..133bd8b888f62a56a35c997d2ea75374fbf203a7 --- /dev/null +++ b/projects/rtx_ambient_occlusion/src/RTX/RTXExtensions.cpp @@ -0,0 +1,129 @@ +#include "RTXExtensions.hpp" + +namespace vkcv::rtx{ + +RTXExtensions::RTXExtensions() +{ + + // prepare needed raytracing extensions + m_instanceExtensions = { + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME + }; + m_deviceExtensions = { + VK_KHR_MAINTENANCE3_EXTENSION_NAME, + VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, + VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, + VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, + VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, + VK_KHR_SPIRV_1_4_EXTENSION_NAME, + VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, + VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME + }; + + // get all features required by the device extensions + for (auto deviceExtension : m_deviceExtensions) { + m_features.requireExtension(deviceExtension); + } + + /* FIXME: We must disable features that will be mentioned as "not supported" by the FeatureManager. If every unsupported feature is disabled, this should work. + * Maybe we find a better workaround... + */ + m_features.requireFeature<vk::PhysicalDeviceVulkan12Features>( + [](vk::PhysicalDeviceVulkan12Features& features) { + features.setSamplerMirrorClampToEdge(true); + features.setDrawIndirectCount(true); + features.setStorageBuffer8BitAccess(true); + features.setUniformAndStorageBuffer8BitAccess(true); + features.setStoragePushConstant8(true); + features.setShaderBufferInt64Atomics(true); + features.setShaderSharedInt64Atomics(true); + features.setShaderFloat16(true); + features.setShaderInt8(true); + features.setDescriptorIndexing(true); + features.setShaderInputAttachmentArrayDynamicIndexing(true); + features.setShaderUniformTexelBufferArrayDynamicIndexing(true); + features.setShaderStorageTexelBufferArrayDynamicIndexing(true); + features.setShaderUniformBufferArrayNonUniformIndexing(true); + features.setShaderSampledImageArrayNonUniformIndexing(true); + features.setShaderStorageBufferArrayNonUniformIndexing(true); + features.setShaderStorageImageArrayNonUniformIndexing(true); + features.setShaderInputAttachmentArrayNonUniformIndexing(true); + features.setShaderUniformTexelBufferArrayNonUniformIndexing(true); + features.setShaderStorageTexelBufferArrayNonUniformIndexing(true); + features.setDescriptorBindingUniformBufferUpdateAfterBind(true); + features.setDescriptorBindingSampledImageUpdateAfterBind(true); + features.setDescriptorBindingStorageImageUpdateAfterBind(true); + features.setDescriptorBindingStorageBufferUpdateAfterBind(true); + features.setDescriptorBindingUniformTexelBufferUpdateAfterBind(true); + features.setDescriptorBindingStorageTexelBufferUpdateAfterBind(true); + features.setDescriptorBindingUpdateUnusedWhilePending(true); + features.setDescriptorBindingPartiallyBound(true); + features.setDescriptorBindingVariableDescriptorCount(true); + features.setRuntimeDescriptorArray(true); + features.setSamplerFilterMinmax(true); + features.setScalarBlockLayout(true); + features.setImagelessFramebuffer(true); + features.setUniformBufferStandardLayout(true); + features.setShaderSubgroupExtendedTypes(true); + features.setSeparateDepthStencilLayouts(true); + features.setHostQueryReset(true); + features.setTimelineSemaphore(true); + features.setBufferDeviceAddress(true); + features.setBufferDeviceAddressCaptureReplay(true); + features.setBufferDeviceAddressMultiDevice(true); + features.setVulkanMemoryModel(true); + features.setVulkanMemoryModelDeviceScope(true); + features.setVulkanMemoryModelAvailabilityVisibilityChains(true); + features.setShaderOutputViewportIndex(true); + features.setShaderOutputLayer(true); + features.setSubgroupBroadcastDynamicId(true); + }); + m_features.requireFeature<vk::PhysicalDeviceVulkan11Features>( + [](vk::PhysicalDeviceVulkan11Features& features) { + features.setMultiview(true); + features.setMultiviewGeometryShader(true); + features.setMultiviewTessellationShader(true); + // features.setProtectedMemory(true); // not supported + features.setSamplerYcbcrConversion(true); + features.setShaderDrawParameters(true); + features.setStorageBuffer16BitAccess(true); + // features.setStorageInputOutput16(true); // not supported + features.setStoragePushConstant16(true); + features.setUniformAndStorageBuffer16BitAccess(true); + features.setVariablePointers(true); + features.setVariablePointersStorageBuffer(true); + }); + m_features.requireFeature<vk::PhysicalDeviceAccelerationStructureFeaturesKHR>( + [](vk::PhysicalDeviceAccelerationStructureFeaturesKHR& features) { + features.setAccelerationStructure(true); + features.setAccelerationStructureCaptureReplay(true); + // features.setAccelerationStructureIndirectBuild(true); // not supported + // features.setAccelerationStructureHostCommands(true); // not supported + features.setDescriptorBindingAccelerationStructureUpdateAfterBind(true); + }); + m_features.requireExtensionFeature<vk::PhysicalDeviceRayTracingPipelineFeaturesKHR>( + VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, [](vk::PhysicalDeviceRayTracingPipelineFeaturesKHR& features) { + features.setRayTracingPipeline(true); + // features.setRayTracingPipelineShaderGroupHandleCaptureReplay(true); // not supported + // features.setRayTracingPipelineShaderGroupHandleCaptureReplayMixed(true); // not supported + features.setRayTracingPipelineTraceRaysIndirect(true); + features.setRayTraversalPrimitiveCulling(true); + }); +} + +std::vector<const char*> RTXExtensions::getInstanceExtensions() +{ + return m_instanceExtensions; +} + +std::vector<const char*> RTXExtensions::getDeviceExtensions() +{ + return m_deviceExtensions; +} + +vkcv::Features RTXExtensions::getFeatures() +{ + return m_features; +} + +} \ No newline at end of file diff --git a/projects/rtx_ambient_occlusion/src/RTX/RTXExtensions.hpp b/projects/rtx_ambient_occlusion/src/RTX/RTXExtensions.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5ad5ae0769b75aa18672648b5eb3cb598b6f8d47 --- /dev/null +++ b/projects/rtx_ambient_occlusion/src/RTX/RTXExtensions.hpp @@ -0,0 +1,36 @@ +#pragma once +#include <vector> +#include <vkcv/Core.hpp> + +namespace vkcv::rtx{ + +class RTXExtensions { +private: + std::vector<const char*> m_instanceExtensions; // the instance extensions needed for using RTX + std::vector<const char*> m_deviceExtensions; // the device extensions needed for using RTX + vkcv::Features m_features; // the features needed to be enabled for using RTX +public: + + RTXExtensions(); + ~RTXExtensions()=default; + /** + * @brief Returns the raytracing instance extensions. + * @return The raytracing instance extensions. + */ + std::vector<const char*> getInstanceExtensions(); + + /** + * @brief Returns the raytracing device extensions. + * @return The raytracing device extensions. + */ + std::vector<const char*> getDeviceExtensions(); + + /** + * @brief Returns the raytracing features. + * @return The raytracing features. + */ + vkcv::Features getFeatures(); + + +}; +} \ No newline at end of file diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bac1fe367031e43cf2fc53d4be23c208f4fb682d --- /dev/null +++ b/projects/rtx_ambient_occlusion/src/main.cpp @@ -0,0 +1,161 @@ +#include <vkcv/Core.hpp> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> +#include <vkcv/shader/GLSLCompiler.hpp> +#include "RTX/RTX.hpp" +#include "RTX/RTXExtensions.hpp" +#include "teapot.hpp" + +/** + * Note: This project is based on the following tutorial https://github.com/Apress/Ray-Tracing-Gems-II/tree/main/Chapter_16. + */ + +int main(int argc, const char** argv) { + const char* applicationName = "RTX Ambient Occlusion"; + + uint32_t windowWidth = 800; + uint32_t windowHeight = 600; + + // prepare raytracing extensions. IMPORTANT: configure compiler to build in 64 bit mode + vkcv::rtx::RTXExtensions rtxExtensions; + std::vector<const char*> raytracingInstanceExtensions = rtxExtensions.getInstanceExtensions(); + + std::vector<const char*> instanceExtensions = {}; // add some more instance extensions, if needed + instanceExtensions.insert(instanceExtensions.end(), raytracingInstanceExtensions.begin(), raytracingInstanceExtensions.end()); // merge together all instance extensions + + vkcv::Features features = rtxExtensions.getFeatures(); // all features required by the RTX device extensions + features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + vkcv::Core core = vkcv::Core::create( + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer }, + features, + instanceExtensions + ); + + vkcv::rtx::ASManager asManager(&core); + + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + + vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); + uint32_t camIndex = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + cameraManager.getCamera(camIndex).setNearFar(0.1f, 30.0f); + + // get Teapot vertices and indices + Teapot teapot; + std::vector<float> vertices = teapot.getVertices(); + std::vector<uint32_t> indices = teapot.getIndices(); + + vkcv::shader::GLSLCompiler compiler; + + vkcv::ShaderProgram rtxShaderProgram; + compiler.compile(vkcv::ShaderStage::RAY_GEN, std::filesystem::path("resources/shaders/ambientOcclusion.rgen"), + [&rtxShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + rtxShaderProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::RAY_CLOSEST_HIT, std::filesystem::path("resources/shaders/ambientOcclusion.rchit"), + [&rtxShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + rtxShaderProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::RAY_MISS, std::filesystem::path("resources/shaders/ambientOcclusion.rmiss"), + [&rtxShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + rtxShaderProgram.addShader(shaderStage, path); + }); + + std::vector<vkcv::DescriptorSetHandle> descriptorSetHandles; + std::vector<vkcv::DescriptorSetLayoutHandle> descriptorSetLayoutHandles; + + vkcv::DescriptorSetLayoutHandle rtxShaderDescriptorSetLayout = core.createDescriptorSetLayout(rtxShaderProgram.getReflectedDescriptors().at(0)); + vkcv::DescriptorSetHandle rtxShaderDescriptorSet = core.createDescriptorSet(rtxShaderDescriptorSetLayout); + descriptorSetHandles.push_back(rtxShaderDescriptorSet); + descriptorSetLayoutHandles.push_back(rtxShaderDescriptorSetLayout); + + // init RTXModule + vkcv::rtx::RTXModule rtxModule(&core, &asManager, vertices, indices,descriptorSetHandles); + + struct RaytracingPushConstantData { + glm::vec4 camera_position; // as origin for ray generation + glm::vec4 camera_right; // for computing ray direction + glm::vec4 camera_up; // for computing ray direction + glm::vec4 camera_forward; // for computing ray direction + }; + + uint32_t pushConstantSize = sizeof(RaytracingPushConstantData); + + rtxModule.createRTXPipelineAndLayout(pushConstantSize, descriptorSetLayoutHandles, rtxShaderProgram); + + vk::Pipeline rtxPipeline = rtxModule.getPipeline(); + vk::PipelineLayout rtxPipelineLayout = rtxModule.getPipelineLayout(); + + vkcv::rtx::ShaderBindingTableRegions rtxRegions = rtxModule.createRegions(); + + vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle(); + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + vkcv::DescriptorWrites rtxWrites; + + auto start = std::chrono::system_clock::now(); + while (vkcv::Window::hasOpenWindow()) { + vkcv::Window::pollEvents(); + + if(core.getWindow(windowHandle).getHeight() == 0 || core.getWindow(windowHandle).getWidth() == 0) + continue; + + uint32_t swapchainWidth, swapchainHeight; + if (!core.beginFrame(swapchainWidth, swapchainHeight,windowHandle)) { + continue; + } + + if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { + depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); + + windowWidth = swapchainWidth; + windowHeight = swapchainHeight; + } + + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + + start = end; + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + + const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; + + RaytracingPushConstantData raytracingPushData; + raytracingPushData.camera_position = glm::vec4(cameraManager.getActiveCamera().getPosition(),0); + raytracingPushData.camera_right = glm::vec4(glm::cross(cameraManager.getActiveCamera().getUp(), cameraManager.getActiveCamera().getFront()), 0); + raytracingPushData.camera_up = glm::vec4(cameraManager.getActiveCamera().getUp(),0); + raytracingPushData.camera_forward = glm::vec4(cameraManager.getActiveCamera().getFront(),0); + + vkcv::PushConstants pushConstantsRTX(sizeof(RaytracingPushConstantData)); + pushConstantsRTX.appendDrawcall(raytracingPushData); + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + rtxWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(0, swapchainInput) }; + core.writeDescriptorSet(rtxShaderDescriptorSet, rtxWrites); + + core.prepareImageForStorage(cmdStream, swapchainInput); + + core.recordRayGenerationToCmdStream( + cmdStream, + rtxPipeline, + rtxPipelineLayout, + rtxRegions.rgenRegion, + rtxRegions.rmissRegion, + rtxRegions.rchitRegion, + rtxRegions.rcallRegion, + { vkcv::DescriptorSetUsage(0, core.getDescriptorSet(rtxShaderDescriptorSet).vulkanHandle)}, + pushConstantsRTX, + windowHandle); + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + core.endFrame(windowHandle); + } + + return 0; +} diff --git a/projects/rtx_ambient_occlusion/src/teapot.hpp b/projects/rtx_ambient_occlusion/src/teapot.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1f35400a313b230f92098fa2ef59cc3c8f3a30df --- /dev/null +++ b/projects/rtx_ambient_occlusion/src/teapot.hpp @@ -0,0 +1,7114 @@ +#pragma once +#include <vector> + +class Teapot { +public: + /** + * @brief The default constructor. + */ + Teapot() = default; + + /** + * default destructor + */ + ~Teapot() = default; + + /** + * @brief Returns the vertex data of the teapot. + * @return The vertex data of the teapot. + */ + std::vector<float> getVertices() { + return m_teapotVertices; + } + + /** + * @brief Returns the index data of the teapot. + * @return The index data of the teapot. + */ + std::vector<uint32_t> getIndices() { + return m_teapotIndices; + } + +private: + + std::vector<float> m_teapotVertices = + { + 0.69999999f, 0.45000005f, 0.00000001f, + 0.69098389f, 0.44999996f, 0.11485600f, + 0.66483200f, 0.45000011f, 0.22332802f, + 0.62288797f, 0.45000002f, 0.32407200f, + 0.56649601f, 0.45000008f, 0.41574404f, + 0.49699998f, 0.45000005f, 0.49700001f, + 0.41574395f, 0.45000005f, 0.56649601f, + 0.32407200f, 0.45000008f, 0.62288797f, + 0.22332799f, 0.45000005f, 0.66483200f, + 0.11485596f, 0.45000005f, 0.69098401f, + 0.00000000f, 0.45000005f, 0.69999999f, + 0.69296241f, 0.46771872f, 0.00000001f, + 0.68403697f, 0.46771869f, 0.11370128f, + 0.65814799f, 0.46771878f, 0.22108276f, + 0.61662567f, 0.46771872f, 0.32081389f, + 0.56080067f, 0.46771872f, 0.41156429f, + 0.49200332f, 0.46771872f, 0.49200332f, + 0.41156423f, 0.46771872f, 0.56080067f, + 0.32081389f, 0.46771872f, 0.61662567f, + 0.22108275f, 0.46771872f, 0.65814799f, + 0.11370124f, 0.46771872f, 0.68403703f, + 0.00000000f, 0.46771872f, 0.69296241f, + 0.69020003f, 0.48150003f, 0.00000001f, + 0.68131018f, 0.48149997f, 0.11324803f, + 0.65552443f, 0.48150006f, 0.22020143f, + 0.61416763f, 0.48150000f, 0.31953502f, + 0.55856514f, 0.48150009f, 0.40992361f, + 0.49004203f, 0.48150003f, 0.49004203f, + 0.40992361f, 0.48150006f, 0.55856514f, + 0.31953505f, 0.48150003f, 0.61416763f, + 0.22020143f, 0.48150003f, 0.65552437f, + 0.11324799f, 0.48150003f, 0.68131030f, + 0.00000000f, 0.48150003f, 0.69020003f, + 0.69111252f, 0.49134374f, 0.00000001f, + 0.68221092f, 0.49134374f, 0.11339775f, + 0.65639102f, 0.49134377f, 0.22049254f, + 0.61497957f, 0.49134377f, 0.31995746f, + 0.55930358f, 0.49134377f, 0.41046557f, + 0.49068987f, 0.49134374f, 0.49068987f, + 0.41046554f, 0.49134374f, 0.55930358f, + 0.31995746f, 0.49134374f, 0.61497957f, + 0.22049253f, 0.49134377f, 0.65639102f, + 0.11339770f, 0.49134374f, 0.68221098f, + 0.00000000f, 0.49134374f, 0.69111252f, + 0.69510001f, 0.49725008f, 0.00000001f, + 0.68614709f, 0.49725005f, 0.11405202f, + 0.66017824f, 0.49725014f, 0.22176473f, + 0.61852777f, 0.49725008f, 0.32180351f, + 0.56253058f, 0.49725008f, 0.41283381f, + 0.49352103f, 0.49725008f, 0.49352100f, + 0.41283381f, 0.49725008f, 0.56253058f, + 0.32180351f, 0.49725008f, 0.61852777f, + 0.22176471f, 0.49725008f, 0.66017818f, + 0.11405198f, 0.49725008f, 0.68614715f, + 0.00000000f, 0.49725008f, 0.69510001f, + 0.70156252f, 0.49921876f, 0.00000001f, + 0.69252634f, 0.49921870f, 0.11511238f, + 0.66631603f, 0.49921876f, 0.22382653f, + 0.62427837f, 0.49921873f, 0.32479537f, + 0.56776059f, 0.49921879f, 0.41667202f, + 0.49810940f, 0.49921876f, 0.49810940f, + 0.41667199f, 0.49921879f, 0.56776053f, + 0.32479542f, 0.49921876f, 0.62427843f, + 0.22382650f, 0.49921876f, 0.66631603f, + 0.11511234f, 0.49921876f, 0.69252640f, + 0.00000000f, 0.49921876f, 0.70156252f, + 0.70989996f, 0.49725002f, 0.00000001f, + 0.70075637f, 0.49724996f, 0.11648039f, + 0.67423457f, 0.49725008f, 0.22648652f, + 0.63169742f, 0.49724999f, 0.32865530f, + 0.57450789f, 0.49725002f, 0.42162383f, + 0.50402898f, 0.49725002f, 0.50402898f, + 0.42162377f, 0.49725002f, 0.57450783f, + 0.32865530f, 0.49725002f, 0.63169742f, + 0.22648649f, 0.49725005f, 0.67423463f, + 0.11648035f, 0.49725002f, 0.70075643f, + 0.00000000f, 0.49725002f, 0.70989996f, + 0.71951252f, 0.49134377f, 0.00000001f, + 0.71024513f, 0.49134374f, 0.11805762f, + 0.68336421f, 0.49134380f, 0.22955328f, + 0.64025098f, 0.49134377f, 0.33310553f, + 0.58228713f, 0.49134383f, 0.42733288f, + 0.51085389f, 0.49134377f, 0.51085389f, + 0.42733288f, 0.49134377f, 0.58228713f, + 0.33310553f, 0.49134377f, 0.64025104f, + 0.22955328f, 0.49134380f, 0.68336427f, + 0.11805756f, 0.49134377f, 0.71024519f, + 0.00000000f, 0.49134377f, 0.71951252f, + 0.72979999f, 0.48150003f, 0.00000001f, + 0.72040009f, 0.48149997f, 0.11974559f, + 0.69313490f, 0.48150006f, 0.23283541f, + 0.64940518f, 0.48150000f, 0.33786824f, + 0.59061253f, 0.48150009f, 0.43344283f, + 0.51815796f, 0.48150003f, 0.51815796f, + 0.43344280f, 0.48150006f, 0.59061259f, + 0.33786821f, 0.48150003f, 0.64940524f, + 0.23283540f, 0.48150003f, 0.69313484f, + 0.11974555f, 0.48150003f, 0.72040015f, + 0.00000000f, 0.48150003f, 0.72979999f, + 0.74016249f, 0.46771878f, 0.00000001f, + 0.73062909f, 0.46771872f, 0.12144586f, + 0.70297670f, 0.46771881f, 0.23614147f, + 0.65862614f, 0.46771878f, 0.34266564f, + 0.59899879f, 0.46771878f, 0.43959734f, + 0.52551538f, 0.46771878f, 0.52551538f, + 0.43959731f, 0.46771878f, 0.59899873f, + 0.34266564f, 0.46771878f, 0.65862620f, + 0.23614144f, 0.46771878f, 0.70297670f, + 0.12144582f, 0.46771878f, 0.73062921f, + 0.00000000f, 0.46771878f, 0.74016249f, + 0.75000000f, 0.45000005f, 0.00000001f, + 0.74033999f, 0.44999996f, 0.12306000f, + 0.71232003f, 0.45000011f, 0.23928000f, + 0.66737998f, 0.45000002f, 0.34721997f, + 0.60696000f, 0.45000008f, 0.44544002f, + 0.53250003f, 0.45000005f, 0.53250003f, + 0.44543999f, 0.45000005f, 0.60696000f, + 0.34722000f, 0.45000008f, 0.66738003f, + 0.23927999f, 0.45000005f, 0.71231997f, + 0.12305996f, 0.45000005f, 0.74033999f, + 0.00000000f, 0.45000005f, 0.75000000f, + 0.00000000f, 0.45000005f, -0.69999999f, + 0.11485599f, 0.44999996f, -0.69098389f, + 0.22332802f, 0.45000011f, -0.66483200f, + 0.32407200f, 0.45000002f, -0.62288797f, + 0.41574404f, 0.45000008f, -0.56649601f, + 0.49700001f, 0.45000005f, -0.49699998f, + 0.56649601f, 0.45000005f, -0.41574395f, + 0.62288797f, 0.45000008f, -0.32407200f, + 0.66483200f, 0.45000005f, -0.22332799f, + 0.69098401f, 0.45000005f, -0.11485595f, + 0.69999999f, 0.45000005f, 0.00000001f, + 0.00000000f, 0.46771872f, -0.69296241f, + 0.11370128f, 0.46771869f, -0.68403697f, + 0.22108276f, 0.46771878f, -0.65814799f, + 0.32081389f, 0.46771872f, -0.61662567f, + 0.41156429f, 0.46771872f, -0.56080067f, + 0.49200332f, 0.46771872f, -0.49200332f, + 0.56080067f, 0.46771872f, -0.41156423f, + 0.61662567f, 0.46771872f, -0.32081389f, + 0.65814799f, 0.46771872f, -0.22108275f, + 0.68403703f, 0.46771872f, -0.11370123f, + 0.69296241f, 0.46771872f, 0.00000001f, + 0.00000000f, 0.48150003f, -0.69020003f, + 0.11324802f, 0.48149997f, -0.68131018f, + 0.22020143f, 0.48150006f, -0.65552443f, + 0.31953502f, 0.48150000f, -0.61416763f, + 0.40992361f, 0.48150009f, -0.55856514f, + 0.49004203f, 0.48150003f, -0.49004203f, + 0.55856514f, 0.48150006f, -0.40992361f, + 0.61416763f, 0.48150003f, -0.31953505f, + 0.65552437f, 0.48150003f, -0.22020143f, + 0.68131030f, 0.48150003f, -0.11324798f, + 0.69020003f, 0.48150003f, 0.00000001f, + 0.00000000f, 0.49134374f, -0.69111252f, + 0.11339774f, 0.49134374f, -0.68221092f, + 0.22049254f, 0.49134377f, -0.65639102f, + 0.31995746f, 0.49134377f, -0.61497957f, + 0.41046557f, 0.49134377f, -0.55930358f, + 0.49068987f, 0.49134374f, -0.49068987f, + 0.55930358f, 0.49134374f, -0.41046554f, + 0.61497957f, 0.49134374f, -0.31995746f, + 0.65639102f, 0.49134377f, -0.22049253f, + 0.68221098f, 0.49134374f, -0.11339770f, + 0.69111252f, 0.49134374f, 0.00000001f, + 0.00000000f, 0.49725008f, -0.69510001f, + 0.11405201f, 0.49725005f, -0.68614709f, + 0.22176473f, 0.49725014f, -0.66017824f, + 0.32180351f, 0.49725008f, -0.61852777f, + 0.41283381f, 0.49725008f, -0.56253058f, + 0.49352100f, 0.49725008f, -0.49352103f, + 0.56253058f, 0.49725008f, -0.41283381f, + 0.61852777f, 0.49725008f, -0.32180351f, + 0.66017818f, 0.49725008f, -0.22176471f, + 0.68614715f, 0.49725008f, -0.11405197f, + 0.69510001f, 0.49725008f, 0.00000001f, + 0.00000000f, 0.49921876f, -0.70156252f, + 0.11511238f, 0.49921870f, -0.69252634f, + 0.22382653f, 0.49921876f, -0.66631603f, + 0.32479537f, 0.49921873f, -0.62427837f, + 0.41667202f, 0.49921879f, -0.56776059f, + 0.49810940f, 0.49921876f, -0.49810940f, + 0.56776053f, 0.49921879f, -0.41667199f, + 0.62427843f, 0.49921876f, -0.32479542f, + 0.66631603f, 0.49921876f, -0.22382650f, + 0.69252640f, 0.49921876f, -0.11511233f, + 0.70156252f, 0.49921876f, 0.00000001f, + 0.00000000f, 0.49725002f, -0.70989996f, + 0.11648039f, 0.49724996f, -0.70075637f, + 0.22648652f, 0.49725008f, -0.67423457f, + 0.32865530f, 0.49724999f, -0.63169742f, + 0.42162383f, 0.49725002f, -0.57450789f, + 0.50402898f, 0.49725002f, -0.50402898f, + 0.57450783f, 0.49725002f, -0.42162377f, + 0.63169742f, 0.49725002f, -0.32865530f, + 0.67423463f, 0.49725005f, -0.22648649f, + 0.70075643f, 0.49725002f, -0.11648034f, + 0.70989996f, 0.49725002f, 0.00000001f, + 0.00000000f, 0.49134377f, -0.71951252f, + 0.11805761f, 0.49134374f, -0.71024513f, + 0.22955328f, 0.49134380f, -0.68336421f, + 0.33310553f, 0.49134377f, -0.64025098f, + 0.42733288f, 0.49134383f, -0.58228713f, + 0.51085389f, 0.49134377f, -0.51085389f, + 0.58228713f, 0.49134377f, -0.42733288f, + 0.64025104f, 0.49134377f, -0.33310553f, + 0.68336427f, 0.49134380f, -0.22955328f, + 0.71024519f, 0.49134377f, -0.11805756f, + 0.71951252f, 0.49134377f, 0.00000001f, + 0.00000000f, 0.48150003f, -0.72979999f, + 0.11974558f, 0.48149997f, -0.72040009f, + 0.23283541f, 0.48150006f, -0.69313490f, + 0.33786824f, 0.48150000f, -0.64940518f, + 0.43344283f, 0.48150009f, -0.59061253f, + 0.51815796f, 0.48150003f, -0.51815796f, + 0.59061259f, 0.48150006f, -0.43344280f, + 0.64940524f, 0.48150003f, -0.33786821f, + 0.69313484f, 0.48150003f, -0.23283540f, + 0.72040015f, 0.48150003f, -0.11974554f, + 0.72979999f, 0.48150003f, 0.00000001f, + 0.00000000f, 0.46771878f, -0.74016249f, + 0.12144586f, 0.46771872f, -0.73062909f, + 0.23614147f, 0.46771881f, -0.70297670f, + 0.34266564f, 0.46771878f, -0.65862614f, + 0.43959734f, 0.46771878f, -0.59899879f, + 0.52551538f, 0.46771878f, -0.52551538f, + 0.59899873f, 0.46771878f, -0.43959731f, + 0.65862620f, 0.46771878f, -0.34266564f, + 0.70297670f, 0.46771878f, -0.23614144f, + 0.73062921f, 0.46771878f, -0.12144581f, + 0.74016249f, 0.46771878f, 0.00000001f, + 0.00000000f, 0.45000005f, -0.75000000f, + 0.12305999f, 0.44999996f, -0.74033999f, + 0.23928000f, 0.45000011f, -0.71232003f, + 0.34721997f, 0.45000002f, -0.66737998f, + 0.44544002f, 0.45000008f, -0.60696000f, + 0.53250003f, 0.45000005f, -0.53250003f, + 0.60696000f, 0.45000005f, -0.44543999f, + 0.66738003f, 0.45000008f, -0.34722000f, + 0.71231997f, 0.45000005f, -0.23927999f, + 0.74033999f, 0.45000005f, -0.12305995f, + 0.75000000f, 0.45000005f, 0.00000001f, + 0.00000000f, 0.45000005f, 0.69999999f, + -0.11485599f, 0.44999996f, 0.69098389f, + -0.22332802f, 0.45000011f, 0.66483200f, + -0.32407200f, 0.45000002f, 0.62288797f, + -0.41574404f, 0.45000008f, 0.56649601f, + -0.49700001f, 0.45000005f, 0.49699998f, + -0.56649601f, 0.45000005f, 0.41574395f, + -0.62288797f, 0.45000008f, 0.32407200f, + -0.66483200f, 0.45000005f, 0.22332799f, + -0.69098401f, 0.45000005f, 0.11485597f, + -0.69999999f, 0.45000005f, 0.00000001f, + 0.00000000f, 0.46771872f, 0.69296241f, + -0.11370128f, 0.46771869f, 0.68403697f, + -0.22108276f, 0.46771878f, 0.65814799f, + -0.32081389f, 0.46771872f, 0.61662567f, + -0.41156429f, 0.46771872f, 0.56080067f, + -0.49200332f, 0.46771872f, 0.49200332f, + -0.56080067f, 0.46771872f, 0.41156423f, + -0.61662567f, 0.46771872f, 0.32081389f, + -0.65814799f, 0.46771872f, 0.22108275f, + -0.68403703f, 0.46771872f, 0.11370125f, + -0.69296241f, 0.46771872f, 0.00000001f, + 0.00000000f, 0.48150003f, 0.69020003f, + -0.11324802f, 0.48149997f, 0.68131018f, + -0.22020143f, 0.48150006f, 0.65552443f, + -0.31953502f, 0.48150000f, 0.61416763f, + -0.40992361f, 0.48150009f, 0.55856514f, + -0.49004203f, 0.48150003f, 0.49004203f, + -0.55856514f, 0.48150006f, 0.40992361f, + -0.61416763f, 0.48150003f, 0.31953505f, + -0.65552437f, 0.48150003f, 0.22020143f, + -0.68131030f, 0.48150003f, 0.11324800f, + -0.69020003f, 0.48150003f, 0.00000001f, + 0.00000000f, 0.49134374f, 0.69111252f, + -0.11339774f, 0.49134374f, 0.68221092f, + -0.22049254f, 0.49134377f, 0.65639102f, + -0.31995746f, 0.49134377f, 0.61497957f, + -0.41046557f, 0.49134377f, 0.55930358f, + -0.49068987f, 0.49134374f, 0.49068987f, + -0.55930358f, 0.49134374f, 0.41046554f, + -0.61497957f, 0.49134374f, 0.31995746f, + -0.65639102f, 0.49134377f, 0.22049253f, + -0.68221098f, 0.49134374f, 0.11339771f, + -0.69111252f, 0.49134374f, 0.00000001f, + 0.00000000f, 0.49725008f, 0.69510001f, + -0.11405201f, 0.49725005f, 0.68614709f, + -0.22176473f, 0.49725014f, 0.66017824f, + -0.32180351f, 0.49725008f, 0.61852777f, + -0.41283381f, 0.49725008f, 0.56253058f, + -0.49352100f, 0.49725008f, 0.49352103f, + -0.56253058f, 0.49725008f, 0.41283381f, + -0.61852777f, 0.49725008f, 0.32180351f, + -0.66017818f, 0.49725008f, 0.22176471f, + -0.68614715f, 0.49725008f, 0.11405198f, + -0.69510001f, 0.49725008f, 0.00000001f, + 0.00000000f, 0.49921876f, 0.70156252f, + -0.11511238f, 0.49921870f, 0.69252634f, + -0.22382653f, 0.49921876f, 0.66631603f, + -0.32479537f, 0.49921873f, 0.62427837f, + -0.41667202f, 0.49921879f, 0.56776059f, + -0.49810940f, 0.49921876f, 0.49810940f, + -0.56776053f, 0.49921879f, 0.41667199f, + -0.62427843f, 0.49921876f, 0.32479542f, + -0.66631603f, 0.49921876f, 0.22382650f, + -0.69252640f, 0.49921876f, 0.11511235f, + -0.70156252f, 0.49921876f, 0.00000001f, + 0.00000000f, 0.49725002f, 0.70989996f, + -0.11648039f, 0.49724996f, 0.70075637f, + -0.22648652f, 0.49725008f, 0.67423457f, + -0.32865530f, 0.49724999f, 0.63169742f, + -0.42162383f, 0.49725002f, 0.57450789f, + -0.50402898f, 0.49725002f, 0.50402898f, + -0.57450783f, 0.49725002f, 0.42162377f, + -0.63169742f, 0.49725002f, 0.32865530f, + -0.67423463f, 0.49725005f, 0.22648649f, + -0.70075643f, 0.49725002f, 0.11648036f, + -0.70989996f, 0.49725002f, 0.00000001f, + 0.00000000f, 0.49134377f, 0.71951252f, + -0.11805761f, 0.49134374f, 0.71024513f, + -0.22955328f, 0.49134380f, 0.68336421f, + -0.33310553f, 0.49134377f, 0.64025098f, + -0.42733288f, 0.49134383f, 0.58228713f, + -0.51085389f, 0.49134377f, 0.51085389f, + -0.58228713f, 0.49134377f, 0.42733288f, + -0.64025104f, 0.49134377f, 0.33310553f, + -0.68336427f, 0.49134380f, 0.22955328f, + -0.71024519f, 0.49134377f, 0.11805757f, + -0.71951252f, 0.49134377f, 0.00000001f, + 0.00000000f, 0.48150003f, 0.72979999f, + -0.11974558f, 0.48149997f, 0.72040009f, + -0.23283541f, 0.48150006f, 0.69313490f, + -0.33786824f, 0.48150000f, 0.64940518f, + -0.43344283f, 0.48150009f, 0.59061253f, + -0.51815796f, 0.48150003f, 0.51815796f, + -0.59061259f, 0.48150006f, 0.43344280f, + -0.64940524f, 0.48150003f, 0.33786821f, + -0.69313484f, 0.48150003f, 0.23283540f, + -0.72040015f, 0.48150003f, 0.11974555f, + -0.72979999f, 0.48150003f, 0.00000001f, + 0.00000000f, 0.46771878f, 0.74016249f, + -0.12144586f, 0.46771872f, 0.73062909f, + -0.23614147f, 0.46771881f, 0.70297670f, + -0.34266564f, 0.46771878f, 0.65862614f, + -0.43959734f, 0.46771878f, 0.59899879f, + -0.52551538f, 0.46771878f, 0.52551538f, + -0.59899873f, 0.46771878f, 0.43959731f, + -0.65862620f, 0.46771878f, 0.34266564f, + -0.70297670f, 0.46771878f, 0.23614144f, + -0.73062921f, 0.46771878f, 0.12144583f, + -0.74016249f, 0.46771878f, 0.00000001f, + 0.00000000f, 0.45000005f, 0.75000000f, + -0.12305999f, 0.44999996f, 0.74033999f, + -0.23928000f, 0.45000011f, 0.71232003f, + -0.34721997f, 0.45000002f, 0.66737998f, + -0.44544002f, 0.45000008f, 0.60696000f, + -0.53250003f, 0.45000005f, 0.53250003f, + -0.60696000f, 0.45000005f, 0.44543999f, + -0.66738003f, 0.45000008f, 0.34722000f, + -0.71231997f, 0.45000005f, 0.23927999f, + -0.74033999f, 0.45000005f, 0.12305997f, + -0.75000000f, 0.45000005f, 0.00000001f, + -0.69999999f, 0.45000005f, 0.00000001f, + -0.69098389f, 0.44999996f, -0.11485598f, + -0.66483200f, 0.45000011f, -0.22332802f, + -0.62288797f, 0.45000002f, -0.32407200f, + -0.56649601f, 0.45000008f, -0.41574404f, + -0.49699998f, 0.45000005f, -0.49700001f, + -0.41574395f, 0.45000005f, -0.56649601f, + -0.32407200f, 0.45000008f, -0.62288797f, + -0.22332799f, 0.45000005f, -0.66483200f, + -0.11485596f, 0.45000005f, -0.69098401f, + 0.00000000f, 0.45000005f, -0.69999999f, + -0.69296241f, 0.46771872f, 0.00000001f, + -0.68403697f, 0.46771869f, -0.11370127f, + -0.65814799f, 0.46771878f, -0.22108276f, + -0.61662567f, 0.46771872f, -0.32081389f, + -0.56080067f, 0.46771872f, -0.41156429f, + -0.49200332f, 0.46771872f, -0.49200332f, + -0.41156423f, 0.46771872f, -0.56080067f, + -0.32081389f, 0.46771872f, -0.61662567f, + -0.22108275f, 0.46771872f, -0.65814799f, + -0.11370124f, 0.46771872f, -0.68403703f, + 0.00000000f, 0.46771872f, -0.69296241f, + -0.69020003f, 0.48150003f, 0.00000001f, + -0.68131018f, 0.48149997f, -0.11324801f, + -0.65552443f, 0.48150006f, -0.22020143f, + -0.61416763f, 0.48150000f, -0.31953502f, + -0.55856514f, 0.48150009f, -0.40992361f, + -0.49004203f, 0.48150003f, -0.49004203f, + -0.40992361f, 0.48150006f, -0.55856514f, + -0.31953505f, 0.48150003f, -0.61416763f, + -0.22020143f, 0.48150003f, -0.65552437f, + -0.11324799f, 0.48150003f, -0.68131030f, + 0.00000000f, 0.48150003f, -0.69020003f, + -0.69111252f, 0.49134374f, 0.00000001f, + -0.68221092f, 0.49134374f, -0.11339773f, + -0.65639102f, 0.49134377f, -0.22049254f, + -0.61497957f, 0.49134377f, -0.31995746f, + -0.55930358f, 0.49134377f, -0.41046557f, + -0.49068987f, 0.49134374f, -0.49068987f, + -0.41046554f, 0.49134374f, -0.55930358f, + -0.31995746f, 0.49134374f, -0.61497957f, + -0.22049253f, 0.49134377f, -0.65639102f, + -0.11339770f, 0.49134374f, -0.68221098f, + 0.00000000f, 0.49134374f, -0.69111252f, + -0.69510001f, 0.49725008f, 0.00000001f, + -0.68614709f, 0.49725005f, -0.11405201f, + -0.66017824f, 0.49725014f, -0.22176473f, + -0.61852777f, 0.49725008f, -0.32180351f, + -0.56253058f, 0.49725008f, -0.41283381f, + -0.49352103f, 0.49725008f, -0.49352100f, + -0.41283381f, 0.49725008f, -0.56253058f, + -0.32180351f, 0.49725008f, -0.61852777f, + -0.22176471f, 0.49725008f, -0.66017818f, + -0.11405198f, 0.49725008f, -0.68614715f, + 0.00000000f, 0.49725008f, -0.69510001f, + -0.70156252f, 0.49921876f, 0.00000001f, + -0.69252634f, 0.49921870f, -0.11511236f, + -0.66631603f, 0.49921876f, -0.22382653f, + -0.62427837f, 0.49921873f, -0.32479537f, + -0.56776059f, 0.49921879f, -0.41667202f, + -0.49810940f, 0.49921876f, -0.49810940f, + -0.41667199f, 0.49921879f, -0.56776053f, + -0.32479542f, 0.49921876f, -0.62427843f, + -0.22382650f, 0.49921876f, -0.66631603f, + -0.11511234f, 0.49921876f, -0.69252640f, + 0.00000000f, 0.49921876f, -0.70156252f, + -0.70989996f, 0.49725002f, 0.00000001f, + -0.70075637f, 0.49724996f, -0.11648037f, + -0.67423457f, 0.49725008f, -0.22648652f, + -0.63169742f, 0.49724999f, -0.32865530f, + -0.57450789f, 0.49725002f, -0.42162383f, + -0.50402898f, 0.49725002f, -0.50402898f, + -0.42162377f, 0.49725002f, -0.57450783f, + -0.32865530f, 0.49725002f, -0.63169742f, + -0.22648649f, 0.49725005f, -0.67423463f, + -0.11648035f, 0.49725002f, -0.70075643f, + 0.00000000f, 0.49725002f, -0.70989996f, + -0.71951252f, 0.49134377f, 0.00000001f, + -0.71024513f, 0.49134374f, -0.11805760f, + -0.68336421f, 0.49134380f, -0.22955328f, + -0.64025098f, 0.49134377f, -0.33310553f, + -0.58228713f, 0.49134383f, -0.42733288f, + -0.51085389f, 0.49134377f, -0.51085389f, + -0.42733288f, 0.49134377f, -0.58228713f, + -0.33310553f, 0.49134377f, -0.64025104f, + -0.22955328f, 0.49134380f, -0.68336427f, + -0.11805756f, 0.49134377f, -0.71024519f, + 0.00000000f, 0.49134377f, -0.71951252f, + -0.72979999f, 0.48150003f, 0.00000001f, + -0.72040009f, 0.48149997f, -0.11974557f, + -0.69313490f, 0.48150006f, -0.23283541f, + -0.64940518f, 0.48150000f, -0.33786824f, + -0.59061253f, 0.48150009f, -0.43344283f, + -0.51815796f, 0.48150003f, -0.51815796f, + -0.43344280f, 0.48150006f, -0.59061259f, + -0.33786821f, 0.48150003f, -0.64940524f, + -0.23283540f, 0.48150003f, -0.69313484f, + -0.11974555f, 0.48150003f, -0.72040015f, + 0.00000000f, 0.48150003f, -0.72979999f, + -0.74016249f, 0.46771878f, 0.00000001f, + -0.73062909f, 0.46771872f, -0.12144585f, + -0.70297670f, 0.46771881f, -0.23614147f, + -0.65862614f, 0.46771878f, -0.34266564f, + -0.59899879f, 0.46771878f, -0.43959734f, + -0.52551538f, 0.46771878f, -0.52551538f, + -0.43959731f, 0.46771878f, -0.59899873f, + -0.34266564f, 0.46771878f, -0.65862620f, + -0.23614144f, 0.46771878f, -0.70297670f, + -0.12144582f, 0.46771878f, -0.73062921f, + 0.00000000f, 0.46771878f, -0.74016249f, + -0.75000000f, 0.45000005f, 0.00000001f, + -0.74033999f, 0.44999996f, -0.12305998f, + -0.71232003f, 0.45000011f, -0.23928000f, + -0.66737998f, 0.45000002f, -0.34721997f, + -0.60696000f, 0.45000008f, -0.44544002f, + -0.53250003f, 0.45000005f, -0.53250003f, + -0.44543999f, 0.45000005f, -0.60696000f, + -0.34722000f, 0.45000008f, -0.66738003f, + -0.23927999f, 0.45000005f, -0.71231997f, + -0.12305996f, 0.45000005f, -0.74033999f, + 0.00000000f, 0.45000005f, -0.75000000f, + 0.75000000f, 0.45000005f, 0.00000001f, + 0.74033999f, 0.44999996f, 0.12306000f, + 0.71232003f, 0.45000011f, 0.23928000f, + 0.66737998f, 0.45000002f, 0.34721997f, + 0.60696000f, 0.45000008f, 0.44544002f, + 0.53250003f, 0.45000005f, 0.53250003f, + 0.44543999f, 0.45000005f, 0.60696000f, + 0.34722000f, 0.45000008f, 0.66738003f, + 0.23927999f, 0.45000005f, 0.71231997f, + 0.12305996f, 0.45000005f, 0.74033999f, + 0.00000000f, 0.45000005f, 0.75000000f, + 0.78737491f, 0.37128749f, 0.00000000f, + 0.77723348f, 0.37128747f, 0.12919247f, + 0.74781722f, 0.37128752f, 0.25120407f, + 0.70063770f, 0.37128749f, 0.36452308f, + 0.63720679f, 0.37128752f, 0.46763775f, + 0.55903620f, 0.37128749f, 0.55903620f, + 0.46763766f, 0.37128749f, 0.63720679f, + 0.36452311f, 0.37128749f, 0.70063770f, + 0.25120407f, 0.37128752f, 0.74781728f, + 0.12919241f, 0.37128749f, 0.77723348f, + 0.00000000f, 0.37128749f, 0.78737491f, + 0.82400006f, 0.29280004f, 0.00000000f, + 0.81338686f, 0.29280004f, 0.13520193f, + 0.78260237f, 0.29280004f, 0.26288900f, + 0.73322815f, 0.29280004f, 0.38147905f, + 0.66684681f, 0.29280004f, 0.48939016f, + 0.58504003f, 0.29280001f, 0.58504003f, + 0.48939011f, 0.29280004f, 0.66684675f, + 0.38147908f, 0.29280007f, 0.73322821f, + 0.26288897f, 0.29280004f, 0.78260231f, + 0.13520187f, 0.29280004f, 0.81338698f, + 0.00000000f, 0.29280004f, 0.82400006f, + 0.85912502f, 0.21476251f, 0.00000000f, + 0.84805942f, 0.21476249f, 0.14096522f, + 0.81596267f, 0.21476252f, 0.27409527f, + 0.76448381f, 0.21476249f, 0.39774051f, + 0.69527274f, 0.21476252f, 0.51025152f, + 0.60997874f, 0.21476251f, 0.60997874f, + 0.51025152f, 0.21476251f, 0.69527274f, + 0.39774054f, 0.21476251f, 0.76448381f, + 0.27409524f, 0.21476251f, 0.81596261f, + 0.14096518f, 0.21476251f, 0.84805954f, + 0.00000000f, 0.21476251f, 0.85912502f, + 0.89200008f, 0.13740003f, 0.00000000f, + 0.88051099f, 0.13740002f, 0.14635937f, + 0.84718603f, 0.13740005f, 0.28458369f, + 0.79373735f, 0.13740002f, 0.41296035f, + 0.72187787f, 0.13740005f, 0.52977669f, + 0.63332003f, 0.13740002f, 0.63332003f, + 0.52977669f, 0.13740002f, 0.72187781f, + 0.41296035f, 0.13740002f, 0.79373741f, + 0.28458369f, 0.13740000f, 0.84718597f, + 0.14635932f, 0.13740000f, 0.88051111f, + 0.00000000f, 0.13740000f, 0.89200008f, + 0.92187500f, 0.06093751f, 0.00000000f, + 0.91000110f, 0.06093750f, 0.15126126f, + 0.87556010f, 0.06093751f, 0.29411504f, + 0.82032120f, 0.06093750f, 0.42679128f, + 0.74605507f, 0.06093750f, 0.54752004f, + 0.65453124f, 0.06093751f, 0.65453124f, + 0.54751998f, 0.06093750f, 0.74605501f, + 0.42679128f, 0.06093750f, 0.82032126f, + 0.29411501f, 0.06093750f, 0.87556005f, + 0.15126120f, 0.06093750f, 0.91000128f, + 0.00000000f, 0.06093750f, 0.92187500f, + 0.94800001f, -0.01440001f, -0.00000000f, + 0.93578976f, -0.01440001f, 0.15554784f, + 0.90037251f, -0.01440001f, 0.30244994f, + 0.84356833f, -0.01440001f, 0.43888608f, + 0.76719749f, -0.01440001f, 0.56303620f, + 0.67308003f, -0.01440001f, 0.67308003f, + 0.56303614f, -0.01440002f, 0.76719743f, + 0.43888611f, -0.01440002f, 0.84356833f, + 0.30244991f, -0.01440002f, 0.90037251f, + 0.15554780f, -0.01440002f, 0.93578976f, + 0.00000000f, -0.01440002f, 0.94800001f, + 0.96962506f, -0.08838750f, -0.00000000f, + 0.95713621f, -0.08838749f, 0.15909605f, + 0.92091113f, -0.08838750f, 0.30934918f, + 0.86281121f, -0.08838750f, 0.44889757f, + 0.78469825f, -0.08838750f, 0.57587969f, + 0.68843377f, -0.08838750f, 0.68843377f, + 0.57587969f, -0.08838750f, 0.78469819f, + 0.44889760f, -0.08838750f, 0.86281121f, + 0.30934915f, -0.08838750f, 0.92091107f, + 0.15909600f, -0.08838750f, 0.95713627f, + 0.00000000f, -0.08838750f, 0.96962506f, + 0.98600000f, -0.16080001f, -0.00000000f, + 0.97330022f, -0.16080000f, 0.16178288f, + 0.93646342f, -0.16080002f, 0.31457347f, + 0.87738222f, -0.16080001f, 0.45647857f, + 0.79795015f, -0.16080002f, 0.58560514f, + 0.70006001f, -0.16080001f, 0.70006001f, + 0.58560514f, -0.16080001f, 0.79795015f, + 0.45647860f, -0.16080001f, 0.87738228f, + 0.31457344f, -0.16080001f, 0.93646336f, + 0.16178282f, -0.16080001f, 0.97330034f, + 0.00000000f, -0.16080001f, 0.98600000f, + 0.99637496f, -0.23141253f, -0.00000000f, + 0.98354161f, -0.23141250f, 0.16348520f, + 0.94631720f, -0.23141254f, 0.31788349f, + 0.88661432f, -0.23141253f, 0.46128178f, + 0.80634636f, -0.23141254f, 0.59176707f, + 0.70742619f, -0.23141253f, 0.70742619f, + 0.59176701f, -0.23141253f, 0.80634630f, + 0.46128178f, -0.23141253f, 0.88661432f, + 0.31788346f, -0.23141253f, 0.94631708f, + 0.16348514f, -0.23141253f, 0.98354173f, + 0.00000000f, -0.23141253f, 0.99637496f, + 1.00000000f, -0.30000001f, -0.00000000f, + 0.98711991f, -0.29999998f, 0.16407999f, + 0.94976002f, -0.30000004f, 0.31904000f, + 0.88984001f, -0.30000004f, 0.46296000f, + 0.80928004f, -0.30000001f, 0.59392005f, + 0.71000004f, -0.30000001f, 0.71000004f, + 0.59391999f, -0.30000001f, 0.80928004f, + 0.46296003f, -0.30000001f, 0.88984001f, + 0.31904000f, -0.30000001f, 0.94976002f, + 0.16407993f, -0.30000001f, 0.98712003f, + 0.00000000f, -0.30000001f, 1.00000000f, + 0.00000000f, 0.45000005f, -0.75000000f, + 0.12305999f, 0.44999996f, -0.74033999f, + 0.23928000f, 0.45000011f, -0.71232003f, + 0.34721997f, 0.45000002f, -0.66737998f, + 0.44544002f, 0.45000008f, -0.60696000f, + 0.53250003f, 0.45000005f, -0.53250003f, + 0.60696000f, 0.45000005f, -0.44543999f, + 0.66738003f, 0.45000008f, -0.34722000f, + 0.71231997f, 0.45000005f, -0.23927999f, + 0.74033999f, 0.45000005f, -0.12305995f, + 0.75000000f, 0.45000005f, 0.00000001f, + 0.00000000f, 0.37128749f, -0.78737491f, + 0.12919247f, 0.37128747f, -0.77723348f, + 0.25120407f, 0.37128752f, -0.74781722f, + 0.36452308f, 0.37128749f, -0.70063770f, + 0.46763775f, 0.37128752f, -0.63720679f, + 0.55903620f, 0.37128749f, -0.55903620f, + 0.63720679f, 0.37128749f, -0.46763766f, + 0.70063770f, 0.37128749f, -0.36452311f, + 0.74781728f, 0.37128752f, -0.25120407f, + 0.77723348f, 0.37128749f, -0.12919241f, + 0.78737491f, 0.37128749f, 0.00000000f, + 0.00000000f, 0.29280004f, -0.82400006f, + 0.13520193f, 0.29280004f, -0.81338686f, + 0.26288900f, 0.29280004f, -0.78260237f, + 0.38147905f, 0.29280004f, -0.73322815f, + 0.48939016f, 0.29280004f, -0.66684681f, + 0.58504003f, 0.29280001f, -0.58504003f, + 0.66684675f, 0.29280004f, -0.48939011f, + 0.73322821f, 0.29280007f, -0.38147908f, + 0.78260231f, 0.29280004f, -0.26288897f, + 0.81338698f, 0.29280004f, -0.13520187f, + 0.82400006f, 0.29280004f, 0.00000000f, + 0.00000000f, 0.21476251f, -0.85912502f, + 0.14096522f, 0.21476249f, -0.84805942f, + 0.27409527f, 0.21476252f, -0.81596267f, + 0.39774051f, 0.21476249f, -0.76448381f, + 0.51025152f, 0.21476252f, -0.69527274f, + 0.60997874f, 0.21476251f, -0.60997874f, + 0.69527274f, 0.21476251f, -0.51025152f, + 0.76448381f, 0.21476251f, -0.39774054f, + 0.81596261f, 0.21476251f, -0.27409524f, + 0.84805954f, 0.21476251f, -0.14096518f, + 0.85912502f, 0.21476251f, 0.00000000f, + 0.00000000f, 0.13740005f, -0.89200008f, + 0.14635937f, 0.13740005f, -0.88051099f, + 0.28458369f, 0.13740005f, -0.84718603f, + 0.41296035f, 0.13740005f, -0.79373735f, + 0.52977669f, 0.13740005f, -0.72187787f, + 0.63332003f, 0.13740003f, -0.63332003f, + 0.72187781f, 0.13740003f, -0.52977669f, + 0.79373741f, 0.13740005f, -0.41296035f, + 0.84718597f, 0.13740003f, -0.28458369f, + 0.88051111f, 0.13740003f, -0.14635932f, + 0.89200008f, 0.13740003f, 0.00000000f, + 0.00000000f, 0.06093752f, -0.92187500f, + 0.15126126f, 0.06093751f, -0.91000110f, + 0.29411504f, 0.06093752f, -0.87556010f, + 0.42679128f, 0.06093752f, -0.82032120f, + 0.54752004f, 0.06093752f, -0.74605507f, + 0.65453124f, 0.06093752f, -0.65453124f, + 0.74605501f, 0.06093752f, -0.54751998f, + 0.82032126f, 0.06093751f, -0.42679128f, + 0.87556005f, 0.06093752f, -0.29411501f, + 0.91000128f, 0.06093751f, -0.15126120f, + 0.92187500f, 0.06093751f, 0.00000000f, + 0.00000000f, -0.01440000f, -0.94800001f, + 0.15554784f, -0.01440000f, -0.93578976f, + 0.30244994f, -0.01440000f, -0.90037251f, + 0.43888608f, -0.01440000f, -0.84356833f, + 0.56303620f, -0.01440000f, -0.76719749f, + 0.67308003f, -0.01440000f, -0.67308003f, + 0.76719743f, -0.01440001f, -0.56303614f, + 0.84356833f, -0.01440001f, -0.43888611f, + 0.90037251f, -0.01440001f, -0.30244991f, + 0.93578976f, -0.01440001f, -0.15554780f, + 0.94800001f, -0.01440001f, -0.00000000f, + 0.00000000f, -0.08838749f, -0.96962506f, + 0.15909605f, -0.08838748f, -0.95713621f, + 0.30934918f, -0.08838750f, -0.92091113f, + 0.44889757f, -0.08838750f, -0.86281121f, + 0.57587969f, -0.08838750f, -0.78469825f, + 0.68843377f, -0.08838749f, -0.68843377f, + 0.78469819f, -0.08838750f, -0.57587969f, + 0.86281121f, -0.08838750f, -0.44889760f, + 0.92091107f, -0.08838750f, -0.30934915f, + 0.95713627f, -0.08838749f, -0.15909600f, + 0.96962506f, -0.08838750f, -0.00000000f, + 0.00000000f, -0.16080000f, -0.98600000f, + 0.16178288f, -0.16079998f, -0.97330022f, + 0.31457347f, -0.16080001f, -0.93646342f, + 0.45647857f, -0.16080000f, -0.87738222f, + 0.58560514f, -0.16080001f, -0.79795015f, + 0.70006001f, -0.16080000f, -0.70006001f, + 0.79795015f, -0.16080000f, -0.58560514f, + 0.87738228f, -0.16080001f, -0.45647860f, + 0.93646336f, -0.16080001f, -0.31457344f, + 0.97330034f, -0.16080001f, -0.16178282f, + 0.98600000f, -0.16080001f, -0.00000000f, + 0.00000000f, -0.23141253f, -0.99637496f, + 0.16348520f, -0.23141250f, -0.98354161f, + 0.31788349f, -0.23141254f, -0.94631720f, + 0.46128178f, -0.23141253f, -0.88661432f, + 0.59176707f, -0.23141254f, -0.80634636f, + 0.70742619f, -0.23141253f, -0.70742619f, + 0.80634630f, -0.23141253f, -0.59176701f, + 0.88661432f, -0.23141253f, -0.46128178f, + 0.94631708f, -0.23141253f, -0.31788346f, + 0.98354173f, -0.23141253f, -0.16348514f, + 0.99637496f, -0.23141253f, -0.00000000f, + 0.00000000f, -0.30000001f, -1.00000000f, + 0.16407999f, -0.29999998f, -0.98711991f, + 0.31904000f, -0.30000004f, -0.94976002f, + 0.46296000f, -0.30000004f, -0.88984001f, + 0.59392005f, -0.30000001f, -0.80928004f, + 0.71000004f, -0.30000001f, -0.71000004f, + 0.80928004f, -0.30000001f, -0.59391999f, + 0.88984001f, -0.30000001f, -0.46296003f, + 0.94976002f, -0.30000001f, -0.31904000f, + 0.98712003f, -0.30000001f, -0.16407993f, + 1.00000000f, -0.30000001f, -0.00000000f, + 0.00000000f, 0.45000005f, 0.75000000f, + -0.12305999f, 0.44999996f, 0.74033999f, + -0.23928000f, 0.45000011f, 0.71232003f, + -0.34721997f, 0.45000002f, 0.66737998f, + -0.44544002f, 0.45000008f, 0.60696000f, + -0.53250003f, 0.45000005f, 0.53250003f, + -0.60696000f, 0.45000005f, 0.44543999f, + -0.66738003f, 0.45000008f, 0.34722000f, + -0.71231997f, 0.45000005f, 0.23927999f, + -0.74033999f, 0.45000005f, 0.12305997f, + -0.75000000f, 0.45000005f, 0.00000001f, + 0.00000000f, 0.37128749f, 0.78737491f, + -0.12919247f, 0.37128747f, 0.77723348f, + -0.25120407f, 0.37128752f, 0.74781722f, + -0.36452308f, 0.37128749f, 0.70063770f, + -0.46763775f, 0.37128752f, 0.63720679f, + -0.55903620f, 0.37128749f, 0.55903620f, + -0.63720679f, 0.37128749f, 0.46763766f, + -0.70063770f, 0.37128749f, 0.36452311f, + -0.74781728f, 0.37128752f, 0.25120407f, + -0.77723348f, 0.37128749f, 0.12919241f, + -0.78737491f, 0.37128749f, 0.00000000f, + 0.00000000f, 0.29280004f, 0.82400006f, + -0.13520193f, 0.29280004f, 0.81338686f, + -0.26288900f, 0.29280004f, 0.78260237f, + -0.38147905f, 0.29280004f, 0.73322815f, + -0.48939016f, 0.29280004f, 0.66684681f, + -0.58504003f, 0.29280001f, 0.58504003f, + -0.66684675f, 0.29280004f, 0.48939011f, + -0.73322821f, 0.29280007f, 0.38147908f, + -0.78260231f, 0.29280004f, 0.26288897f, + -0.81338698f, 0.29280004f, 0.13520187f, + -0.82400006f, 0.29280004f, 0.00000000f, + 0.00000000f, 0.21476251f, 0.85912502f, + -0.14096522f, 0.21476249f, 0.84805942f, + -0.27409527f, 0.21476252f, 0.81596267f, + -0.39774051f, 0.21476249f, 0.76448381f, + -0.51025152f, 0.21476252f, 0.69527274f, + -0.60997874f, 0.21476251f, 0.60997874f, + -0.69527274f, 0.21476251f, 0.51025152f, + -0.76448381f, 0.21476251f, 0.39774054f, + -0.81596261f, 0.21476251f, 0.27409524f, + -0.84805954f, 0.21476251f, 0.14096518f, + -0.85912502f, 0.21476251f, 0.00000000f, + 0.00000000f, 0.13740000f, 0.89200008f, + -0.14635937f, 0.13740000f, 0.88051099f, + -0.28458369f, 0.13740002f, 0.84718603f, + -0.41296035f, 0.13740002f, 0.79373735f, + -0.52977669f, 0.13740002f, 0.72187787f, + -0.63332003f, 0.13740002f, 0.63332003f, + -0.72187781f, 0.13740002f, 0.52977669f, + -0.79373741f, 0.13740003f, 0.41296035f, + -0.84718597f, 0.13740003f, 0.28458369f, + -0.88051111f, 0.13740003f, 0.14635932f, + -0.89200008f, 0.13740003f, 0.00000000f, + 0.00000000f, 0.06093750f, 0.92187500f, + -0.15126126f, 0.06093750f, 0.91000110f, + -0.29411504f, 0.06093751f, 0.87556010f, + -0.42679128f, 0.06093750f, 0.82032120f, + -0.54752004f, 0.06093750f, 0.74605507f, + -0.65453124f, 0.06093750f, 0.65453124f, + -0.74605501f, 0.06093750f, 0.54751998f, + -0.82032126f, 0.06093751f, 0.42679128f, + -0.87556005f, 0.06093751f, 0.29411501f, + -0.91000128f, 0.06093751f, 0.15126120f, + -0.92187500f, 0.06093751f, 0.00000000f, + 0.00000000f, -0.01440002f, 0.94800001f, + -0.15554784f, -0.01440002f, 0.93578976f, + -0.30244994f, -0.01440002f, 0.90037251f, + -0.43888608f, -0.01440002f, 0.84356833f, + -0.56303620f, -0.01440002f, 0.76719749f, + -0.67308003f, -0.01440001f, 0.67308003f, + -0.76719743f, -0.01440001f, 0.56303614f, + -0.84356833f, -0.01440001f, 0.43888611f, + -0.90037251f, -0.01440001f, 0.30244991f, + -0.93578976f, -0.01440001f, 0.15554780f, + -0.94800001f, -0.01440001f, -0.00000000f, + 0.00000000f, -0.08838750f, 0.96962506f, + -0.15909605f, -0.08838750f, 0.95713621f, + -0.30934918f, -0.08838750f, 0.92091113f, + -0.44889757f, -0.08838750f, 0.86281121f, + -0.57587969f, -0.08838751f, 0.78469825f, + -0.68843377f, -0.08838750f, 0.68843377f, + -0.78469819f, -0.08838750f, 0.57587969f, + -0.86281121f, -0.08838750f, 0.44889760f, + -0.92091107f, -0.08838750f, 0.30934915f, + -0.95713627f, -0.08838750f, 0.15909600f, + -0.96962506f, -0.08838750f, -0.00000000f, + 0.00000000f, -0.16080001f, 0.98600000f, + -0.16178288f, -0.16080000f, 0.97330022f, + -0.31457347f, -0.16080002f, 0.93646342f, + -0.45647857f, -0.16080001f, 0.87738222f, + -0.58560514f, -0.16080002f, 0.79795015f, + -0.70006001f, -0.16080001f, 0.70006001f, + -0.79795015f, -0.16080001f, 0.58560514f, + -0.87738228f, -0.16080001f, 0.45647860f, + -0.93646336f, -0.16080001f, 0.31457344f, + -0.97330034f, -0.16080001f, 0.16178282f, + -0.98600000f, -0.16080001f, -0.00000000f, + 0.00000000f, -0.23141253f, 0.99637496f, + -0.16348520f, -0.23141250f, 0.98354161f, + -0.31788349f, -0.23141254f, 0.94631720f, + -0.46128178f, -0.23141253f, 0.88661432f, + -0.59176707f, -0.23141254f, 0.80634636f, + -0.70742619f, -0.23141253f, 0.70742619f, + -0.80634630f, -0.23141253f, 0.59176701f, + -0.88661432f, -0.23141253f, 0.46128178f, + -0.94631708f, -0.23141253f, 0.31788346f, + -0.98354173f, -0.23141253f, 0.16348514f, + -0.99637496f, -0.23141253f, -0.00000000f, + 0.00000000f, -0.30000001f, 1.00000000f, + -0.16407999f, -0.29999998f, 0.98711991f, + -0.31904000f, -0.30000004f, 0.94976002f, + -0.46296000f, -0.30000004f, 0.88984001f, + -0.59392005f, -0.30000001f, 0.80928004f, + -0.71000004f, -0.30000001f, 0.71000004f, + -0.80928004f, -0.30000001f, 0.59391999f, + -0.88984001f, -0.30000001f, 0.46296003f, + -0.94976002f, -0.30000001f, 0.31904000f, + -0.98712003f, -0.30000001f, 0.16407993f, + -1.00000000f, -0.30000001f, -0.00000000f, + -0.75000000f, 0.45000005f, 0.00000001f, + -0.74033999f, 0.44999996f, -0.12305998f, + -0.71232003f, 0.45000011f, -0.23928000f, + -0.66737998f, 0.45000002f, -0.34721997f, + -0.60696000f, 0.45000008f, -0.44544002f, + -0.53250003f, 0.45000005f, -0.53250003f, + -0.44543999f, 0.45000005f, -0.60696000f, + -0.34722000f, 0.45000008f, -0.66738003f, + -0.23927999f, 0.45000005f, -0.71231997f, + -0.12305996f, 0.45000005f, -0.74033999f, + 0.00000000f, 0.45000005f, -0.75000000f, + -0.78737491f, 0.37128749f, 0.00000000f, + -0.77723348f, 0.37128747f, -0.12919247f, + -0.74781722f, 0.37128752f, -0.25120407f, + -0.70063770f, 0.37128749f, -0.36452308f, + -0.63720679f, 0.37128752f, -0.46763775f, + -0.55903620f, 0.37128749f, -0.55903620f, + -0.46763766f, 0.37128749f, -0.63720679f, + -0.36452311f, 0.37128749f, -0.70063770f, + -0.25120407f, 0.37128752f, -0.74781728f, + -0.12919241f, 0.37128749f, -0.77723348f, + 0.00000000f, 0.37128749f, -0.78737491f, + -0.82400006f, 0.29280004f, 0.00000000f, + -0.81338686f, 0.29280004f, -0.13520193f, + -0.78260237f, 0.29280004f, -0.26288900f, + -0.73322815f, 0.29280004f, -0.38147905f, + -0.66684681f, 0.29280004f, -0.48939016f, + -0.58504003f, 0.29280001f, -0.58504003f, + -0.48939011f, 0.29280004f, -0.66684675f, + -0.38147908f, 0.29280007f, -0.73322821f, + -0.26288897f, 0.29280004f, -0.78260231f, + -0.13520187f, 0.29280004f, -0.81338698f, + 0.00000000f, 0.29280004f, -0.82400006f, + -0.85912502f, 0.21476251f, 0.00000000f, + -0.84805942f, 0.21476249f, -0.14096522f, + -0.81596267f, 0.21476252f, -0.27409527f, + -0.76448381f, 0.21476249f, -0.39774051f, + -0.69527274f, 0.21476252f, -0.51025152f, + -0.60997874f, 0.21476251f, -0.60997874f, + -0.51025152f, 0.21476251f, -0.69527274f, + -0.39774054f, 0.21476251f, -0.76448381f, + -0.27409524f, 0.21476251f, -0.81596261f, + -0.14096518f, 0.21476251f, -0.84805954f, + 0.00000000f, 0.21476251f, -0.85912502f, + -0.89200008f, 0.13740003f, 0.00000000f, + -0.88051099f, 0.13740003f, -0.14635937f, + -0.84718603f, 0.13740005f, -0.28458369f, + -0.79373735f, 0.13740005f, -0.41296035f, + -0.72187787f, 0.13740005f, -0.52977669f, + -0.63332003f, 0.13740005f, -0.63332003f, + -0.52977669f, 0.13740005f, -0.72187781f, + -0.41296035f, 0.13740005f, -0.79373741f, + -0.28458369f, 0.13740005f, -0.84718597f, + -0.14635932f, 0.13740005f, -0.88051111f, + 0.00000000f, 0.13740005f, -0.89200008f, + -0.92187500f, 0.06093751f, 0.00000000f, + -0.91000110f, 0.06093751f, -0.15126126f, + -0.87556010f, 0.06093752f, -0.29411504f, + -0.82032120f, 0.06093751f, -0.42679128f, + -0.74605507f, 0.06093752f, -0.54752004f, + -0.65453124f, 0.06093752f, -0.65453124f, + -0.54751998f, 0.06093752f, -0.74605501f, + -0.42679128f, 0.06093752f, -0.82032126f, + -0.29411501f, 0.06093752f, -0.87556005f, + -0.15126120f, 0.06093752f, -0.91000128f, + 0.00000000f, 0.06093752f, -0.92187500f, + -0.94800001f, -0.01440001f, -0.00000000f, + -0.93578976f, -0.01440001f, -0.15554784f, + -0.90037251f, -0.01440001f, -0.30244994f, + -0.84356833f, -0.01440001f, -0.43888608f, + -0.76719749f, -0.01440001f, -0.56303620f, + -0.67308003f, -0.01440000f, -0.67308003f, + -0.56303614f, -0.01440000f, -0.76719743f, + -0.43888611f, -0.01440000f, -0.84356833f, + -0.30244991f, -0.01440000f, -0.90037251f, + -0.15554780f, -0.01440000f, -0.93578976f, + 0.00000000f, -0.01440000f, -0.94800001f, + -0.96962506f, -0.08838750f, -0.00000000f, + -0.95713621f, -0.08838749f, -0.15909605f, + -0.92091113f, -0.08838750f, -0.30934918f, + -0.86281121f, -0.08838750f, -0.44889757f, + -0.78469825f, -0.08838750f, -0.57587969f, + -0.68843377f, -0.08838749f, -0.68843377f, + -0.57587969f, -0.08838749f, -0.78469819f, + -0.44889760f, -0.08838749f, -0.86281121f, + -0.30934915f, -0.08838749f, -0.92091107f, + -0.15909600f, -0.08838749f, -0.95713627f, + 0.00000000f, -0.08838749f, -0.96962506f, + -0.98600000f, -0.16080001f, -0.00000000f, + -0.97330022f, -0.16080000f, -0.16178288f, + -0.93646342f, -0.16080001f, -0.31457347f, + -0.87738222f, -0.16080000f, -0.45647857f, + -0.79795015f, -0.16080001f, -0.58560514f, + -0.70006001f, -0.16080001f, -0.70006001f, + -0.58560514f, -0.16080000f, -0.79795015f, + -0.45647860f, -0.16080001f, -0.87738228f, + -0.31457344f, -0.16080000f, -0.93646336f, + -0.16178282f, -0.16080000f, -0.97330034f, + 0.00000000f, -0.16080000f, -0.98600000f, + -0.99637496f, -0.23141253f, -0.00000000f, + -0.98354161f, -0.23141250f, -0.16348520f, + -0.94631720f, -0.23141254f, -0.31788349f, + -0.88661432f, -0.23141253f, -0.46128178f, + -0.80634636f, -0.23141254f, -0.59176707f, + -0.70742619f, -0.23141253f, -0.70742619f, + -0.59176701f, -0.23141253f, -0.80634630f, + -0.46128178f, -0.23141253f, -0.88661432f, + -0.31788346f, -0.23141253f, -0.94631708f, + -0.16348514f, -0.23141253f, -0.98354173f, + 0.00000000f, -0.23141253f, -0.99637496f, + -1.00000000f, -0.30000001f, -0.00000000f, + -0.98711991f, -0.29999998f, -0.16407999f, + -0.94976002f, -0.30000004f, -0.31904000f, + -0.88984001f, -0.30000004f, -0.46296000f, + -0.80928004f, -0.30000001f, -0.59392005f, + -0.71000004f, -0.30000001f, -0.71000004f, + -0.59391999f, -0.30000001f, -0.80928004f, + -0.46296003f, -0.30000001f, -0.88984001f, + -0.31904000f, -0.30000001f, -0.94976002f, + -0.16407993f, -0.30000001f, -0.98712003f, + 0.00000000f, -0.30000001f, -1.00000000f, + 1.00000000f, -0.30000001f, -0.00000000f, + 0.98711991f, -0.29999998f, 0.16407999f, + 0.94976002f, -0.30000004f, 0.31904000f, + 0.88984001f, -0.30000004f, 0.46296000f, + 0.80928004f, -0.30000001f, 0.59392005f, + 0.71000004f, -0.30000001f, 0.71000004f, + 0.59391999f, -0.30000001f, 0.80928004f, + 0.46296003f, -0.30000001f, 0.88984001f, + 0.31904000f, -0.30000001f, 0.94976002f, + 0.16407993f, -0.30000001f, 0.98712003f, + 0.00000000f, -0.30000001f, 1.00000000f, + 0.99299991f, -0.36416247f, -0.00000000f, + 0.98021001f, -0.36416242f, 0.16293143f, + 0.94311166f, -0.36416250f, 0.31680670f, + 0.88361102f, -0.36416245f, 0.45971927f, + 0.80361503f, -0.36416247f, 0.58976257f, + 0.70502996f, -0.36416247f, 0.70502996f, + 0.58976251f, -0.36416250f, 0.80361497f, + 0.45971930f, -0.36416247f, 0.88361108f, + 0.31680670f, -0.36416250f, 0.94311166f, + 0.16293137f, -0.36416247f, 0.98021007f, + 0.00000000f, -0.36416247f, 0.99299991f, + 0.97400004f, -0.42180002f, -0.00000001f, + 0.96145481f, -0.42179996f, 0.15981390f, + 0.92506635f, -0.42180005f, 0.31074497f, + 0.86670411f, -0.42180002f, 0.45092306f, + 0.78823876f, -0.42180011f, 0.57847816f, + 0.69154000f, -0.42180008f, 0.69154000f, + 0.57847810f, -0.42180005f, 0.78823876f, + 0.45092303f, -0.42180008f, 0.86670417f, + 0.31074494f, -0.42180008f, 0.92506629f, + 0.15981385f, -0.42180008f, 0.96145493f, + 0.00000000f, -0.42180005f, 0.97400004f, + 0.94600004f, -0.47313750f, -0.00000001f, + 0.93381548f, -0.47313747f, 0.15521967f, + 0.89847302f, -0.47313756f, 0.30181187f, + 0.84178865f, -0.47313750f, 0.43796018f, + 0.76557899f, -0.47313753f, 0.56184840f, + 0.67166001f, -0.47313753f, 0.67166001f, + 0.56184828f, -0.47313753f, 0.76557899f, + 0.43796021f, -0.47313753f, 0.84178865f, + 0.30181184f, -0.47313753f, 0.89847302f, + 0.15521961f, -0.47313753f, 0.93381560f, + 0.00000000f, -0.47313753f, 0.94600004f, + 0.91200000f, -0.51840001f, -0.00000001f, + 0.90025330f, -0.51839995f, 0.14964095f, + 0.86618114f, -0.51840007f, 0.29096451f, + 0.81153411f, -0.51840001f, 0.42221951f, + 0.73806345f, -0.51840007f, 0.54165506f, + 0.64752001f, -0.51840007f, 0.64752001f, + 0.54165506f, -0.51840007f, 0.73806340f, + 0.42221954f, -0.51840007f, 0.81153411f, + 0.29096448f, -0.51840007f, 0.86618114f, + 0.14964090f, -0.51840007f, 0.90025342f, + 0.00000000f, -0.51840007f, 0.91200000f, + 0.87500000f, -0.55781251f, -0.00000001f, + 0.86372989f, -0.55781251f, 0.14356998f, + 0.83104002f, -0.55781251f, 0.27916002f, + 0.77860999f, -0.55781251f, 0.40509003f, + 0.70812005f, -0.55781257f, 0.51968002f, + 0.62125003f, -0.55781251f, 0.62125003f, + 0.51967996f, -0.55781251f, 0.70812005f, + 0.40509003f, -0.55781257f, 0.77860999f, + 0.27915999f, -0.55781251f, 0.83104002f, + 0.14356995f, -0.55781251f, 0.86373001f, + 0.00000000f, -0.55781251f, 0.87500000f, + 0.83800000f, -0.59160000f, -0.00000001f, + 0.82720655f, -0.59159994f, 0.13749902f, + 0.79589891f, -0.59160000f, 0.26735553f, + 0.74568588f, -0.59160000f, 0.38796049f, + 0.67817670f, -0.59160006f, 0.49770495f, + 0.59498000f, -0.59160000f, 0.59497994f, + 0.49770495f, -0.59160000f, 0.67817664f, + 0.38796049f, -0.59160006f, 0.74568594f, + 0.26735550f, -0.59160000f, 0.79589891f, + 0.13749899f, -0.59160000f, 0.82720655f, + 0.00000000f, -0.59160000f, 0.83800000f, + 0.80400008f, -0.61998749f, -0.00000001f, + 0.79364455f, -0.61998743f, 0.13192031f, + 0.76360714f, -0.61998749f, 0.25650817f, + 0.71543139f, -0.61998749f, 0.37221986f, + 0.65066117f, -0.61998749f, 0.47751173f, + 0.57084000f, -0.61998749f, 0.57084000f, + 0.47751170f, -0.61998749f, 0.65066117f, + 0.37221986f, -0.61998749f, 0.71543145f, + 0.25650814f, -0.61998749f, 0.76360714f, + 0.13192026f, -0.61998749f, 0.79364455f, + 0.00000000f, -0.61998749f, 0.80400008f, + 0.77600002f, -0.64320004f, -0.00000001f, + 0.76600504f, -0.64319998f, 0.12732607f, + 0.73701382f, -0.64320010f, 0.24757506f, + 0.69051588f, -0.64320004f, 0.35925698f, + 0.62800133f, -0.64320010f, 0.46088195f, + 0.55096000f, -0.64320004f, 0.55096000f, + 0.46088192f, -0.64320004f, 0.62800133f, + 0.35925698f, -0.64320004f, 0.69051588f, + 0.24757503f, -0.64320004f, 0.73701382f, + 0.12732603f, -0.64320004f, 0.76600516f, + 0.00000000f, -0.64320004f, 0.77600002f, + 0.75699997f, -0.66146249f, -0.00000001f, + 0.74724966f, -0.66146243f, 0.12420854f, + 0.71896833f, -0.66146255f, 0.24151328f, + 0.67360884f, -0.66146243f, 0.35046071f, + 0.61262494f, -0.66146255f, 0.44959745f, + 0.53746998f, -0.66146249f, 0.53746998f, + 0.44959742f, -0.66146249f, 0.61262494f, + 0.35046071f, -0.66146249f, 0.67360890f, + 0.24151327f, -0.66146255f, 0.71896827f, + 0.12420851f, -0.66146249f, 0.74724984f, + 0.00000000f, -0.66146249f, 0.75699997f, + 0.75000000f, -0.67500001f, -0.00000001f, + 0.74033999f, -0.67499995f, 0.12305998f, + 0.71232003f, -0.67500007f, 0.23928000f, + 0.66737998f, -0.67500001f, 0.34721997f, + 0.60696000f, -0.67500007f, 0.44544002f, + 0.53250003f, -0.67500007f, 0.53250003f, + 0.44543999f, -0.67500001f, 0.60696000f, + 0.34722000f, -0.67500001f, 0.66738003f, + 0.23927999f, -0.67500001f, 0.71231997f, + 0.12305996f, -0.67500001f, 0.74033999f, + 0.00000000f, -0.67500001f, 0.75000000f, + 0.00000000f, -0.30000001f, -1.00000000f, + 0.16407999f, -0.29999998f, -0.98711991f, + 0.31904000f, -0.30000004f, -0.94976002f, + 0.46296000f, -0.30000004f, -0.88984001f, + 0.59392005f, -0.30000001f, -0.80928004f, + 0.71000004f, -0.30000001f, -0.71000004f, + 0.80928004f, -0.30000001f, -0.59391999f, + 0.88984001f, -0.30000001f, -0.46296003f, + 0.94976002f, -0.30000001f, -0.31904000f, + 0.98712003f, -0.30000001f, -0.16407993f, + 1.00000000f, -0.30000001f, -0.00000000f, + 0.00000000f, -0.36416247f, -0.99299991f, + 0.16293143f, -0.36416242f, -0.98021001f, + 0.31680670f, -0.36416250f, -0.94311166f, + 0.45971927f, -0.36416245f, -0.88361102f, + 0.58976257f, -0.36416247f, -0.80361503f, + 0.70502996f, -0.36416247f, -0.70502996f, + 0.80361497f, -0.36416250f, -0.58976251f, + 0.88361108f, -0.36416247f, -0.45971930f, + 0.94311166f, -0.36416250f, -0.31680670f, + 0.98021007f, -0.36416247f, -0.16293137f, + 0.99299991f, -0.36416247f, -0.00000000f, + 0.00000000f, -0.42180002f, -0.97400004f, + 0.15981390f, -0.42179996f, -0.96145481f, + 0.31074497f, -0.42180005f, -0.92506635f, + 0.45092306f, -0.42180002f, -0.86670411f, + 0.57847816f, -0.42180005f, -0.78823876f, + 0.69154000f, -0.42180002f, -0.69154000f, + 0.78823876f, -0.42180002f, -0.57847810f, + 0.86670417f, -0.42180002f, -0.45092303f, + 0.92506629f, -0.42180002f, -0.31074494f, + 0.96145493f, -0.42180002f, -0.15981385f, + 0.97400004f, -0.42180002f, -0.00000001f, + 0.00000000f, -0.47313750f, -0.94600004f, + 0.15521967f, -0.47313747f, -0.93381548f, + 0.30181187f, -0.47313756f, -0.89847302f, + 0.43796018f, -0.47313750f, -0.84178865f, + 0.56184840f, -0.47313753f, -0.76557899f, + 0.67166001f, -0.47313750f, -0.67166001f, + 0.76557899f, -0.47313750f, -0.56184828f, + 0.84178865f, -0.47313750f, -0.43796021f, + 0.89847302f, -0.47313750f, -0.30181184f, + 0.93381560f, -0.47313750f, -0.15521961f, + 0.94600004f, -0.47313750f, -0.00000001f, + 0.00000000f, -0.51840001f, -0.91200000f, + 0.14964095f, -0.51839995f, -0.90025330f, + 0.29096451f, -0.51840001f, -0.86618114f, + 0.42221951f, -0.51840001f, -0.81153411f, + 0.54165506f, -0.51840007f, -0.73806345f, + 0.64752001f, -0.51840001f, -0.64752001f, + 0.73806340f, -0.51840001f, -0.54165506f, + 0.81153411f, -0.51840007f, -0.42221954f, + 0.86618114f, -0.51840007f, -0.29096448f, + 0.90025342f, -0.51840001f, -0.14964090f, + 0.91200000f, -0.51840001f, -0.00000001f, + 0.00000000f, -0.55781251f, -0.87500000f, + 0.14356999f, -0.55781251f, -0.86372989f, + 0.27916002f, -0.55781251f, -0.83104002f, + 0.40509003f, -0.55781251f, -0.77860999f, + 0.51968002f, -0.55781257f, -0.70812005f, + 0.62125003f, -0.55781251f, -0.62125003f, + 0.70812005f, -0.55781251f, -0.51967996f, + 0.77860999f, -0.55781257f, -0.40509003f, + 0.83104002f, -0.55781251f, -0.27915999f, + 0.86373001f, -0.55781251f, -0.14356995f, + 0.87500000f, -0.55781251f, -0.00000001f, + 0.00000000f, -0.59160000f, -0.83800000f, + 0.13749902f, -0.59159994f, -0.82720655f, + 0.26735553f, -0.59160000f, -0.79589891f, + 0.38796049f, -0.59160000f, -0.74568588f, + 0.49770495f, -0.59160006f, -0.67817670f, + 0.59497994f, -0.59160000f, -0.59498000f, + 0.67817664f, -0.59160000f, -0.49770495f, + 0.74568594f, -0.59160006f, -0.38796049f, + 0.79589891f, -0.59160000f, -0.26735550f, + 0.82720655f, -0.59160000f, -0.13749899f, + 0.83800000f, -0.59160000f, -0.00000001f, + 0.00000000f, -0.61998749f, -0.80400008f, + 0.13192032f, -0.61998743f, -0.79364455f, + 0.25650817f, -0.61998749f, -0.76360714f, + 0.37221986f, -0.61998749f, -0.71543139f, + 0.47751173f, -0.61998749f, -0.65066117f, + 0.57084000f, -0.61998749f, -0.57084000f, + 0.65066117f, -0.61998749f, -0.47751170f, + 0.71543145f, -0.61998749f, -0.37221986f, + 0.76360714f, -0.61998749f, -0.25650814f, + 0.79364455f, -0.61998749f, -0.13192026f, + 0.80400008f, -0.61998749f, -0.00000001f, + 0.00000000f, -0.64320004f, -0.77600002f, + 0.12732607f, -0.64319998f, -0.76600504f, + 0.24757506f, -0.64320010f, -0.73701382f, + 0.35925698f, -0.64320004f, -0.69051588f, + 0.46088195f, -0.64320010f, -0.62800133f, + 0.55096000f, -0.64320004f, -0.55096000f, + 0.62800133f, -0.64320004f, -0.46088192f, + 0.69051588f, -0.64320004f, -0.35925698f, + 0.73701382f, -0.64320004f, -0.24757503f, + 0.76600516f, -0.64320004f, -0.12732603f, + 0.77600002f, -0.64320004f, -0.00000001f, + 0.00000000f, -0.66146249f, -0.75699997f, + 0.12420855f, -0.66146243f, -0.74724966f, + 0.24151328f, -0.66146255f, -0.71896833f, + 0.35046071f, -0.66146243f, -0.67360884f, + 0.44959745f, -0.66146255f, -0.61262494f, + 0.53746998f, -0.66146249f, -0.53746998f, + 0.61262494f, -0.66146249f, -0.44959742f, + 0.67360890f, -0.66146249f, -0.35046071f, + 0.71896827f, -0.66146255f, -0.24151327f, + 0.74724984f, -0.66146249f, -0.12420852f, + 0.75699997f, -0.66146249f, -0.00000001f, + 0.00000000f, -0.67500001f, -0.75000000f, + 0.12305999f, -0.67499995f, -0.74033999f, + 0.23928000f, -0.67500007f, -0.71232003f, + 0.34721997f, -0.67500001f, -0.66737998f, + 0.44544002f, -0.67500007f, -0.60696000f, + 0.53250003f, -0.67500007f, -0.53250003f, + 0.60696000f, -0.67500001f, -0.44543999f, + 0.66738003f, -0.67500001f, -0.34722000f, + 0.71231997f, -0.67500001f, -0.23927999f, + 0.74033999f, -0.67500001f, -0.12305997f, + 0.75000000f, -0.67500001f, -0.00000001f, + 0.00000000f, -0.30000001f, 1.00000000f, + -0.16407999f, -0.29999998f, 0.98711991f, + -0.31904000f, -0.30000004f, 0.94976002f, + -0.46296000f, -0.30000004f, 0.88984001f, + -0.59392005f, -0.30000001f, 0.80928004f, + -0.71000004f, -0.30000001f, 0.71000004f, + -0.80928004f, -0.30000001f, 0.59391999f, + -0.88984001f, -0.30000001f, 0.46296003f, + -0.94976002f, -0.30000001f, 0.31904000f, + -0.98712003f, -0.30000001f, 0.16407993f, + -1.00000000f, -0.30000001f, -0.00000000f, + 0.00000000f, -0.36416247f, 0.99299991f, + -0.16293143f, -0.36416242f, 0.98021001f, + -0.31680670f, -0.36416250f, 0.94311166f, + -0.45971927f, -0.36416245f, 0.88361102f, + -0.58976257f, -0.36416247f, 0.80361503f, + -0.70502996f, -0.36416247f, 0.70502996f, + -0.80361497f, -0.36416250f, 0.58976251f, + -0.88361108f, -0.36416247f, 0.45971930f, + -0.94311166f, -0.36416250f, 0.31680670f, + -0.98021007f, -0.36416247f, 0.16293137f, + -0.99299991f, -0.36416247f, -0.00000000f, + 0.00000000f, -0.42180005f, 0.97400004f, + -0.15981390f, -0.42179999f, 0.96145481f, + -0.31074497f, -0.42180005f, 0.92506635f, + -0.45092306f, -0.42180002f, 0.86670411f, + -0.57847816f, -0.42180011f, 0.78823876f, + -0.69154000f, -0.42180008f, 0.69154000f, + -0.78823876f, -0.42180002f, 0.57847810f, + -0.86670417f, -0.42180005f, 0.45092303f, + -0.92506629f, -0.42180005f, 0.31074494f, + -0.96145493f, -0.42180002f, 0.15981385f, + -0.97400004f, -0.42180002f, -0.00000001f, + 0.00000000f, -0.47313753f, 0.94600004f, + -0.15521967f, -0.47313747f, 0.93381548f, + -0.30181187f, -0.47313756f, 0.89847302f, + -0.43796018f, -0.47313750f, 0.84178865f, + -0.56184840f, -0.47313753f, 0.76557899f, + -0.67166001f, -0.47313750f, 0.67166001f, + -0.76557899f, -0.47313753f, 0.56184828f, + -0.84178865f, -0.47313753f, 0.43796021f, + -0.89847302f, -0.47313750f, 0.30181184f, + -0.93381560f, -0.47313750f, 0.15521961f, + -0.94600004f, -0.47313750f, -0.00000001f, + 0.00000000f, -0.51840007f, 0.91200000f, + -0.14964095f, -0.51839995f, 0.90025330f, + -0.29096451f, -0.51840007f, 0.86618114f, + -0.42221951f, -0.51840007f, 0.81153411f, + -0.54165506f, -0.51840007f, 0.73806345f, + -0.64752001f, -0.51840007f, 0.64752001f, + -0.73806340f, -0.51840007f, 0.54165506f, + -0.81153411f, -0.51840007f, 0.42221954f, + -0.86618114f, -0.51840007f, 0.29096448f, + -0.90025342f, -0.51840001f, 0.14964090f, + -0.91200000f, -0.51840001f, -0.00000001f, + 0.00000000f, -0.55781251f, 0.87500000f, + -0.14356999f, -0.55781251f, 0.86372989f, + -0.27916002f, -0.55781251f, 0.83104002f, + -0.40509003f, -0.55781251f, 0.77860999f, + -0.51968002f, -0.55781257f, 0.70812005f, + -0.62125003f, -0.55781251f, 0.62125003f, + -0.70812005f, -0.55781251f, 0.51967996f, + -0.77860999f, -0.55781257f, 0.40509003f, + -0.83104002f, -0.55781251f, 0.27915999f, + -0.86373001f, -0.55781251f, 0.14356995f, + -0.87500000f, -0.55781251f, -0.00000001f, + 0.00000000f, -0.59160000f, 0.83800000f, + -0.13749902f, -0.59159994f, 0.82720655f, + -0.26735553f, -0.59160000f, 0.79589891f, + -0.38796049f, -0.59160000f, 0.74568588f, + -0.49770495f, -0.59160006f, 0.67817670f, + -0.59497994f, -0.59160000f, 0.59498000f, + -0.67817664f, -0.59160000f, 0.49770495f, + -0.74568594f, -0.59160006f, 0.38796049f, + -0.79589891f, -0.59160000f, 0.26735550f, + -0.82720655f, -0.59160000f, 0.13749899f, + -0.83800000f, -0.59160000f, -0.00000001f, + 0.00000000f, -0.61998749f, 0.80400008f, + -0.13192032f, -0.61998743f, 0.79364455f, + -0.25650817f, -0.61998749f, 0.76360714f, + -0.37221986f, -0.61998749f, 0.71543139f, + -0.47751173f, -0.61998749f, 0.65066117f, + -0.57084000f, -0.61998749f, 0.57084000f, + -0.65066117f, -0.61998749f, 0.47751170f, + -0.71543145f, -0.61998749f, 0.37221986f, + -0.76360714f, -0.61998749f, 0.25650814f, + -0.79364455f, -0.61998749f, 0.13192026f, + -0.80400008f, -0.61998749f, -0.00000001f, + 0.00000000f, -0.64320004f, 0.77600002f, + -0.12732607f, -0.64319998f, 0.76600504f, + -0.24757506f, -0.64320010f, 0.73701382f, + -0.35925698f, -0.64320004f, 0.69051588f, + -0.46088195f, -0.64320010f, 0.62800133f, + -0.55096000f, -0.64320004f, 0.55096000f, + -0.62800133f, -0.64320004f, 0.46088192f, + -0.69051588f, -0.64320004f, 0.35925698f, + -0.73701382f, -0.64320004f, 0.24757503f, + -0.76600516f, -0.64320004f, 0.12732603f, + -0.77600002f, -0.64320004f, -0.00000001f, + 0.00000000f, -0.66146249f, 0.75699997f, + -0.12420855f, -0.66146243f, 0.74724966f, + -0.24151328f, -0.66146255f, 0.71896833f, + -0.35046071f, -0.66146243f, 0.67360884f, + -0.44959745f, -0.66146255f, 0.61262494f, + -0.53746998f, -0.66146249f, 0.53746998f, + -0.61262494f, -0.66146249f, 0.44959742f, + -0.67360890f, -0.66146249f, 0.35046071f, + -0.71896827f, -0.66146255f, 0.24151327f, + -0.74724984f, -0.66146249f, 0.12420850f, + -0.75699997f, -0.66146249f, -0.00000001f, + 0.00000000f, -0.67500001f, 0.75000000f, + -0.12305999f, -0.67499995f, 0.74033999f, + -0.23928000f, -0.67500007f, 0.71232003f, + -0.34721997f, -0.67500001f, 0.66737998f, + -0.44544002f, -0.67500007f, 0.60696000f, + -0.53250003f, -0.67500007f, 0.53250003f, + -0.60696000f, -0.67500001f, 0.44543999f, + -0.66738003f, -0.67500001f, 0.34722000f, + -0.71231997f, -0.67500001f, 0.23927999f, + -0.74033999f, -0.67500001f, 0.12305995f, + -0.75000000f, -0.67500001f, -0.00000001f, + -1.00000000f, -0.30000001f, -0.00000000f, + -0.98711991f, -0.29999998f, -0.16407999f, + -0.94976002f, -0.30000004f, -0.31904000f, + -0.88984001f, -0.30000004f, -0.46296000f, + -0.80928004f, -0.30000001f, -0.59392005f, + -0.71000004f, -0.30000001f, -0.71000004f, + -0.59391999f, -0.30000001f, -0.80928004f, + -0.46296003f, -0.30000001f, -0.88984001f, + -0.31904000f, -0.30000001f, -0.94976002f, + -0.16407993f, -0.30000001f, -0.98712003f, + 0.00000000f, -0.30000001f, -1.00000000f, + -0.99299991f, -0.36416247f, -0.00000000f, + -0.98021001f, -0.36416242f, -0.16293143f, + -0.94311166f, -0.36416250f, -0.31680670f, + -0.88361102f, -0.36416245f, -0.45971927f, + -0.80361503f, -0.36416247f, -0.58976257f, + -0.70502996f, -0.36416247f, -0.70502996f, + -0.58976251f, -0.36416250f, -0.80361497f, + -0.45971930f, -0.36416247f, -0.88361108f, + -0.31680670f, -0.36416250f, -0.94311166f, + -0.16293137f, -0.36416247f, -0.98021007f, + 0.00000000f, -0.36416247f, -0.99299991f, + -0.97400004f, -0.42180002f, -0.00000001f, + -0.96145481f, -0.42179996f, -0.15981390f, + -0.92506635f, -0.42180005f, -0.31074497f, + -0.86670411f, -0.42180002f, -0.45092306f, + -0.78823876f, -0.42180005f, -0.57847816f, + -0.69154000f, -0.42180002f, -0.69154000f, + -0.57847810f, -0.42180002f, -0.78823876f, + -0.45092303f, -0.42180002f, -0.86670417f, + -0.31074494f, -0.42180002f, -0.92506629f, + -0.15981385f, -0.42180002f, -0.96145493f, + 0.00000000f, -0.42180002f, -0.97400004f, + -0.94600004f, -0.47313750f, -0.00000001f, + -0.93381548f, -0.47313747f, -0.15521967f, + -0.89847302f, -0.47313756f, -0.30181187f, + -0.84178865f, -0.47313750f, -0.43796018f, + -0.76557899f, -0.47313753f, -0.56184840f, + -0.67166001f, -0.47313750f, -0.67166001f, + -0.56184828f, -0.47313750f, -0.76557899f, + -0.43796021f, -0.47313750f, -0.84178865f, + -0.30181184f, -0.47313750f, -0.89847302f, + -0.15521961f, -0.47313750f, -0.93381560f, + 0.00000000f, -0.47313750f, -0.94600004f, + -0.91200000f, -0.51840001f, -0.00000001f, + -0.90025330f, -0.51839995f, -0.14964096f, + -0.86618114f, -0.51840001f, -0.29096451f, + -0.81153411f, -0.51840001f, -0.42221951f, + -0.73806345f, -0.51840007f, -0.54165506f, + -0.64752001f, -0.51840001f, -0.64752001f, + -0.54165506f, -0.51840001f, -0.73806340f, + -0.42221954f, -0.51840007f, -0.81153411f, + -0.29096448f, -0.51840007f, -0.86618114f, + -0.14964090f, -0.51840001f, -0.90025342f, + 0.00000000f, -0.51840001f, -0.91200000f, + -0.87500000f, -0.55781251f, -0.00000001f, + -0.86372989f, -0.55781251f, -0.14357001f, + -0.83104002f, -0.55781251f, -0.27916002f, + -0.77860999f, -0.55781251f, -0.40509003f, + -0.70812005f, -0.55781257f, -0.51968002f, + -0.62125003f, -0.55781251f, -0.62125003f, + -0.51967996f, -0.55781251f, -0.70812005f, + -0.40509003f, -0.55781257f, -0.77860999f, + -0.27915999f, -0.55781251f, -0.83104002f, + -0.14356995f, -0.55781251f, -0.86373001f, + 0.00000000f, -0.55781251f, -0.87500000f, + -0.83800000f, -0.59160000f, -0.00000001f, + -0.82720655f, -0.59159994f, -0.13749903f, + -0.79589891f, -0.59160000f, -0.26735553f, + -0.74568588f, -0.59160000f, -0.38796049f, + -0.67817670f, -0.59160006f, -0.49770495f, + -0.59498000f, -0.59160000f, -0.59497994f, + -0.49770495f, -0.59160000f, -0.67817664f, + -0.38796049f, -0.59160006f, -0.74568594f, + -0.26735550f, -0.59160000f, -0.79589891f, + -0.13749899f, -0.59160000f, -0.82720655f, + 0.00000000f, -0.59160000f, -0.83800000f, + -0.80400008f, -0.61998749f, -0.00000001f, + -0.79364455f, -0.61998743f, -0.13192032f, + -0.76360714f, -0.61998749f, -0.25650817f, + -0.71543139f, -0.61998749f, -0.37221986f, + -0.65066117f, -0.61998749f, -0.47751173f, + -0.57084000f, -0.61998749f, -0.57084000f, + -0.47751170f, -0.61998749f, -0.65066117f, + -0.37221986f, -0.61998749f, -0.71543145f, + -0.25650814f, -0.61998749f, -0.76360714f, + -0.13192026f, -0.61998749f, -0.79364455f, + 0.00000000f, -0.61998749f, -0.80400008f, + -0.77600002f, -0.64320004f, -0.00000001f, + -0.76600504f, -0.64319998f, -0.12732607f, + -0.73701382f, -0.64320010f, -0.24757506f, + -0.69051588f, -0.64320004f, -0.35925698f, + -0.62800133f, -0.64320010f, -0.46088195f, + -0.55096000f, -0.64320004f, -0.55096000f, + -0.46088192f, -0.64320004f, -0.62800133f, + -0.35925698f, -0.64320004f, -0.69051588f, + -0.24757503f, -0.64320004f, -0.73701382f, + -0.12732603f, -0.64320004f, -0.76600516f, + 0.00000000f, -0.64320004f, -0.77600002f, + -0.75699997f, -0.66146249f, -0.00000001f, + -0.74724966f, -0.66146243f, -0.12420855f, + -0.71896833f, -0.66146255f, -0.24151328f, + -0.67360884f, -0.66146243f, -0.35046071f, + -0.61262494f, -0.66146255f, -0.44959745f, + -0.53746998f, -0.66146249f, -0.53746998f, + -0.44959742f, -0.66146249f, -0.61262494f, + -0.35046071f, -0.66146249f, -0.67360890f, + -0.24151327f, -0.66146255f, -0.71896827f, + -0.12420851f, -0.66146249f, -0.74724984f, + 0.00000000f, -0.66146249f, -0.75699997f, + -0.75000000f, -0.67500001f, -0.00000001f, + -0.74033999f, -0.67499995f, -0.12306000f, + -0.71232003f, -0.67500007f, -0.23928000f, + -0.66737998f, -0.67500001f, -0.34721997f, + -0.60696000f, -0.67500007f, -0.44544002f, + -0.53250003f, -0.67500007f, -0.53250003f, + -0.44543999f, -0.67500001f, -0.60696000f, + -0.34722000f, -0.67500001f, -0.66738003f, + -0.23927999f, -0.67500001f, -0.71231997f, + -0.12305996f, -0.67500001f, -0.74033999f, + 0.00000000f, -0.67500001f, -0.75000000f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500017f, 0.00000001f, + 0.00000000f, 0.82500011f, 0.00000001f, + 0.00000000f, 0.82500011f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.09730000f, 0.82072502f, 0.00000001f, + 0.09605332f, 0.82072490f, 0.01602404f, + 0.09243499f, 0.82072508f, 0.03113591f, + 0.08662736f, 0.82072502f, 0.04515318f, + 0.07881293f, 0.82072508f, 0.05789340f, + 0.06917413f, 0.82072502f, 0.06917413f, + 0.05789339f, 0.82072502f, 0.07881294f, + 0.04515317f, 0.82072508f, 0.08662736f, + 0.03113590f, 0.82072502f, 0.09243499f, + 0.01602403f, 0.82072502f, 0.09605335f, + 0.00000000f, 0.82072502f, 0.09730001f, + 0.15440002f, 0.80880016f, 0.00000001f, + 0.15242170f, 0.80880004f, 0.02542728f, + 0.14667983f, 0.80880022f, 0.04940725f, + 0.13746388f, 0.80880022f, 0.07165039f, + 0.12506345f, 0.80880028f, 0.09186716f, + 0.10976801f, 0.80880016f, 0.10976802f, + 0.09186715f, 0.80880016f, 0.12506345f, + 0.07165038f, 0.80880022f, 0.13746390f, + 0.04940724f, 0.80880022f, 0.14667983f, + 0.02542726f, 0.80880016f, 0.15242171f, + 0.00000000f, 0.80880016f, 0.15440002f, + 0.17909999f, 0.79057503f, 0.00000001f, + 0.17680508f, 0.79057491f, 0.02949390f, + 0.17014435f, 0.79057509f, 0.05730941f, + 0.15945368f, 0.79057509f, 0.08311062f, + 0.14506906f, 0.79057503f, 0.10656159f, + 0.12732637f, 0.79057503f, 0.12732637f, + 0.10656157f, 0.79057503f, 0.14506905f, + 0.08311062f, 0.79057503f, 0.15945369f, + 0.05730940f, 0.79057503f, 0.17014435f, + 0.02949388f, 0.79057503f, 0.17680509f, + 0.00000000f, 0.79057503f, 0.17909999f, + 0.17920001f, 0.76740009f, 0.00000001f, + 0.17690356f, 0.76740003f, 0.02950812f, + 0.17023848f, 0.76740015f, 0.05733787f, + 0.15954098f, 0.76740009f, 0.08315296f, + 0.14514741f, 0.76740015f, 0.10661709f, + 0.12739401f, 0.76740009f, 0.12739401f, + 0.10661709f, 0.76740009f, 0.14514741f, + 0.08315295f, 0.76740009f, 0.15954098f, + 0.05733785f, 0.76740015f, 0.17023847f, + 0.02950810f, 0.76740009f, 0.17690358f, + 0.00000000f, 0.76740009f, 0.17920001f, + 0.16250001f, 0.74062496f, 0.00000001f, + 0.16041712f, 0.74062496f, 0.02675413f, + 0.15437202f, 0.74062502f, 0.05198801f, + 0.14466989f, 0.74062496f, 0.07539638f, + 0.13161601f, 0.74062496f, 0.09667401f, + 0.11551563f, 0.74062496f, 0.11551563f, + 0.09667400f, 0.74062496f, 0.13161600f, + 0.07539637f, 0.74062502f, 0.14466989f, + 0.05198800f, 0.74062502f, 0.15437201f, + 0.02675411f, 0.74062496f, 0.16041712f, + 0.00000000f, 0.74062496f, 0.16250001f, + 0.13680001f, 0.71160007f, 0.00000001f, + 0.13504578f, 0.71160001f, 0.02251614f, + 0.12995483f, 0.71160012f, 0.04375527f, + 0.12178454f, 0.71160007f, 0.06345994f, + 0.11079245f, 0.71160012f, 0.08137268f, + 0.09723600f, 0.71160007f, 0.09723601f, + 0.08137267f, 0.71160007f, 0.11079245f, + 0.06345994f, 0.71160007f, 0.12178455f, + 0.04375526f, 0.71160007f, 0.12995481f, + 0.02251612f, 0.71160007f, 0.13504580f, + 0.00000000f, 0.71160007f, 0.13680001f, + 0.10990001f, 0.68167502f, 0.00000001f, + 0.10848958f, 0.68167496f, 0.01807833f, + 0.10439678f, 0.68167502f, 0.03513508f, + 0.09782913f, 0.68167496f, 0.05096266f, + 0.08899431f, 0.68167502f, 0.06535347f, + 0.07809988f, 0.68167502f, 0.07809989f, + 0.06535345f, 0.68167502f, 0.08899432f, + 0.05096266f, 0.68167502f, 0.09782915f, + 0.03513507f, 0.68167502f, 0.10439678f, + 0.01807831f, 0.68167502f, 0.10848960f, + 0.00000000f, 0.68167502f, 0.10990001f, + 0.08960000f, 0.65219998f, 0.00000001f, + 0.08844854f, 0.65219992f, 0.01472490f, + 0.08510771f, 0.65220004f, 0.02862286f, + 0.07974781f, 0.65219998f, 0.04152356f, + 0.07253914f, 0.65219998f, 0.05325671f, + 0.06365200f, 0.65219998f, 0.06365201f, + 0.05325670f, 0.65219998f, 0.07253915f, + 0.04152355f, 0.65219998f, 0.07974782f, + 0.02862285f, 0.65219998f, 0.08510773f, + 0.01472489f, 0.65219998f, 0.08844855f, + 0.00000000f, 0.65219998f, 0.08960001f, + 0.08370000f, 0.62452501f, 0.00000001f, + 0.08262266f, 0.62452495f, 0.01374006f, + 0.07949751f, 0.62452501f, 0.02671403f, + 0.07448471f, 0.62452501f, 0.03876166f, + 0.06774452f, 0.62452507f, 0.04972278f, + 0.05943713f, 0.62452501f, 0.05943713f, + 0.04972277f, 0.62452501f, 0.06774452f, + 0.03876166f, 0.62452501f, 0.07448472f, + 0.02671402f, 0.62452501f, 0.07949752f, + 0.01374005f, 0.62452501f, 0.08262268f, + 0.00000000f, 0.62452501f, 0.08370001f, + 0.10000000f, 0.60000002f, 0.00000001f, + 0.09871199f, 0.59999996f, 0.01640801f, + 0.09497602f, 0.60000008f, 0.03190401f, + 0.08898400f, 0.60000008f, 0.04629601f, + 0.08092801f, 0.60000002f, 0.05939201f, + 0.07100000f, 0.60000002f, 0.07100001f, + 0.05939200f, 0.60000002f, 0.08092801f, + 0.04629600f, 0.60000002f, 0.08898401f, + 0.03190400f, 0.60000002f, 0.09497601f, + 0.01640799f, 0.60000002f, 0.09871200f, + 0.00000000f, 0.60000002f, 0.10000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500017f, 0.00000001f, + 0.00000000f, 0.82500011f, 0.00000001f, + 0.00000000f, 0.82500011f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82072502f, -0.09729999f, + 0.01602403f, 0.82072490f, -0.09605332f, + 0.03113590f, 0.82072508f, -0.09243497f, + 0.04515317f, 0.82072502f, -0.08662734f, + 0.05789339f, 0.82072508f, -0.07881292f, + 0.06917413f, 0.82072502f, -0.06917411f, + 0.07881293f, 0.82072502f, -0.05789338f, + 0.08662736f, 0.82072508f, -0.04515316f, + 0.09243498f, 0.82072502f, -0.03113589f, + 0.09605334f, 0.82072502f, -0.01602402f, + 0.09730000f, 0.82072502f, 0.00000001f, + 0.00000000f, 0.80880016f, -0.15440002f, + 0.02542727f, 0.80880004f, -0.15242170f, + 0.04940724f, 0.80880022f, -0.14667983f, + 0.07165038f, 0.80880022f, -0.13746388f, + 0.09186715f, 0.80880028f, -0.12506345f, + 0.10976800f, 0.80880016f, -0.10976801f, + 0.12506345f, 0.80880016f, -0.09186714f, + 0.13746388f, 0.80880022f, -0.07165038f, + 0.14667982f, 0.80880022f, -0.04940723f, + 0.15242171f, 0.80880016f, -0.02542725f, + 0.15440002f, 0.80880016f, 0.00000001f, + 0.00000000f, 0.79057503f, -0.17909999f, + 0.02949389f, 0.79057491f, -0.17680508f, + 0.05730940f, 0.79057509f, -0.17014435f, + 0.08311061f, 0.79057509f, -0.15945368f, + 0.10656158f, 0.79057503f, -0.14506905f, + 0.12732637f, 0.79057503f, -0.12732637f, + 0.14506905f, 0.79057503f, -0.10656157f, + 0.15945369f, 0.79057503f, -0.08311061f, + 0.17014435f, 0.79057503f, -0.05730939f, + 0.17680509f, 0.79057503f, -0.02949387f, + 0.17909999f, 0.79057503f, 0.00000001f, + 0.00000000f, 0.76740009f, -0.17920001f, + 0.02950811f, 0.76740003f, -0.17690356f, + 0.05733786f, 0.76740015f, -0.17023848f, + 0.08315294f, 0.76740009f, -0.15954097f, + 0.10661709f, 0.76740015f, -0.14514740f, + 0.12739401f, 0.76740009f, -0.12739399f, + 0.14514741f, 0.76740009f, -0.10661709f, + 0.15954098f, 0.76740009f, -0.08315295f, + 0.17023847f, 0.76740015f, -0.05733785f, + 0.17690358f, 0.76740009f, -0.02950809f, + 0.17920001f, 0.76740009f, 0.00000001f, + 0.00000000f, 0.74062496f, -0.16250001f, + 0.02675412f, 0.74062496f, -0.16041712f, + 0.05198800f, 0.74062502f, -0.15437202f, + 0.07539637f, 0.74062496f, -0.14466989f, + 0.09667401f, 0.74062496f, -0.13161601f, + 0.11551563f, 0.74062496f, -0.11551563f, + 0.13161600f, 0.74062496f, -0.09667400f, + 0.14466989f, 0.74062502f, -0.07539637f, + 0.15437201f, 0.74062502f, -0.05198799f, + 0.16041712f, 0.74062496f, -0.02675411f, + 0.16250001f, 0.74062496f, 0.00000001f, + 0.00000000f, 0.71160007f, -0.13679999f, + 0.02251613f, 0.71160001f, -0.13504578f, + 0.04375527f, 0.71160012f, -0.12995481f, + 0.06345994f, 0.71160007f, -0.12178454f, + 0.08137268f, 0.71160012f, -0.11079244f, + 0.09723600f, 0.71160007f, -0.09723599f, + 0.11079245f, 0.71160007f, -0.08137266f, + 0.12178455f, 0.71160007f, -0.06345993f, + 0.12995481f, 0.71160007f, -0.04375526f, + 0.13504580f, 0.71160007f, -0.02251611f, + 0.13680001f, 0.71160007f, 0.00000001f, + 0.00000000f, 0.68167502f, -0.10990000f, + 0.01807832f, 0.68167496f, -0.10848958f, + 0.03513507f, 0.68167502f, -0.10439678f, + 0.05096266f, 0.68167496f, -0.09782913f, + 0.06535346f, 0.68167502f, -0.08899431f, + 0.07809988f, 0.68167502f, -0.07809987f, + 0.08899431f, 0.68167502f, -0.06535345f, + 0.09782915f, 0.68167502f, -0.05096265f, + 0.10439678f, 0.68167502f, -0.03513506f, + 0.10848960f, 0.68167502f, -0.01807830f, + 0.10990001f, 0.68167502f, 0.00000001f, + 0.00000000f, 0.65219998f, -0.08960000f, + 0.01472490f, 0.65219992f, -0.08844854f, + 0.02862285f, 0.65220004f, -0.08510771f, + 0.04152355f, 0.65219998f, -0.07974780f, + 0.05325671f, 0.65219998f, -0.07253914f, + 0.06365199f, 0.65219998f, -0.06365199f, + 0.07253914f, 0.65219998f, -0.05325670f, + 0.07974781f, 0.65219998f, -0.04152355f, + 0.08510771f, 0.65219998f, -0.02862284f, + 0.08844854f, 0.65219998f, -0.01472488f, + 0.08960000f, 0.65219998f, 0.00000001f, + 0.00000000f, 0.62452501f, -0.08369999f, + 0.01374006f, 0.62452495f, -0.08262266f, + 0.02671402f, 0.62452501f, -0.07949750f, + 0.03876166f, 0.62452501f, -0.07448471f, + 0.04972277f, 0.62452507f, -0.06774451f, + 0.05943713f, 0.62452501f, -0.05943712f, + 0.06774452f, 0.62452501f, -0.04972276f, + 0.07448471f, 0.62452501f, -0.03876166f, + 0.07949751f, 0.62452501f, -0.02671401f, + 0.08262268f, 0.62452501f, -0.01374004f, + 0.08370000f, 0.62452501f, 0.00000001f, + 0.00000000f, 0.60000002f, -0.09999999f, + 0.01640800f, 0.59999996f, -0.09871199f, + 0.03190400f, 0.60000008f, -0.09497599f, + 0.04629600f, 0.60000008f, -0.08898398f, + 0.05939200f, 0.60000002f, -0.08092800f, + 0.07100000f, 0.60000002f, -0.07099999f, + 0.08092801f, 0.60000002f, -0.05939199f, + 0.08898400f, 0.60000002f, -0.04629600f, + 0.09497601f, 0.60000002f, -0.03190399f, + 0.09871200f, 0.60000002f, -0.01640799f, + 0.10000000f, 0.60000002f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500017f, 0.00000001f, + 0.00000000f, 0.82500011f, 0.00000001f, + 0.00000000f, 0.82500011f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82072502f, 0.09730001f, + -0.01602403f, 0.82072490f, 0.09605334f, + -0.03113590f, 0.82072508f, 0.09243499f, + -0.04515317f, 0.82072502f, 0.08662736f, + -0.05789339f, 0.82072508f, 0.07881294f, + -0.06917413f, 0.82072502f, 0.06917413f, + -0.07881293f, 0.82072502f, 0.05789340f, + -0.08662736f, 0.82072508f, 0.04515318f, + -0.09243498f, 0.82072502f, 0.03113591f, + -0.09605334f, 0.82072502f, 0.01602404f, + -0.09730000f, 0.82072502f, 0.00000001f, + 0.00000000f, 0.80880016f, 0.15440002f, + -0.02542727f, 0.80880004f, 0.15242170f, + -0.04940724f, 0.80880022f, 0.14667983f, + -0.07165038f, 0.80880022f, 0.13746390f, + -0.09186715f, 0.80880028f, 0.12506345f, + -0.10976800f, 0.80880016f, 0.10976802f, + -0.12506345f, 0.80880016f, 0.09186715f, + -0.13746388f, 0.80880022f, 0.07165039f, + -0.14667982f, 0.80880022f, 0.04940725f, + -0.15242171f, 0.80880016f, 0.02542727f, + -0.15440002f, 0.80880016f, 0.00000001f, + 0.00000000f, 0.79057503f, 0.17909999f, + -0.02949389f, 0.79057491f, 0.17680508f, + -0.05730940f, 0.79057509f, 0.17014435f, + -0.08311061f, 0.79057509f, 0.15945368f, + -0.10656158f, 0.79057503f, 0.14506906f, + -0.12732637f, 0.79057503f, 0.12732637f, + -0.14506905f, 0.79057503f, 0.10656157f, + -0.15945369f, 0.79057503f, 0.08311062f, + -0.17014435f, 0.79057503f, 0.05730941f, + -0.17680509f, 0.79057503f, 0.02949389f, + -0.17909999f, 0.79057503f, 0.00000001f, + 0.00000000f, 0.76740009f, 0.17920001f, + -0.02950811f, 0.76740003f, 0.17690358f, + -0.05733786f, 0.76740015f, 0.17023848f, + -0.08315294f, 0.76740009f, 0.15954098f, + -0.10661709f, 0.76740015f, 0.14514741f, + -0.12739401f, 0.76740009f, 0.12739401f, + -0.14514741f, 0.76740009f, 0.10661709f, + -0.15954098f, 0.76740009f, 0.08315295f, + -0.17023847f, 0.76740015f, 0.05733786f, + -0.17690358f, 0.76740009f, 0.02950811f, + -0.17920001f, 0.76740009f, 0.00000001f, + 0.00000000f, 0.74062496f, 0.16250001f, + -0.02675412f, 0.74062496f, 0.16041712f, + -0.05198800f, 0.74062502f, 0.15437202f, + -0.07539637f, 0.74062496f, 0.14466989f, + -0.09667401f, 0.74062496f, 0.13161601f, + -0.11551563f, 0.74062496f, 0.11551563f, + -0.13161600f, 0.74062496f, 0.09667400f, + -0.14466989f, 0.74062502f, 0.07539638f, + -0.15437201f, 0.74062502f, 0.05198800f, + -0.16041712f, 0.74062496f, 0.02675412f, + -0.16250001f, 0.74062496f, 0.00000001f, + 0.00000000f, 0.71160007f, 0.13680001f, + -0.02251613f, 0.71160001f, 0.13504578f, + -0.04375527f, 0.71160012f, 0.12995483f, + -0.06345994f, 0.71160007f, 0.12178455f, + -0.08137268f, 0.71160012f, 0.11079246f, + -0.09723600f, 0.71160007f, 0.09723601f, + -0.11079245f, 0.71160007f, 0.08137267f, + -0.12178455f, 0.71160007f, 0.06345994f, + -0.12995481f, 0.71160007f, 0.04375527f, + -0.13504580f, 0.71160007f, 0.02251613f, + -0.13680001f, 0.71160007f, 0.00000001f, + 0.00000000f, 0.68167502f, 0.10990001f, + -0.01807832f, 0.68167496f, 0.10848960f, + -0.03513507f, 0.68167502f, 0.10439679f, + -0.05096266f, 0.68167496f, 0.09782915f, + -0.06535346f, 0.68167502f, 0.08899432f, + -0.07809988f, 0.68167502f, 0.07809988f, + -0.08899431f, 0.68167502f, 0.06535346f, + -0.09782915f, 0.68167502f, 0.05096267f, + -0.10439678f, 0.68167502f, 0.03513508f, + -0.10848960f, 0.68167502f, 0.01807832f, + -0.10990001f, 0.68167502f, 0.00000001f, + 0.00000000f, 0.65219998f, 0.08960001f, + -0.01472490f, 0.65219992f, 0.08844855f, + -0.02862285f, 0.65220004f, 0.08510773f, + -0.04152355f, 0.65219998f, 0.07974782f, + -0.05325671f, 0.65219998f, 0.07253915f, + -0.06365199f, 0.65219998f, 0.06365201f, + -0.07253914f, 0.65219998f, 0.05325671f, + -0.07974781f, 0.65219998f, 0.04152356f, + -0.08510771f, 0.65219998f, 0.02862286f, + -0.08844854f, 0.65219998f, 0.01472490f, + -0.08960000f, 0.65219998f, 0.00000001f, + 0.00000000f, 0.62452501f, 0.08370001f, + -0.01374006f, 0.62452495f, 0.08262267f, + -0.02671402f, 0.62452501f, 0.07949752f, + -0.03876166f, 0.62452501f, 0.07448472f, + -0.04972277f, 0.62452507f, 0.06774452f, + -0.05943713f, 0.62452501f, 0.05943713f, + -0.06774452f, 0.62452501f, 0.04972278f, + -0.07448471f, 0.62452501f, 0.03876167f, + -0.07949751f, 0.62452501f, 0.02671402f, + -0.08262268f, 0.62452501f, 0.01374006f, + -0.08370000f, 0.62452501f, 0.00000001f, + 0.00000000f, 0.60000002f, 0.10000001f, + -0.01640800f, 0.59999996f, 0.09871200f, + -0.03190400f, 0.60000008f, 0.09497602f, + -0.04629600f, 0.60000008f, 0.08898401f, + -0.05939200f, 0.60000002f, 0.08092801f, + -0.07100000f, 0.60000002f, 0.07100001f, + -0.08092801f, 0.60000002f, 0.05939201f, + -0.08898400f, 0.60000002f, 0.04629601f, + -0.09497601f, 0.60000002f, 0.03190401f, + -0.09871200f, 0.60000002f, 0.01640800f, + -0.10000000f, 0.60000002f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500017f, 0.00000001f, + 0.00000000f, 0.82500011f, 0.00000001f, + 0.00000000f, 0.82500011f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + 0.00000000f, 0.82500005f, 0.00000001f, + -0.09730000f, 0.82072502f, 0.00000001f, + -0.09605332f, 0.82072490f, -0.01602402f, + -0.09243499f, 0.82072508f, -0.03113589f, + -0.08662736f, 0.82072502f, -0.04515316f, + -0.07881293f, 0.82072508f, -0.05789338f, + -0.06917413f, 0.82072502f, -0.06917411f, + -0.05789339f, 0.82072502f, -0.07881292f, + -0.04515317f, 0.82072508f, -0.08662735f, + -0.03113590f, 0.82072502f, -0.09243497f, + -0.01602403f, 0.82072502f, -0.09605333f, + 0.00000000f, 0.82072502f, -0.09729999f, + -0.15440002f, 0.80880016f, 0.00000001f, + -0.15242170f, 0.80880004f, -0.02542726f, + -0.14667983f, 0.80880022f, -0.04940723f, + -0.13746388f, 0.80880022f, -0.07165037f, + -0.12506345f, 0.80880028f, -0.09186714f, + -0.10976801f, 0.80880016f, -0.10976800f, + -0.09186715f, 0.80880016f, -0.12506345f, + -0.07165038f, 0.80880022f, -0.13746388f, + -0.04940724f, 0.80880022f, -0.14667982f, + -0.02542726f, 0.80880016f, -0.15242171f, + 0.00000000f, 0.80880016f, -0.15440002f, + -0.17909999f, 0.79057503f, 0.00000001f, + -0.17680508f, 0.79057491f, -0.02949388f, + -0.17014435f, 0.79057509f, -0.05730940f, + -0.15945368f, 0.79057509f, -0.08311061f, + -0.14506906f, 0.79057503f, -0.10656158f, + -0.12732637f, 0.79057503f, -0.12732637f, + -0.10656157f, 0.79057503f, -0.14506905f, + -0.08311062f, 0.79057503f, -0.15945369f, + -0.05730940f, 0.79057503f, -0.17014435f, + -0.02949388f, 0.79057503f, -0.17680509f, + 0.00000000f, 0.79057503f, -0.17909999f, + -0.17920001f, 0.76740009f, 0.00000001f, + -0.17690356f, 0.76740003f, -0.02950810f, + -0.17023848f, 0.76740015f, -0.05733785f, + -0.15954098f, 0.76740009f, -0.08315294f, + -0.14514741f, 0.76740015f, -0.10661709f, + -0.12739401f, 0.76740009f, -0.12739401f, + -0.10661709f, 0.76740009f, -0.14514740f, + -0.08315295f, 0.76740009f, -0.15954098f, + -0.05733785f, 0.76740015f, -0.17023847f, + -0.02950810f, 0.76740009f, -0.17690358f, + 0.00000000f, 0.76740009f, -0.17920001f, + -0.16250001f, 0.74062496f, 0.00000001f, + -0.16041712f, 0.74062496f, -0.02675412f, + -0.15437202f, 0.74062502f, -0.05198800f, + -0.14466989f, 0.74062496f, -0.07539637f, + -0.13161601f, 0.74062496f, -0.09667400f, + -0.11551563f, 0.74062496f, -0.11551563f, + -0.09667400f, 0.74062496f, -0.13161600f, + -0.07539637f, 0.74062502f, -0.14466989f, + -0.05198800f, 0.74062502f, -0.15437201f, + -0.02675411f, 0.74062496f, -0.16041712f, + 0.00000000f, 0.74062496f, -0.16250001f, + -0.13680001f, 0.71160007f, 0.00000001f, + -0.13504578f, 0.71160001f, -0.02251612f, + -0.12995483f, 0.71160012f, -0.04375526f, + -0.12178454f, 0.71160007f, -0.06345993f, + -0.11079245f, 0.71160012f, -0.08137267f, + -0.09723600f, 0.71160007f, -0.09723599f, + -0.08137267f, 0.71160007f, -0.11079245f, + -0.06345994f, 0.71160007f, -0.12178454f, + -0.04375526f, 0.71160007f, -0.12995481f, + -0.02251612f, 0.71160007f, -0.13504578f, + 0.00000000f, 0.71160007f, -0.13679999f, + -0.10990001f, 0.68167502f, 0.00000001f, + -0.10848958f, 0.68167496f, -0.01807831f, + -0.10439678f, 0.68167502f, -0.03513507f, + -0.09782913f, 0.68167496f, -0.05096265f, + -0.08899431f, 0.68167502f, -0.06535345f, + -0.07809988f, 0.68167502f, -0.07809987f, + -0.06535345f, 0.68167502f, -0.08899430f, + -0.05096266f, 0.68167502f, -0.09782913f, + -0.03513507f, 0.68167502f, -0.10439677f, + -0.01807831f, 0.68167502f, -0.10848959f, + 0.00000000f, 0.68167502f, -0.10990000f, + -0.08960000f, 0.65219998f, 0.00000001f, + -0.08844854f, 0.65219992f, -0.01472489f, + -0.08510771f, 0.65220004f, -0.02862284f, + -0.07974781f, 0.65219998f, -0.04152355f, + -0.07253914f, 0.65219998f, -0.05325670f, + -0.06365200f, 0.65219998f, -0.06365199f, + -0.05325670f, 0.65219998f, -0.07253914f, + -0.04152355f, 0.65219998f, -0.07974781f, + -0.02862285f, 0.65219998f, -0.08510771f, + -0.01472489f, 0.65219998f, -0.08844854f, + 0.00000000f, 0.65219998f, -0.08960000f, + -0.08370000f, 0.62452501f, 0.00000001f, + -0.08262266f, 0.62452495f, -0.01374005f, + -0.07949751f, 0.62452501f, -0.02671401f, + -0.07448471f, 0.62452501f, -0.03876165f, + -0.06774452f, 0.62452507f, -0.04972276f, + -0.05943713f, 0.62452501f, -0.05943712f, + -0.04972277f, 0.62452501f, -0.06774451f, + -0.03876166f, 0.62452501f, -0.07448471f, + -0.02671402f, 0.62452501f, -0.07949750f, + -0.01374005f, 0.62452501f, -0.08262267f, + 0.00000000f, 0.62452501f, -0.08369999f, + -0.10000000f, 0.60000002f, 0.00000001f, + -0.09871199f, 0.59999996f, -0.01640799f, + -0.09497602f, 0.60000008f, -0.03190399f, + -0.08898400f, 0.60000008f, -0.04629599f, + -0.08092801f, 0.60000002f, -0.05939199f, + -0.07100000f, 0.60000002f, -0.07099999f, + -0.05939200f, 0.60000002f, -0.08092800f, + -0.04629600f, 0.60000002f, -0.08898400f, + -0.03190400f, 0.60000002f, -0.09497599f, + -0.01640799f, 0.60000002f, -0.09871200f, + 0.00000000f, 0.60000002f, -0.09999999f, + 0.10000000f, 0.60000002f, 0.00000001f, + 0.09871199f, 0.59999996f, 0.01640801f, + 0.09497602f, 0.60000008f, 0.03190401f, + 0.08898400f, 0.60000008f, 0.04629601f, + 0.08092801f, 0.60000002f, 0.05939201f, + 0.07100000f, 0.60000002f, 0.07100001f, + 0.05939200f, 0.60000002f, 0.08092801f, + 0.04629600f, 0.60000002f, 0.08898401f, + 0.03190400f, 0.60000002f, 0.09497601f, + 0.01640799f, 0.60000002f, 0.09871200f, + 0.00000000f, 0.60000002f, 0.10000001f, + 0.13969998f, 0.57959992f, 0.00000001f, + 0.13790064f, 0.57959986f, 0.02292198f, + 0.13268146f, 0.57959998f, 0.04456990f, + 0.12431064f, 0.57959992f, 0.06467552f, + 0.11305641f, 0.57959998f, 0.08297063f, + 0.09918699f, 0.57959992f, 0.09918701f, + 0.08297062f, 0.57959992f, 0.11305644f, + 0.06467551f, 0.57959998f, 0.12431066f, + 0.04456988f, 0.57959992f, 0.13268149f, + 0.02292197f, 0.57959992f, 0.13790068f, + 0.00000000f, 0.57959992f, 0.13970001f, + 0.19560002f, 0.56280005f, 0.00000001f, + 0.19308068f, 0.56279999f, 0.03209405f, + 0.18577307f, 0.56280011f, 0.06240424f, + 0.17405272f, 0.56280005f, 0.09055499f, + 0.15829518f, 0.56280005f, 0.11617076f, + 0.13887602f, 0.56280005f, 0.13887601f, + 0.11617076f, 0.56280005f, 0.15829518f, + 0.09055499f, 0.56280005f, 0.17405272f, + 0.06240423f, 0.56280005f, 0.18577307f, + 0.03209404f, 0.56280005f, 0.19308069f, + 0.00000000f, 0.56280005f, 0.19560002f, + 0.26289999f, 0.54869998f, 0.00000001f, + 0.25951380f, 0.54869998f, 0.04313663f, + 0.24969190f, 0.54869998f, 0.08387563f, + 0.23393893f, 0.54870003f, 0.12171219f, + 0.21275970f, 0.54869998f, 0.15614158f, + 0.18665901f, 0.54869998f, 0.18665899f, + 0.15614155f, 0.54869998f, 0.21275972f, + 0.12171219f, 0.54869998f, 0.23393893f, + 0.08387562f, 0.54869998f, 0.24969190f, + 0.04313662f, 0.54869998f, 0.25951385f, + 0.00000000f, 0.54869998f, 0.26289999f, + 0.33680001f, 0.53640002f, 0.00000001f, + 0.33246198f, 0.53639996f, 0.05526215f, + 0.31987920f, 0.53640002f, 0.10745268f, + 0.29969811f, 0.53640002f, 0.15592493f, + 0.27256551f, 0.53640002f, 0.20003228f, + 0.23912801f, 0.53640002f, 0.23912801f, + 0.20003226f, 0.53640002f, 0.27256551f, + 0.15592495f, 0.53640008f, 0.29969811f, + 0.10745268f, 0.53640008f, 0.31987917f, + 0.05526213f, 0.53640002f, 0.33246201f, + 0.00000000f, 0.53640002f, 0.33680001f, + 0.41250002f, 0.52499998f, 0.00000001f, + 0.40718701f, 0.52499992f, 0.06768300f, + 0.39177606f, 0.52499998f, 0.13160400f, + 0.36705902f, 0.52499998f, 0.19097100f, + 0.33382803f, 0.52499998f, 0.24499202f, + 0.29287499f, 0.52499998f, 0.29287499f, + 0.24499199f, 0.52499998f, 0.33382803f, + 0.19097102f, 0.52499998f, 0.36705902f, + 0.13160400f, 0.52499998f, 0.39177603f, + 0.06768297f, 0.52499998f, 0.40718701f, + 0.00000000f, 0.52499998f, 0.41250002f, + 0.48519999f, 0.51359999f, 0.00000001f, + 0.47895056f, 0.51359999f, 0.07961162f, + 0.46082360f, 0.51359999f, 0.15479822f, + 0.43175036f, 0.51359999f, 0.22462820f, + 0.39266267f, 0.51360005f, 0.28817001f, + 0.34449199f, 0.51359999f, 0.34449199f, + 0.28816998f, 0.51359999f, 0.39266264f, + 0.22462821f, 0.51359999f, 0.43175036f, + 0.15479821f, 0.51359999f, 0.46082354f, + 0.07961158f, 0.51359999f, 0.47895062f, + 0.00000000f, 0.51359999f, 0.48519999f, + 0.55009997f, 0.50129998f, 0.00000001f, + 0.54301465f, 0.50129992f, 0.09026041f, + 0.52246296f, 0.50129998f, 0.17550392f, + 0.48950094f, 0.50129998f, 0.25467429f, + 0.44518495f, 0.50129998f, 0.32671541f, + 0.39057100f, 0.50129998f, 0.39057100f, + 0.32671538f, 0.50129998f, 0.44518495f, + 0.25467432f, 0.50129998f, 0.48950097f, + 0.17550389f, 0.50129998f, 0.52246296f, + 0.09026037f, 0.50129998f, 0.54301471f, + 0.00000000f, 0.50129998f, 0.55009997f, + 0.60240000f, 0.48720002f, 0.00000001f, + 0.59464109f, 0.48719996f, 0.09884179f, + 0.57213551f, 0.48720005f, 0.19218971f, + 0.53603959f, 0.48719999f, 0.27888709f, + 0.48751029f, 0.48720002f, 0.35777742f, + 0.42770401f, 0.48720002f, 0.42770401f, + 0.35777742f, 0.48720002f, 0.48751026f, + 0.27888709f, 0.48720005f, 0.53603959f, + 0.19218969f, 0.48720002f, 0.57213545f, + 0.09884176f, 0.48720002f, 0.59464109f, + 0.00000000f, 0.48720002f, 0.60240000f, + 0.63730001f, 0.47040004f, 0.00000001f, + 0.62909156f, 0.47039998f, 0.10456818f, + 0.60528207f, 0.47040007f, 0.20332420f, + 0.56709504f, 0.47040001f, 0.29504442f, + 0.51575416f, 0.47040004f, 0.37850523f, + 0.45248300f, 0.47040004f, 0.45248300f, + 0.37850523f, 0.47040004f, 0.51575416f, + 0.29504442f, 0.47040004f, 0.56709504f, + 0.20332420f, 0.47040004f, 0.60528207f, + 0.10456815f, 0.47040004f, 0.62909162f, + 0.00000000f, 0.47040004f, 0.63730001f, + 0.64999998f, 0.45000005f, 0.00000001f, + 0.64162791f, 0.44999996f, 0.10665201f, + 0.61734402f, 0.45000011f, 0.20737600f, + 0.57839590f, 0.45000002f, 0.30092400f, + 0.52603197f, 0.45000008f, 0.38604802f, + 0.46149999f, 0.45000005f, 0.46149999f, + 0.38604796f, 0.45000005f, 0.52603197f, + 0.30092400f, 0.45000008f, 0.57839596f, + 0.20737599f, 0.45000005f, 0.61734402f, + 0.10665196f, 0.45000005f, 0.64162797f, + 0.00000000f, 0.45000005f, 0.64999998f, + 0.00000000f, 0.60000002f, -0.09999999f, + 0.01640800f, 0.59999996f, -0.09871199f, + 0.03190400f, 0.60000008f, -0.09497599f, + 0.04629600f, 0.60000008f, -0.08898398f, + 0.05939200f, 0.60000002f, -0.08092800f, + 0.07100000f, 0.60000002f, -0.07099999f, + 0.08092801f, 0.60000002f, -0.05939199f, + 0.08898400f, 0.60000002f, -0.04629600f, + 0.09497601f, 0.60000002f, -0.03190399f, + 0.09871200f, 0.60000002f, -0.01640799f, + 0.10000000f, 0.60000002f, 0.00000001f, + 0.00000000f, 0.57959992f, -0.13969998f, + 0.02292197f, 0.57959986f, -0.13790064f, + 0.04456988f, 0.57959998f, -0.13268146f, + 0.06467551f, 0.57959992f, -0.12431064f, + 0.08297062f, 0.57959998f, -0.11305641f, + 0.09918699f, 0.57959992f, -0.09918699f, + 0.11305641f, 0.57959992f, -0.08297061f, + 0.12431064f, 0.57959998f, -0.06467551f, + 0.13268146f, 0.57959992f, -0.04456988f, + 0.13790065f, 0.57959992f, -0.02292196f, + 0.13969998f, 0.57959992f, 0.00000001f, + 0.00000000f, 0.56280005f, -0.19560000f, + 0.03209405f, 0.56279999f, -0.19308066f, + 0.06240423f, 0.56280011f, -0.18577306f, + 0.09055499f, 0.56280005f, -0.17405270f, + 0.11617076f, 0.56280005f, -0.15829517f, + 0.13887601f, 0.56280005f, -0.13887601f, + 0.15829518f, 0.56280005f, -0.11617075f, + 0.17405272f, 0.56280005f, -0.09055498f, + 0.18577307f, 0.56280005f, -0.06240422f, + 0.19308069f, 0.56280005f, -0.03209403f, + 0.19560002f, 0.56280005f, 0.00000001f, + 0.00000000f, 0.54869998f, -0.26289999f, + 0.04313663f, 0.54869998f, -0.25951380f, + 0.08387563f, 0.54869998f, -0.24969190f, + 0.12171219f, 0.54870003f, -0.23393893f, + 0.15614158f, 0.54869998f, -0.21275970f, + 0.18665899f, 0.54869998f, -0.18665899f, + 0.21275972f, 0.54869998f, -0.15614155f, + 0.23393893f, 0.54869998f, -0.12171219f, + 0.24969190f, 0.54869998f, -0.08387561f, + 0.25951385f, 0.54869998f, -0.04313661f, + 0.26289999f, 0.54869998f, 0.00000001f, + 0.00000000f, 0.53640002f, -0.33680001f, + 0.05526214f, 0.53639996f, -0.33246198f, + 0.10745268f, 0.53640002f, -0.31987920f, + 0.15592493f, 0.53640002f, -0.29969811f, + 0.20003228f, 0.53640002f, -0.27256551f, + 0.23912801f, 0.53640002f, -0.23912799f, + 0.27256551f, 0.53640002f, -0.20003225f, + 0.29969811f, 0.53640008f, -0.15592495f, + 0.31987917f, 0.53640008f, -0.10745267f, + 0.33246201f, 0.53640002f, -0.05526212f, + 0.33680001f, 0.53640002f, 0.00000001f, + 0.00000000f, 0.52499998f, -0.41250002f, + 0.06768300f, 0.52499992f, -0.40718701f, + 0.13160400f, 0.52499998f, -0.39177606f, + 0.19097100f, 0.52499998f, -0.36705902f, + 0.24499202f, 0.52499998f, -0.33382803f, + 0.29287499f, 0.52499998f, -0.29287499f, + 0.33382803f, 0.52499998f, -0.24499199f, + 0.36705902f, 0.52499998f, -0.19097102f, + 0.39177603f, 0.52499998f, -0.13160400f, + 0.40718701f, 0.52499998f, -0.06768297f, + 0.41250002f, 0.52499998f, 0.00000001f, + 0.00000000f, 0.51359999f, -0.48519999f, + 0.07961161f, 0.51359999f, -0.47895056f, + 0.15479822f, 0.51359999f, -0.46082360f, + 0.22462820f, 0.51359999f, -0.43175036f, + 0.28817001f, 0.51360005f, -0.39266267f, + 0.34449199f, 0.51359999f, -0.34449199f, + 0.39266264f, 0.51359999f, -0.28816998f, + 0.43175036f, 0.51359999f, -0.22462821f, + 0.46082354f, 0.51359999f, -0.15479821f, + 0.47895062f, 0.51359999f, -0.07961158f, + 0.48519999f, 0.51359999f, 0.00000001f, + 0.00000000f, 0.50129998f, -0.55009997f, + 0.09026040f, 0.50129992f, -0.54301465f, + 0.17550392f, 0.50129998f, -0.52246296f, + 0.25467429f, 0.50129998f, -0.48950094f, + 0.32671541f, 0.50129998f, -0.44518495f, + 0.39057100f, 0.50129998f, -0.39057100f, + 0.44518495f, 0.50129998f, -0.32671538f, + 0.48950097f, 0.50129998f, -0.25467432f, + 0.52246296f, 0.50129998f, -0.17550389f, + 0.54301471f, 0.50129998f, -0.09026036f, + 0.55009997f, 0.50129998f, 0.00000001f, + 0.00000000f, 0.48720002f, -0.60240000f, + 0.09884179f, 0.48719996f, -0.59464109f, + 0.19218971f, 0.48720005f, -0.57213551f, + 0.27888709f, 0.48719999f, -0.53603959f, + 0.35777742f, 0.48720002f, -0.48751029f, + 0.42770401f, 0.48720002f, -0.42770401f, + 0.48751026f, 0.48720002f, -0.35777742f, + 0.53603959f, 0.48720005f, -0.27888709f, + 0.57213545f, 0.48720002f, -0.19218969f, + 0.59464109f, 0.48720002f, -0.09884175f, + 0.60240000f, 0.48720002f, 0.00000001f, + 0.00000000f, 0.47040004f, -0.63730001f, + 0.10456818f, 0.47039998f, -0.62909156f, + 0.20332420f, 0.47040007f, -0.60528207f, + 0.29504442f, 0.47040001f, -0.56709504f, + 0.37850523f, 0.47040004f, -0.51575416f, + 0.45248300f, 0.47040004f, -0.45248300f, + 0.51575416f, 0.47040004f, -0.37850523f, + 0.56709504f, 0.47040004f, -0.29504442f, + 0.60528207f, 0.47040004f, -0.20332420f, + 0.62909162f, 0.47040004f, -0.10456815f, + 0.63730001f, 0.47040004f, 0.00000001f, + 0.00000000f, 0.45000005f, -0.64999998f, + 0.10665200f, 0.44999996f, -0.64162791f, + 0.20737600f, 0.45000011f, -0.61734402f, + 0.30092400f, 0.45000002f, -0.57839590f, + 0.38604802f, 0.45000008f, -0.52603197f, + 0.46149999f, 0.45000005f, -0.46149999f, + 0.52603197f, 0.45000005f, -0.38604796f, + 0.57839596f, 0.45000008f, -0.30092400f, + 0.61734402f, 0.45000005f, -0.20737599f, + 0.64162797f, 0.45000005f, -0.10665195f, + 0.64999998f, 0.45000005f, 0.00000001f, + 0.00000000f, 0.60000002f, 0.10000001f, + -0.01640800f, 0.59999996f, 0.09871200f, + -0.03190400f, 0.60000008f, 0.09497602f, + -0.04629600f, 0.60000008f, 0.08898401f, + -0.05939200f, 0.60000002f, 0.08092801f, + -0.07100000f, 0.60000002f, 0.07100001f, + -0.08092801f, 0.60000002f, 0.05939201f, + -0.08898400f, 0.60000002f, 0.04629601f, + -0.09497601f, 0.60000002f, 0.03190401f, + -0.09871200f, 0.60000002f, 0.01640800f, + -0.10000000f, 0.60000002f, 0.00000001f, + 0.00000000f, 0.57959992f, 0.13970001f, + -0.02292197f, 0.57959986f, 0.13790067f, + -0.04456988f, 0.57959998f, 0.13268149f, + -0.06467551f, 0.57959992f, 0.12431065f, + -0.08297062f, 0.57959998f, 0.11305643f, + -0.09918699f, 0.57959992f, 0.09918701f, + -0.11305641f, 0.57959992f, 0.08297063f, + -0.12431064f, 0.57959998f, 0.06467552f, + -0.13268146f, 0.57959992f, 0.04456989f, + -0.13790065f, 0.57959992f, 0.02292197f, + -0.13969998f, 0.57959992f, 0.00000001f, + 0.00000000f, 0.56280005f, 0.19560002f, + -0.03209405f, 0.56279999f, 0.19308068f, + -0.06240423f, 0.56280011f, 0.18577307f, + -0.09055499f, 0.56280005f, 0.17405272f, + -0.11617076f, 0.56280005f, 0.15829518f, + -0.13887601f, 0.56280005f, 0.13887602f, + -0.15829518f, 0.56280005f, 0.11617076f, + -0.17405272f, 0.56280005f, 0.09055499f, + -0.18577307f, 0.56280005f, 0.06240423f, + -0.19308069f, 0.56280005f, 0.03209404f, + -0.19560002f, 0.56280005f, 0.00000001f, + 0.00000000f, 0.54869998f, 0.26289999f, + -0.04313663f, 0.54869998f, 0.25951380f, + -0.08387563f, 0.54869998f, 0.24969190f, + -0.12171219f, 0.54870003f, 0.23393893f, + -0.15614158f, 0.54869998f, 0.21275970f, + -0.18665899f, 0.54869998f, 0.18665901f, + -0.21275972f, 0.54869998f, 0.15614155f, + -0.23393893f, 0.54869998f, 0.12171219f, + -0.24969190f, 0.54869998f, 0.08387562f, + -0.25951385f, 0.54869998f, 0.04313662f, + -0.26289999f, 0.54869998f, 0.00000001f, + 0.00000000f, 0.53640002f, 0.33680001f, + -0.05526214f, 0.53639996f, 0.33246198f, + -0.10745268f, 0.53640002f, 0.31987920f, + -0.15592493f, 0.53640002f, 0.29969811f, + -0.20003228f, 0.53640002f, 0.27256551f, + -0.23912801f, 0.53640002f, 0.23912801f, + -0.27256551f, 0.53640002f, 0.20003226f, + -0.29969811f, 0.53640008f, 0.15592495f, + -0.31987917f, 0.53640008f, 0.10745268f, + -0.33246201f, 0.53640002f, 0.05526213f, + -0.33680001f, 0.53640002f, 0.00000001f, + 0.00000000f, 0.52499998f, 0.41250002f, + -0.06768300f, 0.52499992f, 0.40718701f, + -0.13160400f, 0.52499998f, 0.39177606f, + -0.19097100f, 0.52499998f, 0.36705902f, + -0.24499202f, 0.52499998f, 0.33382803f, + -0.29287499f, 0.52499998f, 0.29287499f, + -0.33382803f, 0.52499998f, 0.24499199f, + -0.36705902f, 0.52499998f, 0.19097102f, + -0.39177603f, 0.52499998f, 0.13160400f, + -0.40718701f, 0.52499998f, 0.06768298f, + -0.41250002f, 0.52499998f, 0.00000001f, + 0.00000000f, 0.51359999f, 0.48519999f, + -0.07961161f, 0.51359999f, 0.47895056f, + -0.15479822f, 0.51359999f, 0.46082360f, + -0.22462820f, 0.51359999f, 0.43175036f, + -0.28817001f, 0.51360005f, 0.39266267f, + -0.34449199f, 0.51359999f, 0.34449199f, + -0.39266264f, 0.51359999f, 0.28816998f, + -0.43175036f, 0.51359999f, 0.22462821f, + -0.46082354f, 0.51359999f, 0.15479821f, + -0.47895062f, 0.51359999f, 0.07961159f, + -0.48519999f, 0.51359999f, 0.00000001f, + 0.00000000f, 0.50129998f, 0.55009997f, + -0.09026040f, 0.50129992f, 0.54301465f, + -0.17550392f, 0.50129998f, 0.52246296f, + -0.25467429f, 0.50129998f, 0.48950094f, + -0.32671541f, 0.50129998f, 0.44518495f, + -0.39057100f, 0.50129998f, 0.39057100f, + -0.44518495f, 0.50129998f, 0.32671538f, + -0.48950097f, 0.50129998f, 0.25467432f, + -0.52246296f, 0.50129998f, 0.17550389f, + -0.54301471f, 0.50129998f, 0.09026038f, + -0.55009997f, 0.50129998f, 0.00000001f, + 0.00000000f, 0.48720002f, 0.60240000f, + -0.09884179f, 0.48719996f, 0.59464109f, + -0.19218971f, 0.48720005f, 0.57213551f, + -0.27888709f, 0.48719999f, 0.53603959f, + -0.35777742f, 0.48720002f, 0.48751029f, + -0.42770401f, 0.48720002f, 0.42770401f, + -0.48751026f, 0.48720002f, 0.35777742f, + -0.53603959f, 0.48720005f, 0.27888709f, + -0.57213545f, 0.48720002f, 0.19218969f, + -0.59464109f, 0.48720002f, 0.09884176f, + -0.60240000f, 0.48720002f, 0.00000001f, + 0.00000000f, 0.47040004f, 0.63730001f, + -0.10456818f, 0.47039998f, 0.62909156f, + -0.20332420f, 0.47040007f, 0.60528207f, + -0.29504442f, 0.47040001f, 0.56709504f, + -0.37850523f, 0.47040004f, 0.51575416f, + -0.45248300f, 0.47040004f, 0.45248300f, + -0.51575416f, 0.47040004f, 0.37850523f, + -0.56709504f, 0.47040004f, 0.29504442f, + -0.60528207f, 0.47040004f, 0.20332420f, + -0.62909162f, 0.47040004f, 0.10456816f, + -0.63730001f, 0.47040004f, 0.00000001f, + 0.00000000f, 0.45000005f, 0.64999998f, + -0.10665200f, 0.44999996f, 0.64162791f, + -0.20737600f, 0.45000011f, 0.61734402f, + -0.30092400f, 0.45000002f, 0.57839590f, + -0.38604802f, 0.45000008f, 0.52603197f, + -0.46149999f, 0.45000005f, 0.46149999f, + -0.52603197f, 0.45000005f, 0.38604796f, + -0.57839596f, 0.45000008f, 0.30092400f, + -0.61734402f, 0.45000005f, 0.20737599f, + -0.64162797f, 0.45000005f, 0.10665197f, + -0.64999998f, 0.45000005f, 0.00000001f, + -0.10000000f, 0.60000002f, 0.00000001f, + -0.09871199f, 0.59999996f, -0.01640799f, + -0.09497602f, 0.60000008f, -0.03190399f, + -0.08898400f, 0.60000008f, -0.04629599f, + -0.08092801f, 0.60000002f, -0.05939199f, + -0.07100000f, 0.60000002f, -0.07099999f, + -0.05939200f, 0.60000002f, -0.08092800f, + -0.04629600f, 0.60000002f, -0.08898400f, + -0.03190400f, 0.60000002f, -0.09497599f, + -0.01640799f, 0.60000002f, -0.09871200f, + 0.00000000f, 0.60000002f, -0.09999999f, + -0.13969998f, 0.57959992f, 0.00000001f, + -0.13790064f, 0.57959986f, -0.02292197f, + -0.13268146f, 0.57959998f, -0.04456988f, + -0.12431064f, 0.57959992f, -0.06467550f, + -0.11305641f, 0.57959998f, -0.08297062f, + -0.09918699f, 0.57959992f, -0.09918699f, + -0.08297062f, 0.57959992f, -0.11305641f, + -0.06467551f, 0.57959998f, -0.12431063f, + -0.04456988f, 0.57959992f, -0.13268146f, + -0.02292197f, 0.57959992f, -0.13790065f, + 0.00000000f, 0.57959992f, -0.13969998f, + -0.19560002f, 0.56280005f, 0.00000001f, + -0.19308068f, 0.56279999f, -0.03209404f, + -0.18577307f, 0.56280011f, -0.06240422f, + -0.17405272f, 0.56280005f, -0.09055497f, + -0.15829518f, 0.56280005f, -0.11617076f, + -0.13887602f, 0.56280005f, -0.13887601f, + -0.11617076f, 0.56280005f, -0.15829517f, + -0.09055499f, 0.56280005f, -0.17405272f, + -0.06240423f, 0.56280005f, -0.18577306f, + -0.03209404f, 0.56280005f, -0.19308066f, + 0.00000000f, 0.56280005f, -0.19560000f, + -0.26289999f, 0.54869998f, 0.00000001f, + -0.25951380f, 0.54869998f, -0.04313662f, + -0.24969190f, 0.54869998f, -0.08387562f, + -0.23393893f, 0.54870003f, -0.12171219f, + -0.21275970f, 0.54869998f, -0.15614156f, + -0.18665901f, 0.54869998f, -0.18665899f, + -0.15614155f, 0.54869998f, -0.21275972f, + -0.12171219f, 0.54869998f, -0.23393893f, + -0.08387562f, 0.54869998f, -0.24969190f, + -0.04313662f, 0.54869998f, -0.25951385f, + 0.00000000f, 0.54869998f, -0.26289999f, + -0.33680001f, 0.53640002f, 0.00000001f, + -0.33246198f, 0.53639996f, -0.05526214f, + -0.31987920f, 0.53640002f, -0.10745268f, + -0.29969811f, 0.53640002f, -0.15592493f, + -0.27256551f, 0.53640002f, -0.20003226f, + -0.23912801f, 0.53640002f, -0.23912801f, + -0.20003226f, 0.53640002f, -0.27256551f, + -0.15592495f, 0.53640008f, -0.29969811f, + -0.10745268f, 0.53640008f, -0.31987917f, + -0.05526213f, 0.53640002f, -0.33246201f, + 0.00000000f, 0.53640002f, -0.33680001f, + -0.41250002f, 0.52499998f, 0.00000001f, + -0.40718701f, 0.52499992f, -0.06768300f, + -0.39177606f, 0.52499998f, -0.13160400f, + -0.36705902f, 0.52499998f, -0.19097100f, + -0.33382803f, 0.52499998f, -0.24499202f, + -0.29287499f, 0.52499998f, -0.29287499f, + -0.24499199f, 0.52499998f, -0.33382803f, + -0.19097102f, 0.52499998f, -0.36705902f, + -0.13160400f, 0.52499998f, -0.39177603f, + -0.06768297f, 0.52499998f, -0.40718701f, + 0.00000000f, 0.52499998f, -0.41250002f, + -0.48519999f, 0.51359999f, 0.00000001f, + -0.47895056f, 0.51359999f, -0.07961161f, + -0.46082360f, 0.51359999f, -0.15479822f, + -0.43175036f, 0.51359999f, -0.22462820f, + -0.39266267f, 0.51360005f, -0.28817001f, + -0.34449199f, 0.51359999f, -0.34449199f, + -0.28816998f, 0.51359999f, -0.39266264f, + -0.22462821f, 0.51359999f, -0.43175036f, + -0.15479821f, 0.51359999f, -0.46082354f, + -0.07961158f, 0.51359999f, -0.47895062f, + 0.00000000f, 0.51359999f, -0.48519999f, + -0.55009997f, 0.50129998f, 0.00000001f, + -0.54301465f, 0.50129992f, -0.09026039f, + -0.52246296f, 0.50129998f, -0.17550392f, + -0.48950094f, 0.50129998f, -0.25467429f, + -0.44518495f, 0.50129998f, -0.32671541f, + -0.39057100f, 0.50129998f, -0.39057100f, + -0.32671538f, 0.50129998f, -0.44518495f, + -0.25467432f, 0.50129998f, -0.48950097f, + -0.17550389f, 0.50129998f, -0.52246296f, + -0.09026037f, 0.50129998f, -0.54301471f, + 0.00000000f, 0.50129998f, -0.55009997f, + -0.60240000f, 0.48720002f, 0.00000001f, + -0.59464109f, 0.48719996f, -0.09884178f, + -0.57213551f, 0.48720005f, -0.19218971f, + -0.53603959f, 0.48719999f, -0.27888709f, + -0.48751029f, 0.48720002f, -0.35777742f, + -0.42770401f, 0.48720002f, -0.42770401f, + -0.35777742f, 0.48720002f, -0.48751026f, + -0.27888709f, 0.48720005f, -0.53603959f, + -0.19218969f, 0.48720002f, -0.57213545f, + -0.09884176f, 0.48720002f, -0.59464109f, + 0.00000000f, 0.48720002f, -0.60240000f, + -0.63730001f, 0.47040004f, 0.00000001f, + -0.62909156f, 0.47039998f, -0.10456817f, + -0.60528207f, 0.47040007f, -0.20332420f, + -0.56709504f, 0.47040001f, -0.29504442f, + -0.51575416f, 0.47040004f, -0.37850523f, + -0.45248300f, 0.47040004f, -0.45248300f, + -0.37850523f, 0.47040004f, -0.51575416f, + -0.29504442f, 0.47040004f, -0.56709504f, + -0.20332420f, 0.47040004f, -0.60528207f, + -0.10456815f, 0.47040004f, -0.62909162f, + 0.00000000f, 0.47040004f, -0.63730001f, + -0.64999998f, 0.45000005f, 0.00000001f, + -0.64162791f, 0.44999996f, -0.10665199f, + -0.61734402f, 0.45000011f, -0.20737600f, + -0.57839590f, 0.45000002f, -0.30092400f, + -0.52603197f, 0.45000008f, -0.38604802f, + -0.46149999f, 0.45000005f, -0.46149999f, + -0.38604796f, 0.45000005f, -0.52603197f, + -0.30092400f, 0.45000008f, -0.57839596f, + -0.20737599f, 0.45000005f, -0.61734402f, + -0.10665196f, 0.45000005f, -0.64162797f, + 0.00000000f, 0.45000005f, -0.64999998f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.74891251f, 0.19413748f, + 0.03185407f, -0.74891245f, 0.19163698f, + 0.06193763f, -0.74891251f, 0.18438403f, + 0.08987789f, -0.74891245f, 0.17275129f, + 0.11530213f, -0.74891257f, 0.15711159f, + 0.13783762f, -0.74891251f, 0.13783762f, + 0.15711159f, -0.74891251f, 0.11530213f, + 0.17275131f, -0.74891257f, 0.08987789f, + 0.18438402f, -0.74891257f, 0.06193761f, + 0.19163698f, -0.74891251f, 0.03185406f, + 0.19413748f, -0.74891251f, -0.00000001f, + 0.00000000f, -0.74580008f, 0.35160002f, + 0.05769053f, -0.74579996f, 0.34707141f, + 0.11217448f, -0.74580014f, 0.33393562f, + 0.16277674f, -0.74580008f, 0.31286776f, + 0.20882230f, -0.74580008f, 0.28454286f, + 0.24963601f, -0.74580008f, 0.24963601f, + 0.28454286f, -0.74580008f, 0.20882228f, + 0.31286776f, -0.74580008f, 0.16277674f, + 0.33393565f, -0.74580008f, 0.11217446f, + 0.34707141f, -0.74580002f, 0.05769050f, + 0.35160002f, -0.74580008f, -0.00000001f, + 0.00000000f, -0.74088752f, 0.47621247f, + 0.07813694f, -0.74088746f, 0.47007880f, + 0.15193085f, -0.74088758f, 0.45228758f, + 0.22046733f, -0.74088752f, 0.42375290f, + 0.28283215f, -0.74088758f, 0.38538927f, + 0.33811086f, -0.74088752f, 0.33811086f, + 0.38538924f, -0.74088752f, 0.28283212f, + 0.42375290f, -0.74088752f, 0.22046733f, + 0.45228755f, -0.74088752f, 0.15193082f, + 0.47007886f, -0.74088752f, 0.07813691f, + 0.47621247f, -0.74088752f, -0.00000001f, + 0.00000000f, -0.73440003f, 0.57179999f, + 0.09382094f, -0.73439997f, 0.56443512f, + 0.18242709f, -0.73440009f, 0.54307282f, + 0.26472056f, -0.73440003f, 0.50881052f, + 0.33960345f, -0.73440003f, 0.46274635f, + 0.40597799f, -0.73440003f, 0.40597799f, + 0.46274632f, -0.73440009f, 0.33960345f, + 0.50881052f, -0.73440003f, 0.26472053f, + 0.54307282f, -0.73440003f, 0.18242708f, + 0.56443524f, -0.73440003f, 0.09382091f, + 0.57179999f, -0.73440003f, -0.00000001f, + 0.00000000f, -0.72656250f, 0.64218748f, + 0.10537013f, -0.72656244f, 0.63391608f, + 0.20488352f, -0.72656256f, 0.60992402f, + 0.29730710f, -0.72656256f, 0.57144409f, + 0.38140801f, -0.72656256f, 0.51970953f, + 0.45595312f, -0.72656250f, 0.45595312f, + 0.51970953f, -0.72656250f, 0.38140798f, + 0.57144415f, -0.72656250f, 0.29730713f, + 0.60992396f, -0.72656250f, 0.20488349f, + 0.63391614f, -0.72656250f, 0.10537008f, + 0.64218748f, -0.72656250f, -0.00000001f, + 0.00000000f, -0.71759999f, 0.69119996f, + 0.11341208f, -0.71759993f, 0.68229729f, + 0.22052045f, -0.71760005f, 0.65647405f, + 0.31999791f, -0.71759999f, 0.61505735f, + 0.41051748f, -0.71759999f, 0.55937433f, + 0.49075195f, -0.71759999f, 0.49075198f, + 0.55937433f, -0.71759999f, 0.41051745f, + 0.61505735f, -0.71759999f, 0.31999797f, + 0.65647411f, -0.71759999f, 0.22052044f, + 0.68229735f, -0.71759999f, 0.11341204f, + 0.69119996f, -0.71759999f, -0.00000001f, + 0.00000000f, -0.70773757f, 0.72266257f, + 0.11857446f, -0.70773745f, 0.71335465f, + 0.23055826f, -0.70773757f, 0.68635601f, + 0.33456385f, -0.70773745f, 0.64305401f, + 0.42920375f, -0.70773751f, 0.58483636f, + 0.51309043f, -0.70773751f, 0.51309037f, + 0.58483636f, -0.70773751f, 0.42920372f, + 0.64305407f, -0.70773757f, 0.33456385f, + 0.68635601f, -0.70773751f, 0.23055825f, + 0.71335471f, -0.70773751f, 0.11857441f, + 0.72266257f, -0.70773751f, -0.00000001f, + 0.00000000f, -0.69720000f, 0.74039996f, + 0.12148482f, -0.69719994f, 0.73086351f, + 0.23621722f, -0.69720006f, 0.70320231f, + 0.34277558f, -0.69720000f, 0.65883750f, + 0.43973836f, -0.69720006f, 0.59919089f, + 0.52568400f, -0.69719994f, 0.52568400f, + 0.59919089f, -0.69720006f, 0.43973833f, + 0.65883750f, -0.69720000f, 0.34277558f, + 0.70320225f, -0.69720006f, 0.23621720f, + 0.73086363f, -0.69720000f, 0.12148478f, + 0.74039996f, -0.69720000f, -0.00000001f, + 0.00000000f, -0.68621248f, 0.74823749f, + 0.12277080f, -0.68621248f, 0.73860013f, + 0.23871772f, -0.68621254f, 0.71064609f, + 0.34640405f, -0.68621248f, 0.66581166f, + 0.44439322f, -0.68621248f, 0.60553366f, + 0.53124863f, -0.68621248f, 0.53124863f, + 0.60553366f, -0.68621248f, 0.44439319f, + 0.66581166f, -0.68621254f, 0.34640405f, + 0.71064603f, -0.68621254f, 0.23871769f, + 0.73860019f, -0.68621248f, 0.12277076f, + 0.74823749f, -0.68621248f, -0.00000001f, + 0.00000000f, -0.67500001f, 0.75000000f, + 0.12305999f, -0.67499995f, 0.74033999f, + 0.23928000f, -0.67500007f, 0.71232003f, + 0.34721997f, -0.67500001f, 0.66737998f, + 0.44544002f, -0.67500007f, 0.60696000f, + 0.53250003f, -0.67500007f, 0.53250003f, + 0.60696000f, -0.67500001f, 0.44543999f, + 0.66738003f, -0.67500001f, 0.34722000f, + 0.71231997f, -0.67500001f, 0.23927999f, + 0.74033999f, -0.67500001f, 0.12305995f, + 0.75000000f, -0.67500001f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.19413748f, -0.74891251f, -0.00000001f, + 0.19163698f, -0.74891245f, -0.03185408f, + 0.18438403f, -0.74891251f, -0.06193763f, + 0.17275129f, -0.74891245f, -0.08987790f, + 0.15711159f, -0.74891257f, -0.11530215f, + 0.13783762f, -0.74891251f, -0.13783762f, + 0.11530213f, -0.74891251f, -0.15711159f, + 0.08987789f, -0.74891257f, -0.17275131f, + 0.06193762f, -0.74891257f, -0.18438402f, + 0.03185407f, -0.74891251f, -0.19163698f, + 0.00000000f, -0.74891251f, -0.19413748f, + 0.35160002f, -0.74580008f, -0.00000001f, + 0.34707141f, -0.74579996f, -0.05769053f, + 0.33393562f, -0.74580014f, -0.11217449f, + 0.31286776f, -0.74580008f, -0.16277674f, + 0.28454286f, -0.74580008f, -0.20882230f, + 0.24963601f, -0.74580008f, -0.24963601f, + 0.20882228f, -0.74580008f, -0.28454286f, + 0.16277674f, -0.74580008f, -0.31286776f, + 0.11217447f, -0.74580008f, -0.33393565f, + 0.05769051f, -0.74580002f, -0.34707141f, + 0.00000000f, -0.74580008f, -0.35160002f, + 0.47621247f, -0.74088752f, -0.00000001f, + 0.47007880f, -0.74088746f, -0.07813694f, + 0.45228758f, -0.74088758f, -0.15193085f, + 0.42375290f, -0.74088752f, -0.22046733f, + 0.38538927f, -0.74088758f, -0.28283215f, + 0.33811086f, -0.74088752f, -0.33811086f, + 0.28283212f, -0.74088752f, -0.38538924f, + 0.22046733f, -0.74088752f, -0.42375290f, + 0.15193082f, -0.74088752f, -0.45228755f, + 0.07813691f, -0.74088752f, -0.47007886f, + 0.00000000f, -0.74088752f, -0.47621247f, + 0.57179999f, -0.73440003f, -0.00000001f, + 0.56443512f, -0.73439997f, -0.09382095f, + 0.54307282f, -0.73440009f, -0.18242709f, + 0.50881052f, -0.73440003f, -0.26472056f, + 0.46274635f, -0.73440003f, -0.33960345f, + 0.40597799f, -0.73440003f, -0.40597799f, + 0.33960345f, -0.73440009f, -0.46274632f, + 0.26472053f, -0.73440003f, -0.50881052f, + 0.18242708f, -0.73440003f, -0.54307282f, + 0.09382091f, -0.73440003f, -0.56443524f, + 0.00000000f, -0.73440003f, -0.57179999f, + 0.64218748f, -0.72656250f, -0.00000001f, + 0.63391608f, -0.72656244f, -0.10537013f, + 0.60992402f, -0.72656256f, -0.20488352f, + 0.57144409f, -0.72656256f, -0.29730710f, + 0.51970953f, -0.72656256f, -0.38140801f, + 0.45595312f, -0.72656250f, -0.45595312f, + 0.38140798f, -0.72656250f, -0.51970953f, + 0.29730713f, -0.72656250f, -0.57144415f, + 0.20488349f, -0.72656250f, -0.60992396f, + 0.10537009f, -0.72656250f, -0.63391614f, + 0.00000000f, -0.72656250f, -0.64218748f, + 0.69119996f, -0.71759999f, -0.00000001f, + 0.68229729f, -0.71759993f, -0.11341209f, + 0.65647405f, -0.71760005f, -0.22052045f, + 0.61505735f, -0.71759999f, -0.31999791f, + 0.55937433f, -0.71759999f, -0.41051748f, + 0.49075198f, -0.71759999f, -0.49075195f, + 0.41051745f, -0.71759999f, -0.55937433f, + 0.31999797f, -0.71759999f, -0.61505735f, + 0.22052044f, -0.71759999f, -0.65647411f, + 0.11341204f, -0.71759999f, -0.68229735f, + 0.00000000f, -0.71759999f, -0.69119996f, + 0.72266257f, -0.70773751f, -0.00000001f, + 0.71335465f, -0.70773745f, -0.11857446f, + 0.68635601f, -0.70773757f, -0.23055826f, + 0.64305401f, -0.70773745f, -0.33456385f, + 0.58483636f, -0.70773751f, -0.42920375f, + 0.51309037f, -0.70773751f, -0.51309043f, + 0.42920372f, -0.70773751f, -0.58483636f, + 0.33456385f, -0.70773751f, -0.64305407f, + 0.23055825f, -0.70773751f, -0.68635601f, + 0.11857442f, -0.70773751f, -0.71335471f, + 0.00000000f, -0.70773751f, -0.72266257f, + 0.74039996f, -0.69720000f, -0.00000001f, + 0.73086351f, -0.69719994f, -0.12148483f, + 0.70320231f, -0.69720006f, -0.23621722f, + 0.65883750f, -0.69720000f, -0.34277558f, + 0.59919089f, -0.69720006f, -0.43973836f, + 0.52568400f, -0.69719994f, -0.52568400f, + 0.43973833f, -0.69720006f, -0.59919089f, + 0.34277558f, -0.69720000f, -0.65883750f, + 0.23621720f, -0.69720006f, -0.70320225f, + 0.12148479f, -0.69720000f, -0.73086363f, + 0.00000000f, -0.69720000f, -0.74039996f, + 0.74823749f, -0.68621248f, -0.00000001f, + 0.73860013f, -0.68621248f, -0.12277081f, + 0.71064609f, -0.68621254f, -0.23871772f, + 0.66581166f, -0.68621248f, -0.34640405f, + 0.60553366f, -0.68621248f, -0.44439322f, + 0.53124863f, -0.68621248f, -0.53124863f, + 0.44439319f, -0.68621248f, -0.60553366f, + 0.34640405f, -0.68621254f, -0.66581166f, + 0.23871769f, -0.68621254f, -0.71064603f, + 0.12277076f, -0.68621248f, -0.73860019f, + 0.00000000f, -0.68621248f, -0.74823749f, + 0.75000000f, -0.67500001f, -0.00000001f, + 0.74033999f, -0.67499995f, -0.12306000f, + 0.71232003f, -0.67500007f, -0.23928000f, + 0.66737998f, -0.67500001f, -0.34721997f, + 0.60696000f, -0.67500007f, -0.44544002f, + 0.53250003f, -0.67500007f, -0.53250003f, + 0.44543999f, -0.67500001f, -0.60696000f, + 0.34722000f, -0.67500001f, -0.66738003f, + 0.23927999f, -0.67500001f, -0.71231997f, + 0.12305996f, -0.67500001f, -0.74033999f, + 0.00000000f, -0.67500001f, -0.75000000f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + -0.19413748f, -0.74891251f, -0.00000001f, + -0.19163698f, -0.74891245f, 0.03185407f, + -0.18438403f, -0.74891251f, 0.06193762f, + -0.17275129f, -0.74891245f, 0.08987788f, + -0.15711159f, -0.74891257f, 0.11530213f, + -0.13783762f, -0.74891251f, 0.13783762f, + -0.11530213f, -0.74891251f, 0.15711159f, + -0.08987789f, -0.74891257f, 0.17275131f, + -0.06193762f, -0.74891257f, 0.18438402f, + -0.03185407f, -0.74891251f, 0.19163698f, + 0.00000000f, -0.74891251f, 0.19413748f, + -0.35160002f, -0.74580008f, -0.00000001f, + -0.34707141f, -0.74579996f, 0.05769052f, + -0.33393562f, -0.74580014f, 0.11217447f, + -0.31286776f, -0.74580008f, 0.16277674f, + -0.28454286f, -0.74580008f, 0.20882230f, + -0.24963601f, -0.74580008f, 0.24963601f, + -0.20882228f, -0.74580008f, 0.28454286f, + -0.16277674f, -0.74580008f, 0.31286776f, + -0.11217447f, -0.74580008f, 0.33393565f, + -0.05769051f, -0.74580002f, 0.34707141f, + 0.00000000f, -0.74580008f, 0.35160002f, + -0.47621247f, -0.74088752f, -0.00000001f, + -0.47007880f, -0.74088746f, 0.07813693f, + -0.45228758f, -0.74088758f, 0.15193084f, + -0.42375290f, -0.74088752f, 0.22046733f, + -0.38538927f, -0.74088758f, 0.28283215f, + -0.33811086f, -0.74088752f, 0.33811086f, + -0.28283212f, -0.74088752f, 0.38538924f, + -0.22046733f, -0.74088752f, 0.42375290f, + -0.15193082f, -0.74088752f, 0.45228755f, + -0.07813691f, -0.74088752f, 0.47007886f, + 0.00000000f, -0.74088752f, 0.47621247f, + -0.57179999f, -0.73440003f, -0.00000001f, + -0.56443512f, -0.73439997f, 0.09382094f, + -0.54307282f, -0.73440009f, 0.18242709f, + -0.50881052f, -0.73440003f, 0.26472056f, + -0.46274635f, -0.73440003f, 0.33960345f, + -0.40597799f, -0.73440003f, 0.40597799f, + -0.33960345f, -0.73440009f, 0.46274632f, + -0.26472053f, -0.73440003f, 0.50881052f, + -0.18242708f, -0.73440003f, 0.54307282f, + -0.09382091f, -0.73440003f, 0.56443524f, + 0.00000000f, -0.73440003f, 0.57179999f, + -0.64218748f, -0.72656250f, -0.00000001f, + -0.63391608f, -0.72656244f, 0.10537011f, + -0.60992402f, -0.72656256f, 0.20488352f, + -0.57144409f, -0.72656256f, 0.29730710f, + -0.51970953f, -0.72656256f, 0.38140801f, + -0.45595312f, -0.72656250f, 0.45595312f, + -0.38140798f, -0.72656250f, 0.51970953f, + -0.29730713f, -0.72656250f, 0.57144415f, + -0.20488349f, -0.72656250f, 0.60992396f, + -0.10537009f, -0.72656250f, 0.63391614f, + 0.00000000f, -0.72656250f, 0.64218748f, + -0.69119996f, -0.71759999f, -0.00000001f, + -0.68229729f, -0.71759993f, 0.11341207f, + -0.65647405f, -0.71760005f, 0.22052045f, + -0.61505735f, -0.71759999f, 0.31999791f, + -0.55937433f, -0.71759999f, 0.41051748f, + -0.49075198f, -0.71759999f, 0.49075195f, + -0.41051745f, -0.71759999f, 0.55937433f, + -0.31999797f, -0.71759999f, 0.61505735f, + -0.22052044f, -0.71759999f, 0.65647411f, + -0.11341204f, -0.71759999f, 0.68229735f, + 0.00000000f, -0.71759999f, 0.69119996f, + -0.72266257f, -0.70773751f, -0.00000001f, + -0.71335465f, -0.70773745f, 0.11857444f, + -0.68635601f, -0.70773757f, 0.23055826f, + -0.64305401f, -0.70773751f, 0.33456385f, + -0.58483636f, -0.70773751f, 0.42920375f, + -0.51309037f, -0.70773751f, 0.51309043f, + -0.42920372f, -0.70773751f, 0.58483636f, + -0.33456385f, -0.70773757f, 0.64305407f, + -0.23055825f, -0.70773757f, 0.68635601f, + -0.11857442f, -0.70773757f, 0.71335471f, + 0.00000000f, -0.70773757f, 0.72266257f, + -0.74039996f, -0.69720000f, -0.00000001f, + -0.73086351f, -0.69719994f, 0.12148482f, + -0.70320231f, -0.69720006f, 0.23621722f, + -0.65883750f, -0.69720000f, 0.34277558f, + -0.59919089f, -0.69720006f, 0.43973836f, + -0.52568400f, -0.69719994f, 0.52568400f, + -0.43973833f, -0.69720006f, 0.59919089f, + -0.34277558f, -0.69720000f, 0.65883750f, + -0.23621720f, -0.69720006f, 0.70320225f, + -0.12148479f, -0.69720000f, 0.73086363f, + 0.00000000f, -0.69720000f, 0.74039996f, + -0.74823749f, -0.68621248f, -0.00000001f, + -0.73860013f, -0.68621248f, 0.12277079f, + -0.71064609f, -0.68621254f, 0.23871772f, + -0.66581166f, -0.68621248f, 0.34640405f, + -0.60553366f, -0.68621248f, 0.44439322f, + -0.53124863f, -0.68621248f, 0.53124863f, + -0.44439319f, -0.68621248f, 0.60553366f, + -0.34640405f, -0.68621254f, 0.66581166f, + -0.23871769f, -0.68621254f, 0.71064603f, + -0.12277076f, -0.68621248f, 0.73860019f, + 0.00000000f, -0.68621248f, 0.74823749f, + -0.75000000f, -0.67500001f, -0.00000001f, + -0.74033999f, -0.67499995f, 0.12305998f, + -0.71232003f, -0.67500007f, 0.23928000f, + -0.66737998f, -0.67500001f, 0.34721997f, + -0.60696000f, -0.67500007f, 0.44544002f, + -0.53250003f, -0.67500007f, 0.53250003f, + -0.44543999f, -0.67500001f, 0.60696000f, + -0.34722000f, -0.67500001f, 0.66738003f, + -0.23927999f, -0.67500001f, 0.71231997f, + -0.12305996f, -0.67500001f, 0.74033999f, + 0.00000000f, -0.67500001f, 0.75000000f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000006f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.75000000f, -0.00000001f, + 0.00000000f, -0.74891251f, -0.19413748f, + -0.03185407f, -0.74891245f, -0.19163698f, + -0.06193763f, -0.74891251f, -0.18438403f, + -0.08987789f, -0.74891245f, -0.17275129f, + -0.11530213f, -0.74891257f, -0.15711159f, + -0.13783762f, -0.74891251f, -0.13783762f, + -0.15711159f, -0.74891251f, -0.11530213f, + -0.17275131f, -0.74891257f, -0.08987790f, + -0.18438402f, -0.74891257f, -0.06193763f, + -0.19163698f, -0.74891251f, -0.03185407f, + -0.19413748f, -0.74891251f, -0.00000001f, + 0.00000000f, -0.74580008f, -0.35160002f, + -0.05769053f, -0.74579996f, -0.34707141f, + -0.11217448f, -0.74580014f, -0.33393562f, + -0.16277674f, -0.74580008f, -0.31286776f, + -0.20882230f, -0.74580008f, -0.28454286f, + -0.24963601f, -0.74580008f, -0.24963601f, + -0.28454286f, -0.74580008f, -0.20882228f, + -0.31286776f, -0.74580008f, -0.16277674f, + -0.33393565f, -0.74580008f, -0.11217447f, + -0.34707141f, -0.74580002f, -0.05769052f, + -0.35160002f, -0.74580008f, -0.00000001f, + 0.00000000f, -0.74088752f, -0.47621247f, + -0.07813694f, -0.74088746f, -0.47007880f, + -0.15193085f, -0.74088758f, -0.45228758f, + -0.22046733f, -0.74088752f, -0.42375290f, + -0.28283215f, -0.74088758f, -0.38538927f, + -0.33811086f, -0.74088752f, -0.33811086f, + -0.38538924f, -0.74088752f, -0.28283212f, + -0.42375290f, -0.74088752f, -0.22046733f, + -0.45228755f, -0.74088752f, -0.15193082f, + -0.47007886f, -0.74088752f, -0.07813692f, + -0.47621247f, -0.74088752f, -0.00000001f, + 0.00000000f, -0.73440003f, -0.57179999f, + -0.09382094f, -0.73439997f, -0.56443512f, + -0.18242709f, -0.73440009f, -0.54307282f, + -0.26472056f, -0.73440003f, -0.50881052f, + -0.33960345f, -0.73440003f, -0.46274635f, + -0.40597799f, -0.73440003f, -0.40597799f, + -0.46274632f, -0.73440009f, -0.33960345f, + -0.50881052f, -0.73440003f, -0.26472053f, + -0.54307282f, -0.73440003f, -0.18242708f, + -0.56443524f, -0.73440003f, -0.09382092f, + -0.57179999f, -0.73440003f, -0.00000001f, + 0.00000000f, -0.72656250f, -0.64218748f, + -0.10537013f, -0.72656244f, -0.63391608f, + -0.20488352f, -0.72656256f, -0.60992402f, + -0.29730710f, -0.72656256f, -0.57144409f, + -0.38140801f, -0.72656256f, -0.51970953f, + -0.45595312f, -0.72656250f, -0.45595312f, + -0.51970953f, -0.72656250f, -0.38140798f, + -0.57144415f, -0.72656250f, -0.29730713f, + -0.60992396f, -0.72656250f, -0.20488349f, + -0.63391614f, -0.72656250f, -0.10537010f, + -0.64218748f, -0.72656250f, -0.00000001f, + 0.00000000f, -0.71759999f, -0.69119996f, + -0.11341208f, -0.71759993f, -0.68229729f, + -0.22052045f, -0.71760005f, -0.65647405f, + -0.31999791f, -0.71759999f, -0.61505735f, + -0.41051748f, -0.71759999f, -0.55937433f, + -0.49075195f, -0.71759999f, -0.49075198f, + -0.55937433f, -0.71759999f, -0.41051745f, + -0.61505735f, -0.71759999f, -0.31999797f, + -0.65647411f, -0.71759999f, -0.22052044f, + -0.68229735f, -0.71759999f, -0.11341205f, + -0.69119996f, -0.71759999f, -0.00000001f, + 0.00000000f, -0.70773751f, -0.72266257f, + -0.11857446f, -0.70773745f, -0.71335465f, + -0.23055826f, -0.70773757f, -0.68635601f, + -0.33456385f, -0.70773745f, -0.64305401f, + -0.42920375f, -0.70773751f, -0.58483636f, + -0.51309043f, -0.70773751f, -0.51309037f, + -0.58483636f, -0.70773751f, -0.42920372f, + -0.64305407f, -0.70773751f, -0.33456385f, + -0.68635601f, -0.70773751f, -0.23055825f, + -0.71335471f, -0.70773751f, -0.11857443f, + -0.72266257f, -0.70773751f, -0.00000001f, + 0.00000000f, -0.69720000f, -0.74039996f, + -0.12148482f, -0.69719994f, -0.73086351f, + -0.23621722f, -0.69720006f, -0.70320231f, + -0.34277558f, -0.69720000f, -0.65883750f, + -0.43973836f, -0.69720006f, -0.59919089f, + -0.52568400f, -0.69719994f, -0.52568400f, + -0.59919089f, -0.69720006f, -0.43973833f, + -0.65883750f, -0.69720000f, -0.34277558f, + -0.70320225f, -0.69720006f, -0.23621720f, + -0.73086363f, -0.69720000f, -0.12148479f, + -0.74039996f, -0.69720000f, -0.00000001f, + 0.00000000f, -0.68621248f, -0.74823749f, + -0.12277080f, -0.68621248f, -0.73860013f, + -0.23871772f, -0.68621254f, -0.71064609f, + -0.34640405f, -0.68621248f, -0.66581166f, + -0.44439322f, -0.68621248f, -0.60553366f, + -0.53124863f, -0.68621248f, -0.53124863f, + -0.60553366f, -0.68621248f, -0.44439319f, + -0.66581166f, -0.68621254f, -0.34640405f, + -0.71064603f, -0.68621254f, -0.23871769f, + -0.73860019f, -0.68621248f, -0.12277077f, + -0.74823749f, -0.68621248f, -0.00000001f, + 0.00000000f, -0.67500001f, -0.75000000f, + -0.12305999f, -0.67499995f, -0.74033999f, + -0.23928000f, -0.67500007f, -0.71232003f, + -0.34721997f, -0.67500001f, -0.66737998f, + -0.44544002f, -0.67500007f, -0.60696000f, + -0.53250003f, -0.67500007f, -0.53250003f, + -0.60696000f, -0.67500001f, -0.44543999f, + -0.66738003f, -0.67500001f, -0.34722000f, + -0.71231997f, -0.67500001f, -0.23927999f, + -0.74033999f, -0.67500001f, -0.12305997f, + -0.75000000f, -0.67500001f, -0.00000001f, + -0.80000001f, 0.26250005f, 0.00000000f, + -0.79859996f, 0.26565003f, 0.04050000f, + -0.79480010f, 0.27420005f, 0.07200000f, + -0.78920001f, 0.28680006f, 0.09450001f, + -0.78240001f, 0.30210006f, 0.10800001f, + -0.77499998f, 0.31875002f, 0.11250000f, + -0.76760000f, 0.33540002f, 0.10800000f, + -0.76080006f, 0.35070002f, 0.09450001f, + -0.75519997f, 0.36330000f, 0.07200000f, + -0.75139999f, 0.37185001f, 0.04049999f, + -0.75000000f, 0.37500000f, 0.00000000f, + -0.90044993f, 0.26238751f, 0.00000000f, + -0.90022725f, 0.26553434f, 0.04050000f, + -0.89962322f, 0.27407584f, 0.07200000f, + -0.89873272f, 0.28666320f, 0.09449999f, + -0.89765161f, 0.30194792f, 0.10800000f, + -0.89647496f, 0.31858125f, 0.11250000f, + -0.89529836f, 0.33521461f, 0.10800000f, + -0.89421713f, 0.35049930f, 0.09449999f, + -0.89332676f, 0.36308670f, 0.07200000f, + -0.89272249f, 0.37162814f, 0.04049999f, + -0.89249992f, 0.37477499f, 0.00000000f, + -0.99160004f, 0.26160005f, 0.00000000f, + -0.99239522f, 0.26472485f, 0.04050001f, + -0.99455369f, 0.27320647f, 0.07200002f, + -0.99773449f, 0.28570563f, 0.09450001f, + -1.00159693f, 0.30088326f, 0.10800002f, + -1.00580013f, 0.31740004f, 0.11250001f, + -1.01000333f, 0.33391684f, 0.10800001f, + -1.01386571f, 0.34909445f, 0.09450001f, + -1.01704645f, 0.36159366f, 0.07200001f, + -1.01920485f, 0.37007523f, 0.04050000f, + -1.02000010f, 0.37320003f, 0.00000000f, + -1.07315004f, 0.25946254f, 0.00000000f, + -1.07481182f, 0.26252747f, 0.04050001f, + -1.07932246f, 0.27084666f, 0.07200002f, + -1.08596969f, 0.28310645f, 0.09450001f, + -1.09404123f, 0.29799330f, 0.10800002f, + -1.10282505f, 0.31419379f, 0.11250001f, + -1.11160886f, 0.33039424f, 0.10800001f, + -1.11968040f, 0.34528112f, 0.09450001f, + -1.12632775f, 0.35754091f, 0.07200001f, + -1.13083827f, 0.36586004f, 0.04050000f, + -1.13250005f, 0.36892501f, 0.00000000f, + -1.14480007f, 0.25530005f, 0.00000000f, + -1.14718556f, 0.25824845f, 0.04050000f, + -1.15366089f, 0.26625127f, 0.07200000f, + -1.16320336f, 0.27804485f, 0.09450001f, + -1.17479050f, 0.29236567f, 0.10800001f, + -1.18740010f, 0.30795002f, 0.11250000f, + -1.20000958f, 0.32353443f, 0.10800000f, + -1.21159685f, 0.33785522f, 0.09450001f, + -1.22113919f, 0.34964880f, 0.07200000f, + -1.22761440f, 0.35765159f, 0.04049999f, + -1.23000002f, 0.36059999f, 0.00000000f, + -1.20625007f, 0.24843754f, 0.00000000f, + -1.20922494f, 0.25119376f, 0.04050000f, + -1.21730018f, 0.25867507f, 0.07200000f, + -1.22920001f, 0.26970002f, 0.09450001f, + -1.24365008f, 0.28308752f, 0.10800001f, + -1.25937510f, 0.29765627f, 0.11250000f, + -1.27509999f, 0.31222504f, 0.10800000f, + -1.28955007f, 0.32561252f, 0.09450001f, + -1.30145001f, 0.33663750f, 0.07200000f, + -1.30952501f, 0.34411874f, 0.04049999f, + -1.31250000f, 0.34687501f, 0.00000000f, + -1.25720000f, 0.23820004f, 0.00000000f, + -1.26063836f, 0.24066961f, 0.04050000f, + -1.26997125f, 0.24737285f, 0.07200000f, + -1.28372490f, 0.25725123f, 0.09450001f, + -1.30042577f, 0.26924643f, 0.10800001f, + -1.31860006f, 0.28230003f, 0.11250000f, + -1.33677435f, 0.29535359f, 0.10800000f, + -1.35347521f, 0.30734879f, 0.09450001f, + -1.36722875f, 0.31722721f, 0.07200000f, + -1.37656152f, 0.32393038f, 0.04049999f, + -1.38000000f, 0.32639998f, 0.00000000f, + -1.29735005f, 0.22391254f, 0.00000000f, + -1.30113411f, 0.22598207f, 0.04050000f, + -1.31140578f, 0.23159945f, 0.07200000f, + -1.32654238f, 0.23987763f, 0.09450001f, + -1.34492302f, 0.24992974f, 0.10800001f, + -1.36492503f, 0.26086879f, 0.11250000f, + -1.38492727f, 0.27180785f, 0.10800000f, + -1.40330780f, 0.28185993f, 0.09450001f, + -1.41844463f, 0.29013813f, 0.07200000f, + -1.42871594f, 0.29575545f, 0.04049999f, + -1.43250012f, 0.29782501f, 0.00000000f, + -1.32640004f, 0.20490001f, 0.00000000f, + -1.33042073f, 0.20643719f, 0.04050000f, + -1.34133446f, 0.21060961f, 0.07200000f, + -1.35741770f, 0.21675842f, 0.09450001f, + -1.37694728f, 0.22422481f, 0.10800001f, + -1.39820004f, 0.23234999f, 0.11250000f, + -1.41945279f, 0.24047519f, 0.10800000f, + -1.43898249f, 0.24794158f, 0.09450001f, + -1.45506573f, 0.25409040f, 0.07200000f, + -1.46597922f, 0.25826281f, 0.04049999f, + -1.47000003f, 0.25979999f, 0.00000000f, + -1.34404993f, 0.18048748f, 0.00000000f, + -1.34820640f, 0.18134111f, 0.04050000f, + -1.35948884f, 0.18365818f, 0.07200000f, + -1.37611520f, 0.18707278f, 0.09450001f, + -1.39630449f, 0.19121909f, 0.10800001f, + -1.41827500f, 0.19573122f, 0.11250000f, + -1.44024563f, 0.20024337f, 0.10800000f, + -1.46043491f, 0.20438966f, 0.09450001f, + -1.47706127f, 0.20780426f, 0.07200000f, + -1.48834348f, 0.21012132f, 0.04049999f, + -1.49250007f, 0.21097496f, 0.00000000f, + -1.35000002f, 0.14999998f, 0.00000000f, + -1.35419989f, 0.14999996f, 0.04050000f, + -1.36559999f, 0.14999999f, 0.07200000f, + -1.38239992f, 0.14999998f, 0.09450001f, + -1.40280008f, 0.14999999f, 0.10800001f, + -1.42499995f, 0.14999998f, 0.11250000f, + -1.44719994f, 0.14999998f, 0.10800000f, + -1.46760011f, 0.14999998f, 0.09450001f, + -1.48440003f, 0.14999998f, 0.07200000f, + -1.49580002f, 0.14999998f, 0.04049999f, + -1.50000000f, 0.14999998f, 0.00000000f, + -0.75000000f, 0.37500000f, 0.00000000f, + -0.75139999f, 0.37184998f, -0.04050000f, + -0.75520003f, 0.36330003f, -0.07200000f, + -0.76080000f, 0.35070002f, -0.09450001f, + -0.76760006f, 0.33540004f, -0.10800001f, + -0.77500004f, 0.31875002f, -0.11250000f, + -0.78240001f, 0.30210003f, -0.10800000f, + -0.78920001f, 0.28680006f, -0.09450001f, + -0.79480004f, 0.27420002f, -0.07200000f, + -0.79860002f, 0.26565003f, -0.04049999f, + -0.80000001f, 0.26250005f, 0.00000000f, + -0.89249992f, 0.37477499f, 0.00000000f, + -0.89272243f, 0.37162811f, -0.04049999f, + -0.89332676f, 0.36308670f, -0.07200000f, + -0.89421707f, 0.35049930f, -0.09449999f, + -0.89529842f, 0.33521461f, -0.10800000f, + -0.89647490f, 0.31858125f, -0.11250000f, + -0.89765155f, 0.30194789f, -0.10800000f, + -0.89873278f, 0.28666323f, -0.09449999f, + -0.89962316f, 0.27407581f, -0.07200000f, + -0.90022731f, 0.26553437f, -0.04049998f, + -0.90044993f, 0.26238751f, 0.00000000f, + -1.02000010f, 0.37320003f, 0.00000000f, + -1.01920474f, 0.37007520f, -0.04050000f, + -1.01704657f, 0.36159366f, -0.07200001f, + -1.01386571f, 0.34909445f, -0.09450001f, + -1.01000333f, 0.33391684f, -0.10800002f, + -1.00580001f, 0.31740004f, -0.11250001f, + -1.00159681f, 0.30088323f, -0.10800001f, + -0.99773443f, 0.28570566f, -0.09450001f, + -0.99455369f, 0.27320647f, -0.07200001f, + -0.99239522f, 0.26472485f, -0.04049999f, + -0.99160004f, 0.26160005f, 0.00000000f, + -1.13250005f, 0.36892501f, 0.00000000f, + -1.13083816f, 0.36586002f, -0.04050000f, + -1.12632775f, 0.35754091f, -0.07200001f, + -1.11968040f, 0.34528109f, -0.09450001f, + -1.11160886f, 0.33039424f, -0.10800002f, + -1.10282505f, 0.31419379f, -0.11250001f, + -1.09404123f, 0.29799333f, -0.10800001f, + -1.08596969f, 0.28310645f, -0.09450001f, + -1.07932246f, 0.27084661f, -0.07200001f, + -1.07481182f, 0.26252750f, -0.04049999f, + -1.07315004f, 0.25946254f, 0.00000000f, + -1.23000002f, 0.36059999f, 0.00000000f, + -1.22761440f, 0.35765156f, -0.04050000f, + -1.22113931f, 0.34964883f, -0.07200000f, + -1.21159685f, 0.33785522f, -0.09450001f, + -1.20000970f, 0.32353443f, -0.10800001f, + -1.18740010f, 0.30795002f, -0.11250000f, + -1.17479038f, 0.29236564f, -0.10800000f, + -1.16320324f, 0.27804482f, -0.09450001f, + -1.15366089f, 0.26625124f, -0.07200000f, + -1.14718568f, 0.25824845f, -0.04049999f, + -1.14480007f, 0.25530005f, 0.00000000f, + -1.31250000f, 0.34687501f, 0.00000000f, + -1.30952489f, 0.34411871f, -0.04050000f, + -1.30145013f, 0.33663750f, -0.07200000f, + -1.28955019f, 0.32561252f, -0.09450001f, + -1.27510011f, 0.31222504f, -0.10800001f, + -1.25937498f, 0.29765630f, -0.11250000f, + -1.24365008f, 0.28308752f, -0.10800000f, + -1.22920012f, 0.26970005f, -0.09450001f, + -1.21730018f, 0.25867504f, -0.07200000f, + -1.20922506f, 0.25119379f, -0.04049999f, + -1.20625007f, 0.24843754f, 0.00000000f, + -1.38000000f, 0.32639998f, 0.00000000f, + -1.37656140f, 0.32393035f, -0.04050000f, + -1.36722875f, 0.31722721f, -0.07200000f, + -1.35347521f, 0.30734879f, -0.09450001f, + -1.33677447f, 0.29535362f, -0.10800001f, + -1.31860006f, 0.28230000f, -0.11250000f, + -1.30042553f, 0.26924643f, -0.10800000f, + -1.28372478f, 0.25725123f, -0.09450001f, + -1.26997125f, 0.24737284f, -0.07200000f, + -1.26063836f, 0.24066964f, -0.04049999f, + -1.25720000f, 0.23820004f, 0.00000000f, + -1.43250012f, 0.29782501f, 0.00000000f, + -1.42871583f, 0.29575542f, -0.04050000f, + -1.41844463f, 0.29013813f, -0.07200000f, + -1.40330768f, 0.28185993f, -0.09450001f, + -1.38492751f, 0.27180785f, -0.10800001f, + -1.36492515f, 0.26086876f, -0.11250000f, + -1.34492302f, 0.24992973f, -0.10800000f, + -1.32654250f, 0.23987764f, -0.09450001f, + -1.31140566f, 0.23159944f, -0.07200000f, + -1.30113423f, 0.22598210f, -0.04049999f, + -1.29735005f, 0.22391254f, 0.00000000f, + -1.47000003f, 0.25979999f, 0.00000000f, + -1.46597922f, 0.25826275f, -0.04050000f, + -1.45506561f, 0.25409040f, -0.07200000f, + -1.43898249f, 0.24794158f, -0.09450001f, + -1.41945291f, 0.24047521f, -0.10800001f, + -1.39820004f, 0.23234999f, -0.11250000f, + -1.37694728f, 0.22422481f, -0.10800000f, + -1.35741770f, 0.21675842f, -0.09450001f, + -1.34133446f, 0.21060961f, -0.07200000f, + -1.33042085f, 0.20643722f, -0.04049999f, + -1.32640004f, 0.20490001f, 0.00000000f, + -1.49250007f, 0.21097496f, 0.00000000f, + -1.48834324f, 0.21012127f, -0.04050000f, + -1.47706139f, 0.20780428f, -0.07200000f, + -1.46043479f, 0.20438966f, -0.09450001f, + -1.44024563f, 0.20024338f, -0.10800001f, + -1.41827488f, 0.19573122f, -0.11250000f, + -1.39630437f, 0.19121908f, -0.10800000f, + -1.37611520f, 0.18707278f, -0.09450001f, + -1.35948884f, 0.18365818f, -0.07200000f, + -1.34820652f, 0.18134113f, -0.04049999f, + -1.34404993f, 0.18048748f, 0.00000000f, + -1.50000000f, 0.14999998f, 0.00000000f, + -1.49580002f, 0.14999996f, -0.04050000f, + -1.48440015f, 0.14999999f, -0.07200000f, + -1.46759999f, 0.14999998f, -0.09450001f, + -1.44720006f, 0.14999999f, -0.10800001f, + -1.42500007f, 0.14999998f, -0.11250000f, + -1.40280008f, 0.14999998f, -0.10800000f, + -1.38240004f, 0.14999998f, -0.09450001f, + -1.36559999f, 0.14999998f, -0.07200000f, + -1.35420001f, 0.14999998f, -0.04049999f, + -1.35000002f, 0.14999998f, 0.00000000f, + -1.35000002f, 0.14999998f, 0.00000000f, + -1.35419989f, 0.14999996f, 0.04050000f, + -1.36559999f, 0.14999999f, 0.07200000f, + -1.38239992f, 0.14999998f, 0.09450001f, + -1.40280008f, 0.14999999f, 0.10800001f, + -1.42499995f, 0.14999998f, 0.11250000f, + -1.44719994f, 0.14999998f, 0.10800000f, + -1.46760011f, 0.14999998f, 0.09450001f, + -1.48440003f, 0.14999998f, 0.07200000f, + -1.49580002f, 0.14999998f, 0.04049999f, + -1.50000000f, 0.14999998f, 0.00000000f, + -1.34694993f, 0.11309998f, 0.00000000f, + -1.35108757f, 0.11225944f, 0.04049999f, + -1.36231863f, 0.10997803f, 0.07200000f, + -1.37886941f, 0.10661592f, 0.09449999f, + -1.39896679f, 0.10253337f, 0.10800000f, + -1.42083752f, 0.09809060f, 0.11250000f, + -1.44270813f, 0.09364782f, 0.10800000f, + -1.46280551f, 0.08956527f, 0.09449999f, + -1.47935629f, 0.08620317f, 0.07200000f, + -1.49058723f, 0.08392174f, 0.04049999f, + -1.49472487f, 0.08308122f, 0.00000000f, + -1.33760011f, 0.07080000f, 0.00000000f, + -1.34155357f, 0.06930479f, 0.04050000f, + -1.35228503f, 0.06524640f, 0.07200002f, + -1.36809933f, 0.05926559f, 0.09450001f, + -1.38730252f, 0.05200320f, 0.10800002f, + -1.40820003f, 0.04410000f, 0.11250001f, + -1.42909765f, 0.03619679f, 0.10800001f, + -1.44830084f, 0.02893440f, 0.09450001f, + -1.46411526f, 0.02295359f, 0.07200001f, + -1.47484648f, 0.01889519f, 0.04049999f, + -1.47880006f, 0.01739999f, 0.00000000f, + -1.32164991f, 0.02445000f, 0.00000000f, + -1.32530177f, 0.02245132f, 0.04050000f, + -1.33521414f, 0.01702635f, 0.07200002f, + -1.34982169f, 0.00903165f, 0.09450001f, + -1.36755967f, -0.00067620f, 0.10800002f, + -1.38686240f, -0.01124063f, 0.11250001f, + -1.40616536f, -0.02180506f, 0.10800001f, + -1.42390323f, -0.03151290f, 0.09450001f, + -1.43851089f, -0.03950761f, 0.07200001f, + -1.44842303f, -0.04493258f, 0.04049999f, + -1.45207500f, -0.04693126f, -0.00000000f, + -1.29880011f, -0.02460000f, -0.00000000f, + -1.30203676f, -0.02698559f, 0.04050000f, + -1.31082261f, -0.03346080f, 0.07200000f, + -1.32376969f, -0.04300320f, 0.09450001f, + -1.33949125f, -0.05459040f, 0.10800001f, + -1.35660005f, -0.06720001f, 0.11250000f, + -1.37370884f, -0.07980961f, 0.10800000f, + -1.38943052f, -0.09139681f, 0.09450001f, + -1.40237761f, -0.10093921f, 0.07200000f, + -1.41116321f, -0.10741441f, 0.04049999f, + -1.41439998f, -0.10980001f, -0.00000000f, + -1.26874995f, -0.07500000f, -0.00000000f, + -1.27146244f, -0.07769062f, 0.04050000f, + -1.27882504f, -0.08499375f, 0.07200000f, + -1.28967500f, -0.09575625f, 0.09450001f, + -1.30285001f, -0.10882500f, 0.10800001f, + -1.31718755f, -0.12304687f, 0.11250000f, + -1.33152497f, -0.13726875f, 0.10800000f, + -1.34470010f, -0.15033749f, 0.09450001f, + -1.35555005f, -0.16110000f, 0.07200000f, + -1.36291242f, -0.16840312f, 0.04049999f, + -1.36562502f, -0.17109375f, -0.00000000f, + -1.23119998f, -0.12540001f, -0.00000000f, + -1.23328304f, -0.12834840f, 0.04050000f, + -1.23893762f, -0.13635120f, 0.07200000f, + -1.24727035f, -0.14814480f, 0.09450001f, + -1.25738895f, -0.16246562f, 0.10800001f, + -1.26839995f, -0.17805001f, 0.11250000f, + -1.27941120f, -0.19363439f, 0.10800000f, + -1.28952956f, -0.20795521f, 0.09450001f, + -1.29786241f, -0.21974881f, 0.07200000f, + -1.30351675f, -0.22775160f, 0.04049999f, + -1.30559993f, -0.23070000f, -0.00000000f, + -1.18585014f, -0.17445001f, -0.00000000f, + -1.18720317f, -0.17764355f, 0.04050000f, + -1.19087601f, -0.18631189f, 0.07200000f, + -1.19628823f, -0.19908616f, 0.09450001f, + -1.20286059f, -0.21459784f, 0.10800001f, + -1.21001256f, -0.23147814f, 0.11250000f, + -1.21716475f, -0.24835847f, 0.10800000f, + -1.22373688f, -0.26387012f, 0.09450001f, + -1.22914934f, -0.27664441f, 0.07200000f, + -1.23282194f, -0.28531271f, 0.04049999f, + -1.23417509f, -0.28850627f, -0.00000000f, + -1.13240004f, -0.22080001f, -0.00000000f, + -1.13292634f, -0.22426079f, 0.04050000f, + -1.13435543f, -0.23365441f, 0.07200000f, + -1.13646090f, -0.24749762f, 0.09450001f, + -1.13901782f, -0.26430723f, 0.10800001f, + -1.14180005f, -0.28260002f, 0.11250000f, + -1.14458251f, -0.30089283f, 0.10800000f, + -1.14713919f, -0.31770241f, 0.09450001f, + -1.14924490f, -0.33154562f, 0.07200000f, + -1.15067363f, -0.34093922f, 0.04049999f, + -1.15120006f, -0.34440002f, -0.00000000f, + -1.07054996f, -0.26310003f, -0.00000000f, + -1.07015729f, -0.26688471f, 0.04050000f, + -1.06909144f, -0.27715757f, 0.07200000f, + -1.06752050f, -0.29229647f, 0.09450001f, + -1.06561327f, -0.31067947f, 0.10800001f, + -1.06353748f, -0.33068439f, 0.11250000f, + -1.06146181f, -0.35068941f, 0.10800000f, + -1.05955434f, -0.36907232f, 0.09450001f, + -1.05798364f, -0.38421124f, 0.07200000f, + -1.05691767f, -0.39448404f, 0.04049999f, + -1.05652499f, -0.39826876f, -0.00000000f, + -1.00000000f, -0.30000001f, -0.00000000f, + -0.99859989f, -0.30419996f, 0.04050000f, + -0.99480003f, -0.31560001f, 0.07200000f, + -0.98920000f, -0.33240002f, 0.09450001f, + -0.98240000f, -0.35280001f, 0.10800001f, + -0.97499996f, -0.37500000f, 0.11250000f, + -0.96759999f, -0.39720002f, 0.10800000f, + -0.96080005f, -0.41759998f, 0.09450001f, + -0.95520002f, -0.43440002f, 0.07200000f, + -0.95139992f, -0.44580001f, 0.04049999f, + -0.94999999f, -0.44999999f, -0.00000001f, + -1.50000000f, 0.14999998f, 0.00000000f, + -1.49580002f, 0.14999996f, -0.04050000f, + -1.48440015f, 0.14999999f, -0.07200000f, + -1.46759999f, 0.14999998f, -0.09450001f, + -1.44720006f, 0.14999999f, -0.10800001f, + -1.42500007f, 0.14999998f, -0.11250000f, + -1.40280008f, 0.14999998f, -0.10800000f, + -1.38240004f, 0.14999998f, -0.09450001f, + -1.36559999f, 0.14999998f, -0.07200000f, + -1.35420001f, 0.14999998f, -0.04049999f, + -1.35000002f, 0.14999998f, 0.00000000f, + -1.49472487f, 0.08308122f, 0.00000000f, + -1.49058712f, 0.08392174f, -0.04049999f, + -1.47935617f, 0.08620317f, -0.07200000f, + -1.46280551f, 0.08956527f, -0.09449999f, + -1.44270813f, 0.09364782f, -0.10800000f, + -1.42083728f, 0.09809060f, -0.11250000f, + -1.39896679f, 0.10253337f, -0.10800000f, + -1.37886930f, 0.10661593f, -0.09449999f, + -1.36231852f, 0.10997803f, -0.07200000f, + -1.35108757f, 0.11225945f, -0.04049999f, + -1.34694993f, 0.11309998f, 0.00000000f, + -1.47880006f, 0.01739999f, 0.00000000f, + -1.47484636f, 0.01889519f, -0.04050000f, + -1.46411538f, 0.02295360f, -0.07200002f, + -1.44830084f, 0.02893439f, -0.09450001f, + -1.42909777f, 0.03619680f, -0.10800002f, + -1.40820003f, 0.04409999f, -0.11250001f, + -1.38730240f, 0.05200320f, -0.10800001f, + -1.36809933f, 0.05926560f, -0.09450001f, + -1.35228491f, 0.06524640f, -0.07200001f, + -1.34155369f, 0.06930479f, -0.04049999f, + -1.33760011f, 0.07080000f, 0.00000000f, + -1.45207500f, -0.04693126f, -0.00000000f, + -1.44842303f, -0.04493257f, -0.04050000f, + -1.43851078f, -0.03950761f, -0.07200002f, + -1.42390323f, -0.03151290f, -0.09450001f, + -1.40616548f, -0.02180506f, -0.10800002f, + -1.38686240f, -0.01124063f, -0.11250001f, + -1.36755955f, -0.00067620f, -0.10800001f, + -1.34982181f, 0.00903165f, -0.09450001f, + -1.33521414f, 0.01702635f, -0.07200001f, + -1.32530189f, 0.02245133f, -0.04049999f, + -1.32164991f, 0.02445000f, 0.00000000f, + -1.41439998f, -0.10980001f, -0.00000000f, + -1.41116297f, -0.10741439f, -0.04050000f, + -1.40237772f, -0.10093922f, -0.07200000f, + -1.38943040f, -0.09139680f, -0.09450001f, + -1.37370884f, -0.07980961f, -0.10800001f, + -1.35660017f, -0.06720000f, -0.11250000f, + -1.33949125f, -0.05459040f, -0.10800000f, + -1.32376981f, -0.04300320f, -0.09450001f, + -1.31082249f, -0.03346080f, -0.07200000f, + -1.30203688f, -0.02698559f, -0.04049999f, + -1.29880011f, -0.02460000f, -0.00000000f, + -1.36562502f, -0.17109375f, -0.00000000f, + -1.36291230f, -0.16840309f, -0.04050000f, + -1.35555005f, -0.16110000f, -0.07200000f, + -1.34469998f, -0.15033749f, -0.09450001f, + -1.33152509f, -0.13726877f, -0.10800001f, + -1.31718755f, -0.12304687f, -0.11250000f, + -1.30285001f, -0.10882499f, -0.10800000f, + -1.28967500f, -0.09575625f, -0.09450001f, + -1.27882504f, -0.08499375f, -0.07200000f, + -1.27146244f, -0.07769062f, -0.04049999f, + -1.26874995f, -0.07500000f, -0.00000000f, + -1.30559993f, -0.23070000f, -0.00000000f, + -1.30351651f, -0.22775158f, -0.04050000f, + -1.29786241f, -0.21974881f, -0.07200000f, + -1.28952956f, -0.20795520f, -0.09450001f, + -1.27941132f, -0.19363441f, -0.10800001f, + -1.26839995f, -0.17805001f, -0.11250000f, + -1.25738883f, -0.16246560f, -0.10800000f, + -1.24727035f, -0.14814481f, -0.09450001f, + -1.23893762f, -0.13635120f, -0.07200000f, + -1.23328316f, -0.12834841f, -0.04049999f, + -1.23119998f, -0.12540001f, -0.00000000f, + -1.23417509f, -0.28850627f, -0.00000000f, + -1.23282194f, -0.28531265f, -0.04050000f, + -1.22914934f, -0.27664444f, -0.07200000f, + -1.22373676f, -0.26387009f, -0.09450001f, + -1.21716475f, -0.24835847f, -0.10800001f, + -1.21001267f, -0.23147814f, -0.11250000f, + -1.20286047f, -0.21459781f, -0.10800000f, + -1.19628835f, -0.19908617f, -0.09450001f, + -1.19087601f, -0.18631187f, -0.07200000f, + -1.18720317f, -0.17764360f, -0.04049999f, + -1.18585014f, -0.17445001f, -0.00000000f, + -1.15120006f, -0.34440002f, -0.00000000f, + -1.15067351f, -0.34093919f, -0.04050000f, + -1.14924490f, -0.33154565f, -0.07200001f, + -1.14713919f, -0.31770241f, -0.09450001f, + -1.14458263f, -0.30089283f, -0.10800001f, + -1.14180017f, -0.28259999f, -0.11250000f, + -1.13901758f, -0.26430720f, -0.10800000f, + -1.13646090f, -0.24749762f, -0.09450001f, + -1.13435531f, -0.23365441f, -0.07200000f, + -1.13292646f, -0.22426081f, -0.04049999f, + -1.13240004f, -0.22080001f, -0.00000000f, + -1.05652499f, -0.39826876f, -0.00000000f, + -1.05691755f, -0.39448401f, -0.04050000f, + -1.05798364f, -0.38421121f, -0.07200001f, + -1.05955434f, -0.36907232f, -0.09450001f, + -1.06146181f, -0.35068938f, -0.10800001f, + -1.06353748f, -0.33068442f, -0.11250000f, + -1.06561315f, -0.31067941f, -0.10800000f, + -1.06752062f, -0.29229647f, -0.09450001f, + -1.06909132f, -0.27715760f, -0.07200000f, + -1.07015729f, -0.26688474f, -0.04049999f, + -1.07054996f, -0.26310003f, -0.00000000f, + -0.94999999f, -0.44999999f, -0.00000001f, + -0.95139986f, -0.44579995f, -0.04050000f, + -0.95520008f, -0.43440005f, -0.07200001f, + -0.96079999f, -0.41760001f, -0.09450001f, + -0.96759999f, -0.39719999f, -0.10800001f, + -0.97500002f, -0.37500000f, -0.11250000f, + -0.98240000f, -0.35280001f, -0.10800000f, + -0.98920006f, -0.33240002f, -0.09450001f, + -0.99480003f, -0.31560001f, -0.07200000f, + -0.99860001f, -0.30419999f, -0.04049999f, + -1.00000000f, -0.30000001f, -0.00000000f, + 0.85000002f, -0.03750002f, -0.00000000f, + 0.84999996f, -0.04905002f, 0.08910000f, + 0.85000008f, -0.08040002f, 0.15840001f, + 0.85000002f, -0.12660003f, 0.20790000f, + 0.85000008f, -0.18270002f, 0.23760001f, + 0.85000002f, -0.24375001f, 0.24750000f, + 0.85000002f, -0.30480003f, 0.23760000f, + 0.85000002f, -0.36089998f, 0.20790002f, + 0.85000002f, -0.40710002f, 0.15840001f, + 0.85000002f, -0.43845001f, 0.08909997f, + 0.85000002f, -0.44999999f, -0.00000001f, + 0.96794993f, -0.02790002f, -0.00000000f, + 0.96969706f, -0.03838952f, 0.08755019f, + 0.97443962f, -0.06686102f, 0.15564480f, + 0.98142833f, -0.10881902f, 0.20428377f, + 0.98991477f, -0.15976802f, 0.23346718f, + 0.99914992f, -0.21521249f, 0.24319497f, + 1.00838506f, -0.27065700f, 0.23346716f, + 1.01687145f, -0.32160598f, 0.20428379f, + 1.02386022f, -0.36356401f, 0.15564479f, + 1.02860272f, -0.39203548f, 0.08755016f, + 1.03034985f, -0.40252498f, -0.00000000f, + 1.05560005f, -0.00120003f, -0.00000000f, + 1.05848956f, -0.01044003f, 0.08334360f, + 1.06633294f, -0.03552003f, 0.14816642f, + 1.07789123f, -0.07248003f, 0.19446841f, + 1.09192657f, -0.11736003f, 0.22224963f, + 1.10720015f, -0.16620001f, 0.23151001f, + 1.12247372f, -0.21504003f, 0.22224963f, + 1.13650894f, -0.25992000f, 0.19446844f, + 1.14806736f, -0.29688001f, 0.14816642f, + 1.15591049f, -0.32196000f, 0.08334358f, + 1.15880013f, -0.33120000f, -0.00000000f, + 1.11864996f, 0.03944998f, 0.00000000f, + 1.12222838f, 0.03158548f, 0.07714440f, + 1.13194120f, 0.01023899f, 0.13714561f, + 1.14625478f, -0.02121901f, 0.18000358f, + 1.16363573f, -0.05941800f, 0.20571840f, + 1.18255007f, -0.10098749f, 0.21428999f, + 1.20146441f, -0.14255700f, 0.20571840f, + 1.21884537f, -0.18075597f, 0.18000360f, + 1.23315883f, -0.21221398f, 0.13714559f, + 1.24287164f, -0.23356047f, 0.07714437f, + 1.24645007f, -0.24142496f, -0.00000000f, + 1.16280007f, 0.09089998f, 0.00000000f, + 1.16676486f, 0.08447397f, 0.06961680f, + 1.17752659f, 0.06703199f, 0.12376321f, + 1.19338572f, 0.04132799f, 0.16243920f, + 1.21264338f, 0.01011599f, 0.18564481f, + 1.23360014f, -0.02385001f, 0.19338000f, + 1.25455689f, -0.05781601f, 0.18564481f, + 1.27381444f, -0.08902800f, 0.16243921f, + 1.28967381f, -0.11473200f, 0.12376320f, + 1.30043530f, -0.13217400f, 0.06961678f, + 1.30440009f, -0.13859999f, -0.00000000f, + 1.19375002f, 0.14999998f, 0.00000000f, + 1.19794989f, 0.14501247f, 0.06142500f, + 1.20935011f, 0.13147499f, 0.10920001f, + 1.22614992f, 0.11152498f, 0.14332500f, + 1.24654996f, 0.08730000f, 0.16380000f, + 1.26874995f, 0.06093749f, 0.17062500f, + 1.29094982f, 0.03457499f, 0.16380000f, + 1.31134987f, 0.01035001f, 0.14332500f, + 1.32814991f, -0.00959999f, 0.10920000f, + 1.33954990f, -0.02313749f, 0.06142498f, + 1.34374988f, -0.02812499f, -0.00000000f, + 1.21719992f, 0.21360001f, 0.00000000f, + 1.22163498f, 0.20998798f, 0.05323320f, + 1.23367357f, 0.20018403f, 0.09463681f, + 1.25141430f, 0.18573602f, 0.12421080f, + 1.27295685f, 0.16819203f, 0.14195521f, + 1.29639995f, 0.14910004f, 0.14787000f, + 1.31984317f, 0.13000804f, 0.14195520f, + 1.34138560f, 0.11246406f, 0.12421081f, + 1.35912633f, 0.09801605f, 0.09463680f, + 1.37116480f, 0.08821206f, 0.05323318f, + 1.37559998f, 0.08460006f, 0.00000000f, + 1.23885000f, 0.27855000f, 0.00000000f, + 1.24367154f, 0.27618748f, 0.04570561f, + 1.25675893f, 0.26977503f, 0.08125442f, + 1.27604520f, 0.26032501f, 0.10664641f, + 1.29946446f, 0.24885003f, 0.12188162f, + 1.32495010f, 0.23636252f, 0.12696001f, + 1.35043573f, 0.22387503f, 0.12188161f, + 1.37385488f, 0.21240003f, 0.10664642f, + 1.39314127f, 0.20295003f, 0.08125441f, + 1.40622854f, 0.19653754f, 0.04570559f, + 1.41105008f, 0.19417503f, 0.00000000f, + 1.26440001f, 0.34170002f, 0.00000000f, + 1.26991034f, 0.34039798f, 0.03950640f, + 1.28486729f, 0.33686405f, 0.07023361f, + 1.30690885f, 0.33165601f, 0.09218160f, + 1.33367372f, 0.32533202f, 0.10535040f, + 1.36280000f, 0.31845003f, 0.10974000f, + 1.39192641f, 0.31156802f, 0.10535040f, + 1.41869128f, 0.30524403f, 0.09218161f, + 1.44073272f, 0.30003607f, 0.07023360f, + 1.45568967f, 0.29650205f, 0.03950639f, + 1.46120000f, 0.29520005f, 0.00000000f, + 1.29955006f, 0.39990005f, 0.00000000f, + 1.30620289f, 0.39940652f, 0.03529980f, + 1.32426059f, 0.39806706f, 0.06275520f, + 1.35087168f, 0.39609307f, 0.08236619f, + 1.38318527f, 0.39369607f, 0.09413280f, + 1.41835010f, 0.39108756f, 0.09805499f, + 1.45351493f, 0.38847905f, 0.09413280f, + 1.48582840f, 0.38608208f, 0.08236620f, + 1.51243973f, 0.38410807f, 0.06275519f, + 1.53049719f, 0.38276857f, 0.03529979f, + 1.53715003f, 0.38227507f, 0.00000000f, + 1.35000002f, 0.45000005f, 0.00000001f, + 1.35839975f, 0.44999996f, 0.03375000f, + 1.38120008f, 0.45000011f, 0.06000001f, + 1.41480005f, 0.45000002f, 0.07875000f, + 1.45560014f, 0.45000008f, 0.09000000f, + 1.50000000f, 0.45000005f, 0.09375000f, + 1.54439998f, 0.45000005f, 0.09000000f, + 1.58520007f, 0.45000008f, 0.07875000f, + 1.61880004f, 0.45000005f, 0.06000000f, + 1.64159989f, 0.45000005f, 0.03374999f, + 1.64999998f, 0.45000005f, 0.00000001f, + 0.85000002f, -0.44999999f, -0.00000001f, + 0.84999996f, -0.43844995f, -0.08910000f, + 0.85000008f, -0.40710002f, -0.15840001f, + 0.85000002f, -0.36089998f, -0.20790000f, + 0.85000008f, -0.30480000f, -0.23760001f, + 0.85000002f, -0.24375001f, -0.24750000f, + 0.85000002f, -0.18269999f, -0.23760000f, + 0.85000002f, -0.12660003f, -0.20790002f, + 0.85000002f, -0.08040002f, -0.15840001f, + 0.85000002f, -0.04905001f, -0.08909997f, + 0.85000002f, -0.03750002f, -0.00000000f, + 1.03034985f, -0.40252498f, -0.00000000f, + 1.02860260f, -0.39203545f, -0.08755019f, + 1.02386034f, -0.36356398f, -0.15564480f, + 1.01687145f, -0.32160601f, -0.20428377f, + 1.00838506f, -0.27065703f, -0.23346718f, + 0.99914992f, -0.21521249f, -0.24319497f, + 0.98991477f, -0.15976799f, -0.23346716f, + 0.98142833f, -0.10881902f, -0.20428379f, + 0.97443956f, -0.06686102f, -0.15564479f, + 0.96969712f, -0.03838951f, -0.08755016f, + 0.96794993f, -0.02790002f, -0.00000000f, + 1.15880013f, -0.33120000f, -0.00000000f, + 1.15591037f, -0.32195994f, -0.08334360f, + 1.14806736f, -0.29688004f, -0.14816642f, + 1.13650882f, -0.25992000f, -0.19446841f, + 1.12247384f, -0.21504001f, -0.22224963f, + 1.10720003f, -0.16620003f, -0.23151001f, + 1.09192646f, -0.11736001f, -0.22224963f, + 1.07789123f, -0.07248002f, -0.19446844f, + 1.06633282f, -0.03552002f, -0.14816642f, + 1.05848956f, -0.01044002f, -0.08334358f, + 1.05560005f, -0.00120003f, -0.00000000f, + 1.24645007f, -0.24142496f, -0.00000000f, + 1.24287152f, -0.23356044f, -0.07714440f, + 1.23315895f, -0.21221398f, -0.13714561f, + 1.21884525f, -0.18075597f, -0.18000358f, + 1.20146453f, -0.14255700f, -0.20571840f, + 1.18254995f, -0.10098749f, -0.21428999f, + 1.16363561f, -0.05941799f, -0.20571840f, + 1.14625478f, -0.02121901f, -0.18000360f, + 1.13194120f, 0.01023899f, -0.13714559f, + 1.12222838f, 0.03158549f, -0.07714437f, + 1.11864996f, 0.03944998f, 0.00000000f, + 1.30440009f, -0.13859999f, -0.00000000f, + 1.30043507f, -0.13217399f, -0.06961680f, + 1.28967369f, -0.11473200f, -0.12376321f, + 1.27381444f, -0.08902799f, -0.16243920f, + 1.25455701f, -0.05781601f, -0.18564481f, + 1.23360002f, -0.02385001f, -0.19338000f, + 1.21264338f, 0.01011600f, -0.18564481f, + 1.19338572f, 0.04132798f, -0.16243921f, + 1.17752647f, 0.06703199f, -0.12376320f, + 1.16676486f, 0.08447399f, -0.06961678f, + 1.16280007f, 0.09089998f, 0.00000000f, + 1.34374988f, -0.02812499f, -0.00000000f, + 1.33954978f, -0.02313748f, -0.06142500f, + 1.32814991f, -0.00959999f, -0.10920001f, + 1.31134987f, 0.01035001f, -0.14332500f, + 1.29095006f, 0.03457500f, -0.16380000f, + 1.26874995f, 0.06093749f, -0.17062500f, + 1.24654996f, 0.08730000f, -0.16380000f, + 1.22615004f, 0.11152498f, -0.14332500f, + 1.20935011f, 0.13147499f, -0.10920000f, + 1.19795001f, 0.14501248f, -0.06142498f, + 1.19375002f, 0.14999998f, 0.00000000f, + 1.37559998f, 0.08460006f, 0.00000000f, + 1.37116480f, 0.08821206f, -0.05323320f, + 1.35912645f, 0.09801605f, -0.09463680f, + 1.34138560f, 0.11246406f, -0.12421079f, + 1.31984317f, 0.13000806f, -0.14195520f, + 1.29639995f, 0.14910004f, -0.14786999f, + 1.27295685f, 0.16819203f, -0.14195520f, + 1.25141430f, 0.18573603f, -0.12421080f, + 1.23367357f, 0.20018402f, -0.09463680f, + 1.22163510f, 0.20998801f, -0.05323318f, + 1.21719992f, 0.21360001f, 0.00000000f, + 1.41105008f, 0.19417503f, 0.00000000f, + 1.40622830f, 0.19653751f, -0.04570560f, + 1.39314139f, 0.20295003f, -0.08125441f, + 1.37385488f, 0.21240002f, -0.10664640f, + 1.35043585f, 0.22387503f, -0.12188162f, + 1.32494998f, 0.23636252f, -0.12696001f, + 1.29946434f, 0.24885002f, -0.12188160f, + 1.27604532f, 0.26032501f, -0.10664640f, + 1.25675893f, 0.26977503f, -0.08125440f, + 1.24367166f, 0.27618751f, -0.04570558f, + 1.23885000f, 0.27855000f, 0.00000000f, + 1.46120000f, 0.29520005f, 0.00000000f, + 1.45568943f, 0.29650205f, -0.03950639f, + 1.44073284f, 0.30003604f, -0.07023360f, + 1.41869116f, 0.30524403f, -0.09218159f, + 1.39192653f, 0.31156805f, -0.10535039f, + 1.36280012f, 0.31845003f, -0.10973999f, + 1.33367360f, 0.32533202f, -0.10535039f, + 1.30690885f, 0.33165604f, -0.09218159f, + 1.28486729f, 0.33686402f, -0.07023359f, + 1.26991045f, 0.34039801f, -0.03950638f, + 1.26440001f, 0.34170002f, 0.00000000f, + 1.53715003f, 0.38227507f, 0.00000000f, + 1.53049695f, 0.38276854f, -0.03529979f, + 1.51243961f, 0.38410810f, -0.06275519f, + 1.48582840f, 0.38608205f, -0.08236619f, + 1.45351493f, 0.38847908f, -0.09413280f, + 1.41835010f, 0.39108753f, -0.09805499f, + 1.38318527f, 0.39369607f, -0.09413280f, + 1.35087168f, 0.39609307f, -0.08236620f, + 1.32426047f, 0.39806706f, -0.06275519f, + 1.30620289f, 0.39940655f, -0.03529978f, + 1.29955006f, 0.39990005f, 0.00000000f, + 1.64999998f, 0.45000005f, 0.00000001f, + 1.64159989f, 0.44999996f, -0.03374999f, + 1.61880016f, 0.45000011f, -0.05999999f, + 1.58519995f, 0.45000002f, -0.07874999f, + 1.54440010f, 0.45000008f, -0.09000000f, + 1.50000000f, 0.45000005f, -0.09374999f, + 1.45560002f, 0.45000005f, -0.08999999f, + 1.41480005f, 0.45000008f, -0.07875000f, + 1.38120008f, 0.45000005f, -0.05999999f, + 1.35839999f, 0.45000005f, -0.03374998f, + 1.35000002f, 0.45000005f, 0.00000001f, + 1.35000002f, 0.45000005f, 0.00000001f, + 1.35839975f, 0.44999996f, 0.03375000f, + 1.38120008f, 0.45000011f, 0.06000001f, + 1.41480005f, 0.45000002f, 0.07875000f, + 1.45560014f, 0.45000008f, 0.09000000f, + 1.50000000f, 0.45000005f, 0.09375000f, + 1.54439998f, 0.45000005f, 0.09000000f, + 1.58520007f, 0.45000008f, 0.07875000f, + 1.61880004f, 0.45000005f, 0.06000000f, + 1.64159989f, 0.45000005f, 0.03374999f, + 1.64999998f, 0.45000005f, 0.00000001f, + 1.36489987f, 0.46012494f, 0.00000001f, + 1.37370336f, 0.46020287f, 0.03337200f, + 1.39759886f, 0.46041453f, 0.05932800f, + 1.43281305f, 0.46072635f, 0.07786799f, + 1.47557306f, 0.46110505f, 0.08899199f, + 1.52210617f, 0.46151716f, 0.09269999f, + 1.56863928f, 0.46192923f, 0.08899198f, + 1.61139929f, 0.46230793f, 0.07786799f, + 1.64661360f, 0.46261978f, 0.05932799f, + 1.67050874f, 0.46283138f, 0.03337199f, + 1.67931235f, 0.46290934f, 0.00000001f, + 1.37919998f, 0.46800002f, 0.00000001f, + 1.38818228f, 0.46815118f, 0.03234600f, + 1.41256332f, 0.46856162f, 0.05750401f, + 1.44849277f, 0.46916643f, 0.07547401f, + 1.49212170f, 0.46990088f, 0.08625601f, + 1.53960001f, 0.47070009f, 0.08985001f, + 1.58707845f, 0.47149926f, 0.08625601f, + 1.63070726f, 0.47223371f, 0.07547401f, + 1.66663694f, 0.47283852f, 0.05750401f, + 1.69101763f, 0.47324890f, 0.03234600f, + 1.70000005f, 0.47340012f, 0.00000001f, + 1.39230001f, 0.47362497f, 0.00000001f, + 1.40126371f, 0.47383994f, 0.03083400f, + 1.42559445f, 0.47442356f, 0.05481601f, + 1.46144974f, 0.47528344f, 0.07194600f, + 1.50498855f, 0.47632772f, 0.08222401f, + 1.55236876f, 0.47746408f, 0.08565000f, + 1.59974909f, 0.47860044f, 0.08222400f, + 1.64328790f, 0.47964469f, 0.07194600f, + 1.67914319f, 0.48050463f, 0.05481600f, + 1.70347357f, 0.48108816f, 0.03083399f, + 1.71243751f, 0.48130316f, 0.00000001f, + 1.40359998f, 0.47700000f, 0.00000001f, + 1.41237509f, 0.47726458f, 0.02899800f, + 1.43619370f, 0.47798279f, 0.05155201f, + 1.47129452f, 0.47904122f, 0.06766201f, + 1.51391697f, 0.48032647f, 0.07732801f, + 1.56030011f, 0.48172504f, 0.08055001f, + 1.60668325f, 0.48312366f, 0.07732800f, + 1.64930582f, 0.48440886f, 0.06766201f, + 1.68440676f, 0.48546728f, 0.05155201f, + 1.70822501f, 0.48618549f, 0.02899799f, + 1.71700025f, 0.48645008f, 0.00000001f, + 1.41249990f, 0.47812498f, 0.00000001f, + 1.42094362f, 0.47842023f, 0.02700000f, + 1.44386256f, 0.47922191f, 0.04800001f, + 1.47763753f, 0.48040313f, 0.06300000f, + 1.51865005f, 0.48183754f, 0.07200000f, + 1.56328130f, 0.48339847f, 0.07500000f, + 1.60791266f, 0.48495942f, 0.07200000f, + 1.64892507f, 0.48639381f, 0.06300000f, + 1.68270016f, 0.48757505f, 0.04800000f, + 1.70561898f, 0.48837662f, 0.02700000f, + 1.71406269f, 0.48867193f, 0.00000001f, + 1.41839993f, 0.47700000f, 0.00000001f, + 1.42639649f, 0.47730237f, 0.02500200f, + 1.44810247f, 0.47812322f, 0.04444801f, + 1.48008955f, 0.47933280f, 0.05833800f, + 1.51893127f, 0.48080164f, 0.06667200f, + 1.56120014f, 0.48240003f, 0.06945001f, + 1.60346889f, 0.48399845f, 0.06667200f, + 1.64231050f, 0.48546726f, 0.05833801f, + 1.67429769f, 0.48667687f, 0.04444801f, + 1.69600332f, 0.48749766f, 0.02500200f, + 1.70400012f, 0.48780006f, 0.00000001f, + 1.42070007f, 0.47362500f, 0.00000001f, + 1.42816150f, 0.47390610f, 0.02316600f, + 1.44841480f, 0.47466925f, 0.04118401f, + 1.47826135f, 0.47579375f, 0.05405401f, + 1.51450372f, 0.47715935f, 0.06177600f, + 1.55394375f, 0.47864535f, 0.06435001f, + 1.59338403f, 0.48013136f, 0.06177600f, + 1.62962627f, 0.48149687f, 0.05405401f, + 1.65947294f, 0.48262146f, 0.04118400f, + 1.67972589f, 0.48338455f, 0.02316600f, + 1.68718755f, 0.48366567f, 0.00000001f, + 1.41880012f, 0.46799999f, 0.00000001f, + 1.42566562f, 0.46822673f, 0.02165400f, + 1.44430101f, 0.46884245f, 0.03849601f, + 1.47176325f, 0.46974963f, 0.05052601f, + 1.50511050f, 0.47085124f, 0.05774401f, + 1.54139996f, 0.47205001f, 0.06015000f, + 1.57768965f, 0.47324884f, 0.05774400f, + 1.61103690f, 0.47435045f, 0.05052601f, + 1.63849926f, 0.47525764f, 0.03849601f, + 1.65713453f, 0.47587326f, 0.02165400f, + 1.66400003f, 0.47610006f, 0.00000001f, + 1.41209996f, 0.46012503f, 0.00000001f, + 1.41833580f, 0.46025965f, 0.02062801f, + 1.43526208f, 0.46062523f, 0.03667201f, + 1.46020591f, 0.46116382f, 0.04813201f, + 1.49049485f, 0.46181795f, 0.05500801f, + 1.52345622f, 0.46252972f, 0.05730001f, + 1.55641770f, 0.46324152f, 0.05500801f, + 1.58670676f, 0.46389559f, 0.04813201f, + 1.61165047f, 0.46443427f, 0.03667201f, + 1.62857664f, 0.46479973f, 0.02062800f, + 1.63481259f, 0.46493441f, 0.00000001f, + 1.39999998f, 0.45000005f, 0.00000001f, + 1.40559983f, 0.44999996f, 0.02025001f, + 1.42079997f, 0.45000011f, 0.03600001f, + 1.44319999f, 0.45000002f, 0.04725001f, + 1.47040009f, 0.45000008f, 0.05400001f, + 1.50000000f, 0.45000005f, 0.05625001f, + 1.52960002f, 0.45000005f, 0.05400001f, + 1.55680001f, 0.45000008f, 0.04725001f, + 1.57920003f, 0.45000005f, 0.03600001f, + 1.59440005f, 0.45000005f, 0.02025000f, + 1.60000002f, 0.45000005f, 0.00000001f, + 1.64999998f, 0.45000005f, 0.00000001f, + 1.64159989f, 0.44999996f, -0.03374999f, + 1.61880016f, 0.45000011f, -0.05999999f, + 1.58519995f, 0.45000002f, -0.07874999f, + 1.54440010f, 0.45000008f, -0.09000000f, + 1.50000000f, 0.45000005f, -0.09374999f, + 1.45560002f, 0.45000005f, -0.08999999f, + 1.41480005f, 0.45000008f, -0.07875000f, + 1.38120008f, 0.45000005f, -0.05999999f, + 1.35839999f, 0.45000005f, -0.03374998f, + 1.35000002f, 0.45000005f, 0.00000001f, + 1.67931235f, 0.46290934f, 0.00000001f, + 1.67050874f, 0.46283132f, -0.03337199f, + 1.64661360f, 0.46261978f, -0.05932799f, + 1.61139941f, 0.46230793f, -0.07786798f, + 1.56863928f, 0.46192926f, -0.08899198f, + 1.52210605f, 0.46151716f, -0.09269998f, + 1.47557306f, 0.46110505f, -0.08899198f, + 1.43281293f, 0.46072638f, -0.07786798f, + 1.39759874f, 0.46041453f, -0.05932799f, + 1.37370336f, 0.46020290f, -0.03337198f, + 1.36489987f, 0.46012494f, 0.00000001f, + 1.70000005f, 0.47340012f, 0.00000001f, + 1.69101751f, 0.47324887f, -0.03234600f, + 1.66663706f, 0.47283855f, -0.05750400f, + 1.63070726f, 0.47223368f, -0.07547399f, + 1.58707845f, 0.47149929f, -0.08625600f, + 1.53960001f, 0.47070006f, -0.08985000f, + 1.49212158f, 0.46990088f, -0.08625600f, + 1.44849288f, 0.46916646f, -0.07547400f, + 1.41256320f, 0.46856165f, -0.05750399f, + 1.38818240f, 0.46815124f, -0.03234598f, + 1.37919998f, 0.46800002f, 0.00000001f, + 1.71243751f, 0.48130316f, 0.00000001f, + 1.70347345f, 0.48108810f, -0.03083399f, + 1.67914343f, 0.48050466f, -0.05481599f, + 1.64328778f, 0.47964469f, -0.07194599f, + 1.59974921f, 0.47860047f, -0.08222400f, + 1.55236864f, 0.47746405f, -0.08564999f, + 1.50498843f, 0.47632769f, -0.08222400f, + 1.46144986f, 0.47528344f, -0.07194600f, + 1.42559433f, 0.47442353f, -0.05481599f, + 1.40126395f, 0.47383997f, -0.03083398f, + 1.39230001f, 0.47362497f, 0.00000001f, + 1.71700025f, 0.48645008f, 0.00000001f, + 1.70822489f, 0.48618543f, -0.02899799f, + 1.68440676f, 0.48546731f, -0.05155200f, + 1.64930582f, 0.48440889f, -0.06766199f, + 1.60668337f, 0.48312369f, -0.07732800f, + 1.56030011f, 0.48172504f, -0.08055000f, + 1.51391685f, 0.48032641f, -0.07732800f, + 1.47129452f, 0.47904122f, -0.06766200f, + 1.43619370f, 0.47798282f, -0.05155200f, + 1.41237521f, 0.47726461f, -0.02899799f, + 1.40359998f, 0.47700000f, 0.00000001f, + 1.71406269f, 0.48867193f, 0.00000001f, + 1.70561886f, 0.48837656f, -0.02699999f, + 1.68270016f, 0.48757505f, -0.04800000f, + 1.64892519f, 0.48639381f, -0.06299999f, + 1.60791278f, 0.48495948f, -0.07200000f, + 1.56328130f, 0.48339844f, -0.07500000f, + 1.51865005f, 0.48183751f, -0.07200000f, + 1.47763753f, 0.48040313f, -0.06299999f, + 1.44386244f, 0.47922188f, -0.04799999f, + 1.42094362f, 0.47842029f, -0.02699998f, + 1.41249990f, 0.47812498f, 0.00000001f, + 1.70400012f, 0.48780006f, 0.00000001f, + 1.69600320f, 0.48749760f, -0.02500199f, + 1.67429769f, 0.48667687f, -0.04444800f, + 1.64231050f, 0.48546728f, -0.05833799f, + 1.60346901f, 0.48399848f, -0.06667200f, + 1.56120002f, 0.48240003f, -0.06944999f, + 1.51893127f, 0.48080158f, -0.06667199f, + 1.48008966f, 0.47933280f, -0.05833799f, + 1.44810236f, 0.47812319f, -0.04444799f, + 1.42639661f, 0.47730240f, -0.02500199f, + 1.41839993f, 0.47700000f, 0.00000001f, + 1.68718755f, 0.48366567f, 0.00000001f, + 1.67972589f, 0.48338449f, -0.02316599f, + 1.65947306f, 0.48262149f, -0.04118400f, + 1.62962627f, 0.48149690f, -0.05405399f, + 1.59338415f, 0.48013139f, -0.06177600f, + 1.55394387f, 0.47864535f, -0.06434999f, + 1.51450372f, 0.47715932f, -0.06177600f, + 1.47826147f, 0.47579378f, -0.05405399f, + 1.44841480f, 0.47466925f, -0.04118399f, + 1.42816162f, 0.47390613f, -0.02316599f, + 1.42070007f, 0.47362500f, 0.00000001f, + 1.66400003f, 0.47610006f, 0.00000001f, + 1.65713418f, 0.47587320f, -0.02165399f, + 1.63849938f, 0.47525769f, -0.03849600f, + 1.61103702f, 0.47435045f, -0.05052599f, + 1.57768977f, 0.47324887f, -0.05774400f, + 1.54140007f, 0.47205001f, -0.06015000f, + 1.50511050f, 0.47085121f, -0.05774400f, + 1.47176337f, 0.46974963f, -0.05052600f, + 1.44430089f, 0.46884239f, -0.03849599f, + 1.42566574f, 0.46822679f, -0.02165399f, + 1.41880012f, 0.46799999f, 0.00000001f, + 1.63481259f, 0.46493441f, 0.00000001f, + 1.62857652f, 0.46479967f, -0.02062799f, + 1.61165059f, 0.46443427f, -0.03667200f, + 1.58670664f, 0.46389559f, -0.04813199f, + 1.55641782f, 0.46324155f, -0.05500800f, + 1.52345634f, 0.46252972f, -0.05730000f, + 1.49049485f, 0.46181795f, -0.05500799f, + 1.46020591f, 0.46116385f, -0.04813200f, + 1.43526220f, 0.46062523f, -0.03667200f, + 1.41833591f, 0.46025968f, -0.02062799f, + 1.41209996f, 0.46012503f, 0.00000001f, + 1.60000002f, 0.45000005f, 0.00000001f, + 1.59439981f, 0.44999996f, -0.02024999f, + 1.57920015f, 0.45000011f, -0.03600000f, + 1.55680001f, 0.45000002f, -0.04725000f, + 1.52960002f, 0.45000008f, -0.05400000f, + 1.50000000f, 0.45000005f, -0.05625000f, + 1.47039998f, 0.45000005f, -0.05400000f, + 1.44320011f, 0.45000008f, -0.04725000f, + 1.42079997f, 0.45000005f, -0.03599999f, + 1.40559995f, 0.45000005f, -0.02024999f, + 1.39999998f, 0.45000005f, 0.00000001f, + }; + + std::vector<uint32_t> m_teapotIndices = + { + 0, 1, 11, 11, 1, 12, + 1, 2, 12, 12, 2, 13, + 2, 3, 13, 13, 3, 14, + 3, 4, 14, 14, 4, 15, + 4, 5, 15, 15, 5, 16, + 5, 6, 16, 16, 6, 17, + 6, 7, 17, 17, 7, 18, + 7, 8, 18, 18, 8, 19, + 8, 9, 19, 19, 9, 20, + 9, 10, 20, 20, 10, 21, + 11, 12, 22, 22, 12, 23, + 12, 13, 23, 23, 13, 24, + 13, 14, 24, 24, 14, 25, + 14, 15, 25, 25, 15, 26, + 15, 16, 26, 26, 16, 27, + 16, 17, 27, 27, 17, 28, + 17, 18, 28, 28, 18, 29, + 18, 19, 29, 29, 19, 30, + 19, 20, 30, 30, 20, 31, + 20, 21, 31, 31, 21, 32, + 22, 23, 33, 33, 23, 34, + 23, 24, 34, 34, 24, 35, + 24, 25, 35, 35, 25, 36, + 25, 26, 36, 36, 26, 37, + 26, 27, 37, 37, 27, 38, + 27, 28, 38, 38, 28, 39, + 28, 29, 39, 39, 29, 40, + 29, 30, 40, 40, 30, 41, + 30, 31, 41, 41, 31, 42, + 31, 32, 42, 42, 32, 43, + 33, 34, 44, 44, 34, 45, + 34, 35, 45, 45, 35, 46, + 35, 36, 46, 46, 36, 47, + 36, 37, 47, 47, 37, 48, + 37, 38, 48, 48, 38, 49, + 38, 39, 49, 49, 39, 50, + 39, 40, 50, 50, 40, 51, + 40, 41, 51, 51, 41, 52, + 41, 42, 52, 52, 42, 53, + 42, 43, 53, 53, 43, 54, + 44, 45, 55, 55, 45, 56, + 45, 46, 56, 56, 46, 57, + 46, 47, 57, 57, 47, 58, + 47, 48, 58, 58, 48, 59, + 48, 49, 59, 59, 49, 60, + 49, 50, 60, 60, 50, 61, + 50, 51, 61, 61, 51, 62, + 51, 52, 62, 62, 52, 63, + 52, 53, 63, 63, 53, 64, + 53, 54, 64, 64, 54, 65, + 55, 56, 66, 66, 56, 67, + 56, 57, 67, 67, 57, 68, + 57, 58, 68, 68, 58, 69, + 58, 59, 69, 69, 59, 70, + 59, 60, 70, 70, 60, 71, + 60, 61, 71, 71, 61, 72, + 61, 62, 72, 72, 62, 73, + 62, 63, 73, 73, 63, 74, + 63, 64, 74, 74, 64, 75, + 64, 65, 75, 75, 65, 76, + 66, 67, 77, 77, 67, 78, + 67, 68, 78, 78, 68, 79, + 68, 69, 79, 79, 69, 80, + 69, 70, 80, 80, 70, 81, + 70, 71, 81, 81, 71, 82, + 71, 72, 82, 82, 72, 83, + 72, 73, 83, 83, 73, 84, + 73, 74, 84, 84, 74, 85, + 74, 75, 85, 85, 75, 86, + 75, 76, 86, 86, 76, 87, + 77, 78, 88, 88, 78, 89, + 78, 79, 89, 89, 79, 90, + 79, 80, 90, 90, 80, 91, + 80, 81, 91, 91, 81, 92, + 81, 82, 92, 92, 82, 93, + 82, 83, 93, 93, 83, 94, + 83, 84, 94, 94, 84, 95, + 84, 85, 95, 95, 85, 96, + 85, 86, 96, 96, 86, 97, + 86, 87, 97, 97, 87, 98, + 88, 89, 99, 99, 89, 100, + 89, 90, 100, 100, 90, 101, + 90, 91, 101, 101, 91, 102, + 91, 92, 102, 102, 92, 103, + 92, 93, 103, 103, 93, 104, + 93, 94, 104, 104, 94, 105, + 94, 95, 105, 105, 95, 106, + 95, 96, 106, 106, 96, 107, + 96, 97, 107, 107, 97, 108, + 97, 98, 108, 108, 98, 109, + 99, 100, 110, 110, 100, 111, + 100, 101, 111, 111, 101, 112, + 101, 102, 112, 112, 102, 113, + 102, 103, 113, 113, 103, 114, + 103, 104, 114, 114, 104, 115, + 104, 105, 115, 115, 105, 116, + 105, 106, 116, 116, 106, 117, + 106, 107, 117, 117, 107, 118, + 107, 108, 118, 118, 108, 119, + 108, 109, 119, 119, 109, 120, + 121, 122, 132, 132, 122, 133, + 122, 123, 133, 133, 123, 134, + 123, 124, 134, 134, 124, 135, + 124, 125, 135, 135, 125, 136, + 125, 126, 136, 136, 126, 137, + 126, 127, 137, 137, 127, 138, + 127, 128, 138, 138, 128, 139, + 128, 129, 139, 139, 129, 140, + 129, 130, 140, 140, 130, 141, + 130, 131, 141, 141, 131, 142, + 132, 133, 143, 143, 133, 144, + 133, 134, 144, 144, 134, 145, + 134, 135, 145, 145, 135, 146, + 135, 136, 146, 146, 136, 147, + 136, 137, 147, 147, 137, 148, + 137, 138, 148, 148, 138, 149, + 138, 139, 149, 149, 139, 150, + 139, 140, 150, 150, 140, 151, + 140, 141, 151, 151, 141, 152, + 141, 142, 152, 152, 142, 153, + 143, 144, 154, 154, 144, 155, + 144, 145, 155, 155, 145, 156, + 145, 146, 156, 156, 146, 157, + 146, 147, 157, 157, 147, 158, + 147, 148, 158, 158, 148, 159, + 148, 149, 159, 159, 149, 160, + 149, 150, 160, 160, 150, 161, + 150, 151, 161, 161, 151, 162, + 151, 152, 162, 162, 152, 163, + 152, 153, 163, 163, 153, 164, + 154, 155, 165, 165, 155, 166, + 155, 156, 166, 166, 156, 167, + 156, 157, 167, 167, 157, 168, + 157, 158, 168, 168, 158, 169, + 158, 159, 169, 169, 159, 170, + 159, 160, 170, 170, 160, 171, + 160, 161, 171, 171, 161, 172, + 161, 162, 172, 172, 162, 173, + 162, 163, 173, 173, 163, 174, + 163, 164, 174, 174, 164, 175, + 165, 166, 176, 176, 166, 177, + 166, 167, 177, 177, 167, 178, + 167, 168, 178, 178, 168, 179, + 168, 169, 179, 179, 169, 180, + 169, 170, 180, 180, 170, 181, + 170, 171, 181, 181, 171, 182, + 171, 172, 182, 182, 172, 183, + 172, 173, 183, 183, 173, 184, + 173, 174, 184, 184, 174, 185, + 174, 175, 185, 185, 175, 186, + 176, 177, 187, 187, 177, 188, + 177, 178, 188, 188, 178, 189, + 178, 179, 189, 189, 179, 190, + 179, 180, 190, 190, 180, 191, + 180, 181, 191, 191, 181, 192, + 181, 182, 192, 192, 182, 193, + 182, 183, 193, 193, 183, 194, + 183, 184, 194, 194, 184, 195, + 184, 185, 195, 195, 185, 196, + 185, 186, 196, 196, 186, 197, + 187, 188, 198, 198, 188, 199, + 188, 189, 199, 199, 189, 200, + 189, 190, 200, 200, 190, 201, + 190, 191, 201, 201, 191, 202, + 191, 192, 202, 202, 192, 203, + 192, 193, 203, 203, 193, 204, + 193, 194, 204, 204, 194, 205, + 194, 195, 205, 205, 195, 206, + 195, 196, 206, 206, 196, 207, + 196, 197, 207, 207, 197, 208, + 198, 199, 209, 209, 199, 210, + 199, 200, 210, 210, 200, 211, + 200, 201, 211, 211, 201, 212, + 201, 202, 212, 212, 202, 213, + 202, 203, 213, 213, 203, 214, + 203, 204, 214, 214, 204, 215, + 204, 205, 215, 215, 205, 216, + 205, 206, 216, 216, 206, 217, + 206, 207, 217, 217, 207, 218, + 207, 208, 218, 218, 208, 219, + 209, 210, 220, 220, 210, 221, + 210, 211, 221, 221, 211, 222, + 211, 212, 222, 222, 212, 223, + 212, 213, 223, 223, 213, 224, + 213, 214, 224, 224, 214, 225, + 214, 215, 225, 225, 215, 226, + 215, 216, 226, 226, 216, 227, + 216, 217, 227, 227, 217, 228, + 217, 218, 228, 228, 218, 229, + 218, 219, 229, 229, 219, 230, + 220, 221, 231, 231, 221, 232, + 221, 222, 232, 232, 222, 233, + 222, 223, 233, 233, 223, 234, + 223, 224, 234, 234, 224, 235, + 224, 225, 235, 235, 225, 236, + 225, 226, 236, 236, 226, 237, + 226, 227, 237, 237, 227, 238, + 227, 228, 238, 238, 228, 239, + 228, 229, 239, 239, 229, 240, + 229, 230, 240, 240, 230, 241, + 242, 243, 253, 253, 243, 254, + 243, 244, 254, 254, 244, 255, + 244, 245, 255, 255, 245, 256, + 245, 246, 256, 256, 246, 257, + 246, 247, 257, 257, 247, 258, + 247, 248, 258, 258, 248, 259, + 248, 249, 259, 259, 249, 260, + 249, 250, 260, 260, 250, 261, + 250, 251, 261, 261, 251, 262, + 251, 252, 262, 262, 252, 263, + 253, 254, 264, 264, 254, 265, + 254, 255, 265, 265, 255, 266, + 255, 256, 266, 266, 256, 267, + 256, 257, 267, 267, 257, 268, + 257, 258, 268, 268, 258, 269, + 258, 259, 269, 269, 259, 270, + 259, 260, 270, 270, 260, 271, + 260, 261, 271, 271, 261, 272, + 261, 262, 272, 272, 262, 273, + 262, 263, 273, 273, 263, 274, + 264, 265, 275, 275, 265, 276, + 265, 266, 276, 276, 266, 277, + 266, 267, 277, 277, 267, 278, + 267, 268, 278, 278, 268, 279, + 268, 269, 279, 279, 269, 280, + 269, 270, 280, 280, 270, 281, + 270, 271, 281, 281, 271, 282, + 271, 272, 282, 282, 272, 283, + 272, 273, 283, 283, 273, 284, + 273, 274, 284, 284, 274, 285, + 275, 276, 286, 286, 276, 287, + 276, 277, 287, 287, 277, 288, + 277, 278, 288, 288, 278, 289, + 278, 279, 289, 289, 279, 290, + 279, 280, 290, 290, 280, 291, + 280, 281, 291, 291, 281, 292, + 281, 282, 292, 292, 282, 293, + 282, 283, 293, 293, 283, 294, + 283, 284, 294, 294, 284, 295, + 284, 285, 295, 295, 285, 296, + 286, 287, 297, 297, 287, 298, + 287, 288, 298, 298, 288, 299, + 288, 289, 299, 299, 289, 300, + 289, 290, 300, 300, 290, 301, + 290, 291, 301, 301, 291, 302, + 291, 292, 302, 302, 292, 303, + 292, 293, 303, 303, 293, 304, + 293, 294, 304, 304, 294, 305, + 294, 295, 305, 305, 295, 306, + 295, 296, 306, 306, 296, 307, + 297, 298, 308, 308, 298, 309, + 298, 299, 309, 309, 299, 310, + 299, 300, 310, 310, 300, 311, + 300, 301, 311, 311, 301, 312, + 301, 302, 312, 312, 302, 313, + 302, 303, 313, 313, 303, 314, + 303, 304, 314, 314, 304, 315, + 304, 305, 315, 315, 305, 316, + 305, 306, 316, 316, 306, 317, + 306, 307, 317, 317, 307, 318, + 308, 309, 319, 319, 309, 320, + 309, 310, 320, 320, 310, 321, + 310, 311, 321, 321, 311, 322, + 311, 312, 322, 322, 312, 323, + 312, 313, 323, 323, 313, 324, + 313, 314, 324, 324, 314, 325, + 314, 315, 325, 325, 315, 326, + 315, 316, 326, 326, 316, 327, + 316, 317, 327, 327, 317, 328, + 317, 318, 328, 328, 318, 329, + 319, 320, 330, 330, 320, 331, + 320, 321, 331, 331, 321, 332, + 321, 322, 332, 332, 322, 333, + 322, 323, 333, 333, 323, 334, + 323, 324, 334, 334, 324, 335, + 324, 325, 335, 335, 325, 336, + 325, 326, 336, 336, 326, 337, + 326, 327, 337, 337, 327, 338, + 327, 328, 338, 338, 328, 339, + 328, 329, 339, 339, 329, 340, + 330, 331, 341, 341, 331, 342, + 331, 332, 342, 342, 332, 343, + 332, 333, 343, 343, 333, 344, + 333, 334, 344, 344, 334, 345, + 334, 335, 345, 345, 335, 346, + 335, 336, 346, 346, 336, 347, + 336, 337, 347, 347, 337, 348, + 337, 338, 348, 348, 338, 349, + 338, 339, 349, 349, 339, 350, + 339, 340, 350, 350, 340, 351, + 341, 342, 352, 352, 342, 353, + 342, 343, 353, 353, 343, 354, + 343, 344, 354, 354, 344, 355, + 344, 345, 355, 355, 345, 356, + 345, 346, 356, 356, 346, 357, + 346, 347, 357, 357, 347, 358, + 347, 348, 358, 358, 348, 359, + 348, 349, 359, 359, 349, 360, + 349, 350, 360, 360, 350, 361, + 350, 351, 361, 361, 351, 362, + 363, 364, 374, 374, 364, 375, + 364, 365, 375, 375, 365, 376, + 365, 366, 376, 376, 366, 377, + 366, 367, 377, 377, 367, 378, + 367, 368, 378, 378, 368, 379, + 368, 369, 379, 379, 369, 380, + 369, 370, 380, 380, 370, 381, + 370, 371, 381, 381, 371, 382, + 371, 372, 382, 382, 372, 383, + 372, 373, 383, 383, 373, 384, + 374, 375, 385, 385, 375, 386, + 375, 376, 386, 386, 376, 387, + 376, 377, 387, 387, 377, 388, + 377, 378, 388, 388, 378, 389, + 378, 379, 389, 389, 379, 390, + 379, 380, 390, 390, 380, 391, + 380, 381, 391, 391, 381, 392, + 381, 382, 392, 392, 382, 393, + 382, 383, 393, 393, 383, 394, + 383, 384, 394, 394, 384, 395, + 385, 386, 396, 396, 386, 397, + 386, 387, 397, 397, 387, 398, + 387, 388, 398, 398, 388, 399, + 388, 389, 399, 399, 389, 400, + 389, 390, 400, 400, 390, 401, + 390, 391, 401, 401, 391, 402, + 391, 392, 402, 402, 392, 403, + 392, 393, 403, 403, 393, 404, + 393, 394, 404, 404, 394, 405, + 394, 395, 405, 405, 395, 406, + 396, 397, 407, 407, 397, 408, + 397, 398, 408, 408, 398, 409, + 398, 399, 409, 409, 399, 410, + 399, 400, 410, 410, 400, 411, + 400, 401, 411, 411, 401, 412, + 401, 402, 412, 412, 402, 413, + 402, 403, 413, 413, 403, 414, + 403, 404, 414, 414, 404, 415, + 404, 405, 415, 415, 405, 416, + 405, 406, 416, 416, 406, 417, + 407, 408, 418, 418, 408, 419, + 408, 409, 419, 419, 409, 420, + 409, 410, 420, 420, 410, 421, + 410, 411, 421, 421, 411, 422, + 411, 412, 422, 422, 412, 423, + 412, 413, 423, 423, 413, 424, + 413, 414, 424, 424, 414, 425, + 414, 415, 425, 425, 415, 426, + 415, 416, 426, 426, 416, 427, + 416, 417, 427, 427, 417, 428, + 418, 419, 429, 429, 419, 430, + 419, 420, 430, 430, 420, 431, + 420, 421, 431, 431, 421, 432, + 421, 422, 432, 432, 422, 433, + 422, 423, 433, 433, 423, 434, + 423, 424, 434, 434, 424, 435, + 424, 425, 435, 435, 425, 436, + 425, 426, 436, 436, 426, 437, + 426, 427, 437, 437, 427, 438, + 427, 428, 438, 438, 428, 439, + 429, 430, 440, 440, 430, 441, + 430, 431, 441, 441, 431, 442, + 431, 432, 442, 442, 432, 443, + 432, 433, 443, 443, 433, 444, + 433, 434, 444, 444, 434, 445, + 434, 435, 445, 445, 435, 446, + 435, 436, 446, 446, 436, 447, + 436, 437, 447, 447, 437, 448, + 437, 438, 448, 448, 438, 449, + 438, 439, 449, 449, 439, 450, + 440, 441, 451, 451, 441, 452, + 441, 442, 452, 452, 442, 453, + 442, 443, 453, 453, 443, 454, + 443, 444, 454, 454, 444, 455, + 444, 445, 455, 455, 445, 456, + 445, 446, 456, 456, 446, 457, + 446, 447, 457, 457, 447, 458, + 447, 448, 458, 458, 448, 459, + 448, 449, 459, 459, 449, 460, + 449, 450, 460, 460, 450, 461, + 451, 452, 462, 462, 452, 463, + 452, 453, 463, 463, 453, 464, + 453, 454, 464, 464, 454, 465, + 454, 455, 465, 465, 455, 466, + 455, 456, 466, 466, 456, 467, + 456, 457, 467, 467, 457, 468, + 457, 458, 468, 468, 458, 469, + 458, 459, 469, 469, 459, 470, + 459, 460, 470, 470, 460, 471, + 460, 461, 471, 471, 461, 472, + 462, 463, 473, 473, 463, 474, + 463, 464, 474, 474, 464, 475, + 464, 465, 475, 475, 465, 476, + 465, 466, 476, 476, 466, 477, + 466, 467, 477, 477, 467, 478, + 467, 468, 478, 478, 468, 479, + 468, 469, 479, 479, 469, 480, + 469, 470, 480, 480, 470, 481, + 470, 471, 481, 481, 471, 482, + 471, 472, 482, 482, 472, 483, + 484, 485, 495, 495, 485, 496, + 485, 486, 496, 496, 486, 497, + 486, 487, 497, 497, 487, 498, + 487, 488, 498, 498, 488, 499, + 488, 489, 499, 499, 489, 500, + 489, 490, 500, 500, 490, 501, + 490, 491, 501, 501, 491, 502, + 491, 492, 502, 502, 492, 503, + 492, 493, 503, 503, 493, 504, + 493, 494, 504, 504, 494, 505, + 495, 496, 506, 506, 496, 507, + 496, 497, 507, 507, 497, 508, + 497, 498, 508, 508, 498, 509, + 498, 499, 509, 509, 499, 510, + 499, 500, 510, 510, 500, 511, + 500, 501, 511, 511, 501, 512, + 501, 502, 512, 512, 502, 513, + 502, 503, 513, 513, 503, 514, + 503, 504, 514, 514, 504, 515, + 504, 505, 515, 515, 505, 516, + 506, 507, 517, 517, 507, 518, + 507, 508, 518, 518, 508, 519, + 508, 509, 519, 519, 509, 520, + 509, 510, 520, 520, 510, 521, + 510, 511, 521, 521, 511, 522, + 511, 512, 522, 522, 512, 523, + 512, 513, 523, 523, 513, 524, + 513, 514, 524, 524, 514, 525, + 514, 515, 525, 525, 515, 526, + 515, 516, 526, 526, 516, 527, + 517, 518, 528, 528, 518, 529, + 518, 519, 529, 529, 519, 530, + 519, 520, 530, 530, 520, 531, + 520, 521, 531, 531, 521, 532, + 521, 522, 532, 532, 522, 533, + 522, 523, 533, 533, 523, 534, + 523, 524, 534, 534, 524, 535, + 524, 525, 535, 535, 525, 536, + 525, 526, 536, 536, 526, 537, + 526, 527, 537, 537, 527, 538, + 528, 529, 539, 539, 529, 540, + 529, 530, 540, 540, 530, 541, + 530, 531, 541, 541, 531, 542, + 531, 532, 542, 542, 532, 543, + 532, 533, 543, 543, 533, 544, + 533, 534, 544, 544, 534, 545, + 534, 535, 545, 545, 535, 546, + 535, 536, 546, 546, 536, 547, + 536, 537, 547, 547, 537, 548, + 537, 538, 548, 548, 538, 549, + 539, 540, 550, 550, 540, 551, + 540, 541, 551, 551, 541, 552, + 541, 542, 552, 552, 542, 553, + 542, 543, 553, 553, 543, 554, + 543, 544, 554, 554, 544, 555, + 544, 545, 555, 555, 545, 556, + 545, 546, 556, 556, 546, 557, + 546, 547, 557, 557, 547, 558, + 547, 548, 558, 558, 548, 559, + 548, 549, 559, 559, 549, 560, + 550, 551, 561, 561, 551, 562, + 551, 552, 562, 562, 552, 563, + 552, 553, 563, 563, 553, 564, + 553, 554, 564, 564, 554, 565, + 554, 555, 565, 565, 555, 566, + 555, 556, 566, 566, 556, 567, + 556, 557, 567, 567, 557, 568, + 557, 558, 568, 568, 558, 569, + 558, 559, 569, 569, 559, 570, + 559, 560, 570, 570, 560, 571, + 561, 562, 572, 572, 562, 573, + 562, 563, 573, 573, 563, 574, + 563, 564, 574, 574, 564, 575, + 564, 565, 575, 575, 565, 576, + 565, 566, 576, 576, 566, 577, + 566, 567, 577, 577, 567, 578, + 567, 568, 578, 578, 568, 579, + 568, 569, 579, 579, 569, 580, + 569, 570, 580, 580, 570, 581, + 570, 571, 581, 581, 571, 582, + 572, 573, 583, 583, 573, 584, + 573, 574, 584, 584, 574, 585, + 574, 575, 585, 585, 575, 586, + 575, 576, 586, 586, 576, 587, + 576, 577, 587, 587, 577, 588, + 577, 578, 588, 588, 578, 589, + 578, 579, 589, 589, 579, 590, + 579, 580, 590, 590, 580, 591, + 580, 581, 591, 591, 581, 592, + 581, 582, 592, 592, 582, 593, + 583, 584, 594, 594, 584, 595, + 584, 585, 595, 595, 585, 596, + 585, 586, 596, 596, 586, 597, + 586, 587, 597, 597, 587, 598, + 587, 588, 598, 598, 588, 599, + 588, 589, 599, 599, 589, 600, + 589, 590, 600, 600, 590, 601, + 590, 591, 601, 601, 591, 602, + 591, 592, 602, 602, 592, 603, + 592, 593, 603, 603, 593, 604, + 605, 606, 616, 616, 606, 617, + 606, 607, 617, 617, 607, 618, + 607, 608, 618, 618, 608, 619, + 608, 609, 619, 619, 609, 620, + 609, 610, 620, 620, 610, 621, + 610, 611, 621, 621, 611, 622, + 611, 612, 622, 622, 612, 623, + 612, 613, 623, 623, 613, 624, + 613, 614, 624, 624, 614, 625, + 614, 615, 625, 625, 615, 626, + 616, 617, 627, 627, 617, 628, + 617, 618, 628, 628, 618, 629, + 618, 619, 629, 629, 619, 630, + 619, 620, 630, 630, 620, 631, + 620, 621, 631, 631, 621, 632, + 621, 622, 632, 632, 622, 633, + 622, 623, 633, 633, 623, 634, + 623, 624, 634, 634, 624, 635, + 624, 625, 635, 635, 625, 636, + 625, 626, 636, 636, 626, 637, + 627, 628, 638, 638, 628, 639, + 628, 629, 639, 639, 629, 640, + 629, 630, 640, 640, 630, 641, + 630, 631, 641, 641, 631, 642, + 631, 632, 642, 642, 632, 643, + 632, 633, 643, 643, 633, 644, + 633, 634, 644, 644, 634, 645, + 634, 635, 645, 645, 635, 646, + 635, 636, 646, 646, 636, 647, + 636, 637, 647, 647, 637, 648, + 638, 639, 649, 649, 639, 650, + 639, 640, 650, 650, 640, 651, + 640, 641, 651, 651, 641, 652, + 641, 642, 652, 652, 642, 653, + 642, 643, 653, 653, 643, 654, + 643, 644, 654, 654, 644, 655, + 644, 645, 655, 655, 645, 656, + 645, 646, 656, 656, 646, 657, + 646, 647, 657, 657, 647, 658, + 647, 648, 658, 658, 648, 659, + 649, 650, 660, 660, 650, 661, + 650, 651, 661, 661, 651, 662, + 651, 652, 662, 662, 652, 663, + 652, 653, 663, 663, 653, 664, + 653, 654, 664, 664, 654, 665, + 654, 655, 665, 665, 655, 666, + 655, 656, 666, 666, 656, 667, + 656, 657, 667, 667, 657, 668, + 657, 658, 668, 668, 658, 669, + 658, 659, 669, 669, 659, 670, + 660, 661, 671, 671, 661, 672, + 661, 662, 672, 672, 662, 673, + 662, 663, 673, 673, 663, 674, + 663, 664, 674, 674, 664, 675, + 664, 665, 675, 675, 665, 676, + 665, 666, 676, 676, 666, 677, + 666, 667, 677, 677, 667, 678, + 667, 668, 678, 678, 668, 679, + 668, 669, 679, 679, 669, 680, + 669, 670, 680, 680, 670, 681, + 671, 672, 682, 682, 672, 683, + 672, 673, 683, 683, 673, 684, + 673, 674, 684, 684, 674, 685, + 674, 675, 685, 685, 675, 686, + 675, 676, 686, 686, 676, 687, + 676, 677, 687, 687, 677, 688, + 677, 678, 688, 688, 678, 689, + 678, 679, 689, 689, 679, 690, + 679, 680, 690, 690, 680, 691, + 680, 681, 691, 691, 681, 692, + 682, 683, 693, 693, 683, 694, + 683, 684, 694, 694, 684, 695, + 684, 685, 695, 695, 685, 696, + 685, 686, 696, 696, 686, 697, + 686, 687, 697, 697, 687, 698, + 687, 688, 698, 698, 688, 699, + 688, 689, 699, 699, 689, 700, + 689, 690, 700, 700, 690, 701, + 690, 691, 701, 701, 691, 702, + 691, 692, 702, 702, 692, 703, + 693, 694, 704, 704, 694, 705, + 694, 695, 705, 705, 695, 706, + 695, 696, 706, 706, 696, 707, + 696, 697, 707, 707, 697, 708, + 697, 698, 708, 708, 698, 709, + 698, 699, 709, 709, 699, 710, + 699, 700, 710, 710, 700, 711, + 700, 701, 711, 711, 701, 712, + 701, 702, 712, 712, 702, 713, + 702, 703, 713, 713, 703, 714, + 704, 705, 715, 715, 705, 716, + 705, 706, 716, 716, 706, 717, + 706, 707, 717, 717, 707, 718, + 707, 708, 718, 718, 708, 719, + 708, 709, 719, 719, 709, 720, + 709, 710, 720, 720, 710, 721, + 710, 711, 721, 721, 711, 722, + 711, 712, 722, 722, 712, 723, + 712, 713, 723, 723, 713, 724, + 713, 714, 724, 724, 714, 725, + 726, 727, 737, 737, 727, 738, + 727, 728, 738, 738, 728, 739, + 728, 729, 739, 739, 729, 740, + 729, 730, 740, 740, 730, 741, + 730, 731, 741, 741, 731, 742, + 731, 732, 742, 742, 732, 743, + 732, 733, 743, 743, 733, 744, + 733, 734, 744, 744, 734, 745, + 734, 735, 745, 745, 735, 746, + 735, 736, 746, 746, 736, 747, + 737, 738, 748, 748, 738, 749, + 738, 739, 749, 749, 739, 750, + 739, 740, 750, 750, 740, 751, + 740, 741, 751, 751, 741, 752, + 741, 742, 752, 752, 742, 753, + 742, 743, 753, 753, 743, 754, + 743, 744, 754, 754, 744, 755, + 744, 745, 755, 755, 745, 756, + 745, 746, 756, 756, 746, 757, + 746, 747, 757, 757, 747, 758, + 748, 749, 759, 759, 749, 760, + 749, 750, 760, 760, 750, 761, + 750, 751, 761, 761, 751, 762, + 751, 752, 762, 762, 752, 763, + 752, 753, 763, 763, 753, 764, + 753, 754, 764, 764, 754, 765, + 754, 755, 765, 765, 755, 766, + 755, 756, 766, 766, 756, 767, + 756, 757, 767, 767, 757, 768, + 757, 758, 768, 768, 758, 769, + 759, 760, 770, 770, 760, 771, + 760, 761, 771, 771, 761, 772, + 761, 762, 772, 772, 762, 773, + 762, 763, 773, 773, 763, 774, + 763, 764, 774, 774, 764, 775, + 764, 765, 775, 775, 765, 776, + 765, 766, 776, 776, 766, 777, + 766, 767, 777, 777, 767, 778, + 767, 768, 778, 778, 768, 779, + 768, 769, 779, 779, 769, 780, + 770, 771, 781, 781, 771, 782, + 771, 772, 782, 782, 772, 783, + 772, 773, 783, 783, 773, 784, + 773, 774, 784, 784, 774, 785, + 774, 775, 785, 785, 775, 786, + 775, 776, 786, 786, 776, 787, + 776, 777, 787, 787, 777, 788, + 777, 778, 788, 788, 778, 789, + 778, 779, 789, 789, 779, 790, + 779, 780, 790, 790, 780, 791, + 781, 782, 792, 792, 782, 793, + 782, 783, 793, 793, 783, 794, + 783, 784, 794, 794, 784, 795, + 784, 785, 795, 795, 785, 796, + 785, 786, 796, 796, 786, 797, + 786, 787, 797, 797, 787, 798, + 787, 788, 798, 798, 788, 799, + 788, 789, 799, 799, 789, 800, + 789, 790, 800, 800, 790, 801, + 790, 791, 801, 801, 791, 802, + 792, 793, 803, 803, 793, 804, + 793, 794, 804, 804, 794, 805, + 794, 795, 805, 805, 795, 806, + 795, 796, 806, 806, 796, 807, + 796, 797, 807, 807, 797, 808, + 797, 798, 808, 808, 798, 809, + 798, 799, 809, 809, 799, 810, + 799, 800, 810, 810, 800, 811, + 800, 801, 811, 811, 801, 812, + 801, 802, 812, 812, 802, 813, + 803, 804, 814, 814, 804, 815, + 804, 805, 815, 815, 805, 816, + 805, 806, 816, 816, 806, 817, + 806, 807, 817, 817, 807, 818, + 807, 808, 818, 818, 808, 819, + 808, 809, 819, 819, 809, 820, + 809, 810, 820, 820, 810, 821, + 810, 811, 821, 821, 811, 822, + 811, 812, 822, 822, 812, 823, + 812, 813, 823, 823, 813, 824, + 814, 815, 825, 825, 815, 826, + 815, 816, 826, 826, 816, 827, + 816, 817, 827, 827, 817, 828, + 817, 818, 828, 828, 818, 829, + 818, 819, 829, 829, 819, 830, + 819, 820, 830, 830, 820, 831, + 820, 821, 831, 831, 821, 832, + 821, 822, 832, 832, 822, 833, + 822, 823, 833, 833, 823, 834, + 823, 824, 834, 834, 824, 835, + 825, 826, 836, 836, 826, 837, + 826, 827, 837, 837, 827, 838, + 827, 828, 838, 838, 828, 839, + 828, 829, 839, 839, 829, 840, + 829, 830, 840, 840, 830, 841, + 830, 831, 841, 841, 831, 842, + 831, 832, 842, 842, 832, 843, + 832, 833, 843, 843, 833, 844, + 833, 834, 844, 844, 834, 845, + 834, 835, 845, 845, 835, 846, + 847, 848, 858, 858, 848, 859, + 848, 849, 859, 859, 849, 860, + 849, 850, 860, 860, 850, 861, + 850, 851, 861, 861, 851, 862, + 851, 852, 862, 862, 852, 863, + 852, 853, 863, 863, 853, 864, + 853, 854, 864, 864, 854, 865, + 854, 855, 865, 865, 855, 866, + 855, 856, 866, 866, 856, 867, + 856, 857, 867, 867, 857, 868, + 858, 859, 869, 869, 859, 870, + 859, 860, 870, 870, 860, 871, + 860, 861, 871, 871, 861, 872, + 861, 862, 872, 872, 862, 873, + 862, 863, 873, 873, 863, 874, + 863, 864, 874, 874, 864, 875, + 864, 865, 875, 875, 865, 876, + 865, 866, 876, 876, 866, 877, + 866, 867, 877, 877, 867, 878, + 867, 868, 878, 878, 868, 879, + 869, 870, 880, 880, 870, 881, + 870, 871, 881, 881, 871, 882, + 871, 872, 882, 882, 872, 883, + 872, 873, 883, 883, 873, 884, + 873, 874, 884, 884, 874, 885, + 874, 875, 885, 885, 875, 886, + 875, 876, 886, 886, 876, 887, + 876, 877, 887, 887, 877, 888, + 877, 878, 888, 888, 878, 889, + 878, 879, 889, 889, 879, 890, + 880, 881, 891, 891, 881, 892, + 881, 882, 892, 892, 882, 893, + 882, 883, 893, 893, 883, 894, + 883, 884, 894, 894, 884, 895, + 884, 885, 895, 895, 885, 896, + 885, 886, 896, 896, 886, 897, + 886, 887, 897, 897, 887, 898, + 887, 888, 898, 898, 888, 899, + 888, 889, 899, 899, 889, 900, + 889, 890, 900, 900, 890, 901, + 891, 892, 902, 902, 892, 903, + 892, 893, 903, 903, 893, 904, + 893, 894, 904, 904, 894, 905, + 894, 895, 905, 905, 895, 906, + 895, 896, 906, 906, 896, 907, + 896, 897, 907, 907, 897, 908, + 897, 898, 908, 908, 898, 909, + 898, 899, 909, 909, 899, 910, + 899, 900, 910, 910, 900, 911, + 900, 901, 911, 911, 901, 912, + 902, 903, 913, 913, 903, 914, + 903, 904, 914, 914, 904, 915, + 904, 905, 915, 915, 905, 916, + 905, 906, 916, 916, 906, 917, + 906, 907, 917, 917, 907, 918, + 907, 908, 918, 918, 908, 919, + 908, 909, 919, 919, 909, 920, + 909, 910, 920, 920, 910, 921, + 910, 911, 921, 921, 911, 922, + 911, 912, 922, 922, 912, 923, + 913, 914, 924, 924, 914, 925, + 914, 915, 925, 925, 915, 926, + 915, 916, 926, 926, 916, 927, + 916, 917, 927, 927, 917, 928, + 917, 918, 928, 928, 918, 929, + 918, 919, 929, 929, 919, 930, + 919, 920, 930, 930, 920, 931, + 920, 921, 931, 931, 921, 932, + 921, 922, 932, 932, 922, 933, + 922, 923, 933, 933, 923, 934, + 924, 925, 935, 935, 925, 936, + 925, 926, 936, 936, 926, 937, + 926, 927, 937, 937, 927, 938, + 927, 928, 938, 938, 928, 939, + 928, 929, 939, 939, 929, 940, + 929, 930, 940, 940, 930, 941, + 930, 931, 941, 941, 931, 942, + 931, 932, 942, 942, 932, 943, + 932, 933, 943, 943, 933, 944, + 933, 934, 944, 944, 934, 945, + 935, 936, 946, 946, 936, 947, + 936, 937, 947, 947, 937, 948, + 937, 938, 948, 948, 938, 949, + 938, 939, 949, 949, 939, 950, + 939, 940, 950, 950, 940, 951, + 940, 941, 951, 951, 941, 952, + 941, 942, 952, 952, 942, 953, + 942, 943, 953, 953, 943, 954, + 943, 944, 954, 954, 944, 955, + 944, 945, 955, 955, 945, 956, + 946, 947, 957, 957, 947, 958, + 947, 948, 958, 958, 948, 959, + 948, 949, 959, 959, 949, 960, + 949, 950, 960, 960, 950, 961, + 950, 951, 961, 961, 951, 962, + 951, 952, 962, 962, 952, 963, + 952, 953, 963, 963, 953, 964, + 953, 954, 964, 964, 954, 965, + 954, 955, 965, 965, 955, 966, + 955, 956, 966, 966, 956, 967, + 968, 969, 979, 979, 969, 980, + 969, 970, 980, 980, 970, 981, + 970, 971, 981, 981, 971, 982, + 971, 972, 982, 982, 972, 983, + 972, 973, 983, 983, 973, 984, + 973, 974, 984, 984, 974, 985, + 974, 975, 985, 985, 975, 986, + 975, 976, 986, 986, 976, 987, + 976, 977, 987, 987, 977, 988, + 977, 978, 988, 988, 978, 989, + 979, 980, 990, 990, 980, 991, + 980, 981, 991, 991, 981, 992, + 981, 982, 992, 992, 982, 993, + 982, 983, 993, 993, 983, 994, + 983, 984, 994, 994, 984, 995, + 984, 985, 995, 995, 985, 996, + 985, 986, 996, 996, 986, 997, + 986, 987, 997, 997, 987, 998, + 987, 988, 998, 998, 988, 999, + 988, 989, 999, 999, 989, 1000, + 990, 991, 1001, 1001, 991, 1002, + 991, 992, 1002, 1002, 992, 1003, + 992, 993, 1003, 1003, 993, 1004, + 993, 994, 1004, 1004, 994, 1005, + 994, 995, 1005, 1005, 995, 1006, + 995, 996, 1006, 1006, 996, 1007, + 996, 997, 1007, 1007, 997, 1008, + 997, 998, 1008, 1008, 998, 1009, + 998, 999, 1009, 1009, 999, 1010, + 999, 1000, 1010, 1010, 1000, 1011, + 1001, 1002, 1012, 1012, 1002, 1013, + 1002, 1003, 1013, 1013, 1003, 1014, + 1003, 1004, 1014, 1014, 1004, 1015, + 1004, 1005, 1015, 1015, 1005, 1016, + 1005, 1006, 1016, 1016, 1006, 1017, + 1006, 1007, 1017, 1017, 1007, 1018, + 1007, 1008, 1018, 1018, 1008, 1019, + 1008, 1009, 1019, 1019, 1009, 1020, + 1009, 1010, 1020, 1020, 1010, 1021, + 1010, 1011, 1021, 1021, 1011, 1022, + 1012, 1013, 1023, 1023, 1013, 1024, + 1013, 1014, 1024, 1024, 1014, 1025, + 1014, 1015, 1025, 1025, 1015, 1026, + 1015, 1016, 1026, 1026, 1016, 1027, + 1016, 1017, 1027, 1027, 1017, 1028, + 1017, 1018, 1028, 1028, 1018, 1029, + 1018, 1019, 1029, 1029, 1019, 1030, + 1019, 1020, 1030, 1030, 1020, 1031, + 1020, 1021, 1031, 1031, 1021, 1032, + 1021, 1022, 1032, 1032, 1022, 1033, + 1023, 1024, 1034, 1034, 1024, 1035, + 1024, 1025, 1035, 1035, 1025, 1036, + 1025, 1026, 1036, 1036, 1026, 1037, + 1026, 1027, 1037, 1037, 1027, 1038, + 1027, 1028, 1038, 1038, 1028, 1039, + 1028, 1029, 1039, 1039, 1029, 1040, + 1029, 1030, 1040, 1040, 1030, 1041, + 1030, 1031, 1041, 1041, 1031, 1042, + 1031, 1032, 1042, 1042, 1032, 1043, + 1032, 1033, 1043, 1043, 1033, 1044, + 1034, 1035, 1045, 1045, 1035, 1046, + 1035, 1036, 1046, 1046, 1036, 1047, + 1036, 1037, 1047, 1047, 1037, 1048, + 1037, 1038, 1048, 1048, 1038, 1049, + 1038, 1039, 1049, 1049, 1039, 1050, + 1039, 1040, 1050, 1050, 1040, 1051, + 1040, 1041, 1051, 1051, 1041, 1052, + 1041, 1042, 1052, 1052, 1042, 1053, + 1042, 1043, 1053, 1053, 1043, 1054, + 1043, 1044, 1054, 1054, 1044, 1055, + 1045, 1046, 1056, 1056, 1046, 1057, + 1046, 1047, 1057, 1057, 1047, 1058, + 1047, 1048, 1058, 1058, 1048, 1059, + 1048, 1049, 1059, 1059, 1049, 1060, + 1049, 1050, 1060, 1060, 1050, 1061, + 1050, 1051, 1061, 1061, 1051, 1062, + 1051, 1052, 1062, 1062, 1052, 1063, + 1052, 1053, 1063, 1063, 1053, 1064, + 1053, 1054, 1064, 1064, 1054, 1065, + 1054, 1055, 1065, 1065, 1055, 1066, + 1056, 1057, 1067, 1067, 1057, 1068, + 1057, 1058, 1068, 1068, 1058, 1069, + 1058, 1059, 1069, 1069, 1059, 1070, + 1059, 1060, 1070, 1070, 1060, 1071, + 1060, 1061, 1071, 1071, 1061, 1072, + 1061, 1062, 1072, 1072, 1062, 1073, + 1062, 1063, 1073, 1073, 1063, 1074, + 1063, 1064, 1074, 1074, 1064, 1075, + 1064, 1065, 1075, 1075, 1065, 1076, + 1065, 1066, 1076, 1076, 1066, 1077, + 1067, 1068, 1078, 1078, 1068, 1079, + 1068, 1069, 1079, 1079, 1069, 1080, + 1069, 1070, 1080, 1080, 1070, 1081, + 1070, 1071, 1081, 1081, 1071, 1082, + 1071, 1072, 1082, 1082, 1072, 1083, + 1072, 1073, 1083, 1083, 1073, 1084, + 1073, 1074, 1084, 1084, 1074, 1085, + 1074, 1075, 1085, 1085, 1075, 1086, + 1075, 1076, 1086, 1086, 1076, 1087, + 1076, 1077, 1087, 1087, 1077, 1088, + 1089, 1090, 1100, 1100, 1090, 1101, + 1090, 1091, 1101, 1101, 1091, 1102, + 1091, 1092, 1102, 1102, 1092, 1103, + 1092, 1093, 1103, 1103, 1093, 1104, + 1093, 1094, 1104, 1104, 1094, 1105, + 1094, 1095, 1105, 1105, 1095, 1106, + 1095, 1096, 1106, 1106, 1096, 1107, + 1096, 1097, 1107, 1107, 1097, 1108, + 1097, 1098, 1108, 1108, 1098, 1109, + 1098, 1099, 1109, 1109, 1099, 1110, + 1100, 1101, 1111, 1111, 1101, 1112, + 1101, 1102, 1112, 1112, 1102, 1113, + 1102, 1103, 1113, 1113, 1103, 1114, + 1103, 1104, 1114, 1114, 1104, 1115, + 1104, 1105, 1115, 1115, 1105, 1116, + 1105, 1106, 1116, 1116, 1106, 1117, + 1106, 1107, 1117, 1117, 1107, 1118, + 1107, 1108, 1118, 1118, 1108, 1119, + 1108, 1109, 1119, 1119, 1109, 1120, + 1109, 1110, 1120, 1120, 1110, 1121, + 1111, 1112, 1122, 1122, 1112, 1123, + 1112, 1113, 1123, 1123, 1113, 1124, + 1113, 1114, 1124, 1124, 1114, 1125, + 1114, 1115, 1125, 1125, 1115, 1126, + 1115, 1116, 1126, 1126, 1116, 1127, + 1116, 1117, 1127, 1127, 1117, 1128, + 1117, 1118, 1128, 1128, 1118, 1129, + 1118, 1119, 1129, 1129, 1119, 1130, + 1119, 1120, 1130, 1130, 1120, 1131, + 1120, 1121, 1131, 1131, 1121, 1132, + 1122, 1123, 1133, 1133, 1123, 1134, + 1123, 1124, 1134, 1134, 1124, 1135, + 1124, 1125, 1135, 1135, 1125, 1136, + 1125, 1126, 1136, 1136, 1126, 1137, + 1126, 1127, 1137, 1137, 1127, 1138, + 1127, 1128, 1138, 1138, 1128, 1139, + 1128, 1129, 1139, 1139, 1129, 1140, + 1129, 1130, 1140, 1140, 1130, 1141, + 1130, 1131, 1141, 1141, 1131, 1142, + 1131, 1132, 1142, 1142, 1132, 1143, + 1133, 1134, 1144, 1144, 1134, 1145, + 1134, 1135, 1145, 1145, 1135, 1146, + 1135, 1136, 1146, 1146, 1136, 1147, + 1136, 1137, 1147, 1147, 1137, 1148, + 1137, 1138, 1148, 1148, 1138, 1149, + 1138, 1139, 1149, 1149, 1139, 1150, + 1139, 1140, 1150, 1150, 1140, 1151, + 1140, 1141, 1151, 1151, 1141, 1152, + 1141, 1142, 1152, 1152, 1142, 1153, + 1142, 1143, 1153, 1153, 1143, 1154, + 1144, 1145, 1155, 1155, 1145, 1156, + 1145, 1146, 1156, 1156, 1146, 1157, + 1146, 1147, 1157, 1157, 1147, 1158, + 1147, 1148, 1158, 1158, 1148, 1159, + 1148, 1149, 1159, 1159, 1149, 1160, + 1149, 1150, 1160, 1160, 1150, 1161, + 1150, 1151, 1161, 1161, 1151, 1162, + 1151, 1152, 1162, 1162, 1152, 1163, + 1152, 1153, 1163, 1163, 1153, 1164, + 1153, 1154, 1164, 1164, 1154, 1165, + 1155, 1156, 1166, 1166, 1156, 1167, + 1156, 1157, 1167, 1167, 1157, 1168, + 1157, 1158, 1168, 1168, 1158, 1169, + 1158, 1159, 1169, 1169, 1159, 1170, + 1159, 1160, 1170, 1170, 1160, 1171, + 1160, 1161, 1171, 1171, 1161, 1172, + 1161, 1162, 1172, 1172, 1162, 1173, + 1162, 1163, 1173, 1173, 1163, 1174, + 1163, 1164, 1174, 1174, 1164, 1175, + 1164, 1165, 1175, 1175, 1165, 1176, + 1166, 1167, 1177, 1177, 1167, 1178, + 1167, 1168, 1178, 1178, 1168, 1179, + 1168, 1169, 1179, 1179, 1169, 1180, + 1169, 1170, 1180, 1180, 1170, 1181, + 1170, 1171, 1181, 1181, 1171, 1182, + 1171, 1172, 1182, 1182, 1172, 1183, + 1172, 1173, 1183, 1183, 1173, 1184, + 1173, 1174, 1184, 1184, 1174, 1185, + 1174, 1175, 1185, 1185, 1175, 1186, + 1175, 1176, 1186, 1186, 1176, 1187, + 1177, 1178, 1188, 1188, 1178, 1189, + 1178, 1179, 1189, 1189, 1179, 1190, + 1179, 1180, 1190, 1190, 1180, 1191, + 1180, 1181, 1191, 1191, 1181, 1192, + 1181, 1182, 1192, 1192, 1182, 1193, + 1182, 1183, 1193, 1193, 1183, 1194, + 1183, 1184, 1194, 1194, 1184, 1195, + 1184, 1185, 1195, 1195, 1185, 1196, + 1185, 1186, 1196, 1196, 1186, 1197, + 1186, 1187, 1197, 1197, 1187, 1198, + 1188, 1189, 1199, 1199, 1189, 1200, + 1189, 1190, 1200, 1200, 1190, 1201, + 1190, 1191, 1201, 1201, 1191, 1202, + 1191, 1192, 1202, 1202, 1192, 1203, + 1192, 1193, 1203, 1203, 1193, 1204, + 1193, 1194, 1204, 1204, 1194, 1205, + 1194, 1195, 1205, 1205, 1195, 1206, + 1195, 1196, 1206, 1206, 1196, 1207, + 1196, 1197, 1207, 1207, 1197, 1208, + 1197, 1198, 1208, 1208, 1198, 1209, + 1210, 1211, 1221, 1221, 1211, 1222, + 1211, 1212, 1222, 1222, 1212, 1223, + 1212, 1213, 1223, 1223, 1213, 1224, + 1213, 1214, 1224, 1224, 1214, 1225, + 1214, 1215, 1225, 1225, 1215, 1226, + 1215, 1216, 1226, 1226, 1216, 1227, + 1216, 1217, 1227, 1227, 1217, 1228, + 1217, 1218, 1228, 1228, 1218, 1229, + 1218, 1219, 1229, 1229, 1219, 1230, + 1219, 1220, 1230, 1230, 1220, 1231, + 1221, 1222, 1232, 1232, 1222, 1233, + 1222, 1223, 1233, 1233, 1223, 1234, + 1223, 1224, 1234, 1234, 1224, 1235, + 1224, 1225, 1235, 1235, 1225, 1236, + 1225, 1226, 1236, 1236, 1226, 1237, + 1226, 1227, 1237, 1237, 1227, 1238, + 1227, 1228, 1238, 1238, 1228, 1239, + 1228, 1229, 1239, 1239, 1229, 1240, + 1229, 1230, 1240, 1240, 1230, 1241, + 1230, 1231, 1241, 1241, 1231, 1242, + 1232, 1233, 1243, 1243, 1233, 1244, + 1233, 1234, 1244, 1244, 1234, 1245, + 1234, 1235, 1245, 1245, 1235, 1246, + 1235, 1236, 1246, 1246, 1236, 1247, + 1236, 1237, 1247, 1247, 1237, 1248, + 1237, 1238, 1248, 1248, 1238, 1249, + 1238, 1239, 1249, 1249, 1239, 1250, + 1239, 1240, 1250, 1250, 1240, 1251, + 1240, 1241, 1251, 1251, 1241, 1252, + 1241, 1242, 1252, 1252, 1242, 1253, + 1243, 1244, 1254, 1254, 1244, 1255, + 1244, 1245, 1255, 1255, 1245, 1256, + 1245, 1246, 1256, 1256, 1246, 1257, + 1246, 1247, 1257, 1257, 1247, 1258, + 1247, 1248, 1258, 1258, 1248, 1259, + 1248, 1249, 1259, 1259, 1249, 1260, + 1249, 1250, 1260, 1260, 1250, 1261, + 1250, 1251, 1261, 1261, 1251, 1262, + 1251, 1252, 1262, 1262, 1252, 1263, + 1252, 1253, 1263, 1263, 1253, 1264, + 1254, 1255, 1265, 1265, 1255, 1266, + 1255, 1256, 1266, 1266, 1256, 1267, + 1256, 1257, 1267, 1267, 1257, 1268, + 1257, 1258, 1268, 1268, 1258, 1269, + 1258, 1259, 1269, 1269, 1259, 1270, + 1259, 1260, 1270, 1270, 1260, 1271, + 1260, 1261, 1271, 1271, 1261, 1272, + 1261, 1262, 1272, 1272, 1262, 1273, + 1262, 1263, 1273, 1273, 1263, 1274, + 1263, 1264, 1274, 1274, 1264, 1275, + 1265, 1266, 1276, 1276, 1266, 1277, + 1266, 1267, 1277, 1277, 1267, 1278, + 1267, 1268, 1278, 1278, 1268, 1279, + 1268, 1269, 1279, 1279, 1269, 1280, + 1269, 1270, 1280, 1280, 1270, 1281, + 1270, 1271, 1281, 1281, 1271, 1282, + 1271, 1272, 1282, 1282, 1272, 1283, + 1272, 1273, 1283, 1283, 1273, 1284, + 1273, 1274, 1284, 1284, 1274, 1285, + 1274, 1275, 1285, 1285, 1275, 1286, + 1276, 1277, 1287, 1287, 1277, 1288, + 1277, 1278, 1288, 1288, 1278, 1289, + 1278, 1279, 1289, 1289, 1279, 1290, + 1279, 1280, 1290, 1290, 1280, 1291, + 1280, 1281, 1291, 1291, 1281, 1292, + 1281, 1282, 1292, 1292, 1282, 1293, + 1282, 1283, 1293, 1293, 1283, 1294, + 1283, 1284, 1294, 1294, 1284, 1295, + 1284, 1285, 1295, 1295, 1285, 1296, + 1285, 1286, 1296, 1296, 1286, 1297, + 1287, 1288, 1298, 1298, 1288, 1299, + 1288, 1289, 1299, 1299, 1289, 1300, + 1289, 1290, 1300, 1300, 1290, 1301, + 1290, 1291, 1301, 1301, 1291, 1302, + 1291, 1292, 1302, 1302, 1292, 1303, + 1292, 1293, 1303, 1303, 1293, 1304, + 1293, 1294, 1304, 1304, 1294, 1305, + 1294, 1295, 1305, 1305, 1295, 1306, + 1295, 1296, 1306, 1306, 1296, 1307, + 1296, 1297, 1307, 1307, 1297, 1308, + 1298, 1299, 1309, 1309, 1299, 1310, + 1299, 1300, 1310, 1310, 1300, 1311, + 1300, 1301, 1311, 1311, 1301, 1312, + 1301, 1302, 1312, 1312, 1302, 1313, + 1302, 1303, 1313, 1313, 1303, 1314, + 1303, 1304, 1314, 1314, 1304, 1315, + 1304, 1305, 1315, 1315, 1305, 1316, + 1305, 1306, 1316, 1316, 1306, 1317, + 1306, 1307, 1317, 1317, 1307, 1318, + 1307, 1308, 1318, 1318, 1308, 1319, + 1309, 1310, 1320, 1320, 1310, 1321, + 1310, 1311, 1321, 1321, 1311, 1322, + 1311, 1312, 1322, 1322, 1312, 1323, + 1312, 1313, 1323, 1323, 1313, 1324, + 1313, 1314, 1324, 1324, 1314, 1325, + 1314, 1315, 1325, 1325, 1315, 1326, + 1315, 1316, 1326, 1326, 1316, 1327, + 1316, 1317, 1327, 1327, 1317, 1328, + 1317, 1318, 1328, 1328, 1318, 1329, + 1318, 1319, 1329, 1329, 1319, 1330, + 1331, 1332, 1342, 1342, 1332, 1343, + 1332, 1333, 1343, 1343, 1333, 1344, + 1333, 1334, 1344, 1344, 1334, 1345, + 1334, 1335, 1345, 1345, 1335, 1346, + 1335, 1336, 1346, 1346, 1336, 1347, + 1336, 1337, 1347, 1347, 1337, 1348, + 1337, 1338, 1348, 1348, 1338, 1349, + 1338, 1339, 1349, 1349, 1339, 1350, + 1339, 1340, 1350, 1350, 1340, 1351, + 1340, 1341, 1351, 1351, 1341, 1352, + 1342, 1343, 1353, 1353, 1343, 1354, + 1343, 1344, 1354, 1354, 1344, 1355, + 1344, 1345, 1355, 1355, 1345, 1356, + 1345, 1346, 1356, 1356, 1346, 1357, + 1346, 1347, 1357, 1357, 1347, 1358, + 1347, 1348, 1358, 1358, 1348, 1359, + 1348, 1349, 1359, 1359, 1349, 1360, + 1349, 1350, 1360, 1360, 1350, 1361, + 1350, 1351, 1361, 1361, 1351, 1362, + 1351, 1352, 1362, 1362, 1352, 1363, + 1353, 1354, 1364, 1364, 1354, 1365, + 1354, 1355, 1365, 1365, 1355, 1366, + 1355, 1356, 1366, 1366, 1356, 1367, + 1356, 1357, 1367, 1367, 1357, 1368, + 1357, 1358, 1368, 1368, 1358, 1369, + 1358, 1359, 1369, 1369, 1359, 1370, + 1359, 1360, 1370, 1370, 1360, 1371, + 1360, 1361, 1371, 1371, 1361, 1372, + 1361, 1362, 1372, 1372, 1362, 1373, + 1362, 1363, 1373, 1373, 1363, 1374, + 1364, 1365, 1375, 1375, 1365, 1376, + 1365, 1366, 1376, 1376, 1366, 1377, + 1366, 1367, 1377, 1377, 1367, 1378, + 1367, 1368, 1378, 1378, 1368, 1379, + 1368, 1369, 1379, 1379, 1369, 1380, + 1369, 1370, 1380, 1380, 1370, 1381, + 1370, 1371, 1381, 1381, 1371, 1382, + 1371, 1372, 1382, 1382, 1372, 1383, + 1372, 1373, 1383, 1383, 1373, 1384, + 1373, 1374, 1384, 1384, 1374, 1385, + 1375, 1376, 1386, 1386, 1376, 1387, + 1376, 1377, 1387, 1387, 1377, 1388, + 1377, 1378, 1388, 1388, 1378, 1389, + 1378, 1379, 1389, 1389, 1379, 1390, + 1379, 1380, 1390, 1390, 1380, 1391, + 1380, 1381, 1391, 1391, 1381, 1392, + 1381, 1382, 1392, 1392, 1382, 1393, + 1382, 1383, 1393, 1393, 1383, 1394, + 1383, 1384, 1394, 1394, 1384, 1395, + 1384, 1385, 1395, 1395, 1385, 1396, + 1386, 1387, 1397, 1397, 1387, 1398, + 1387, 1388, 1398, 1398, 1388, 1399, + 1388, 1389, 1399, 1399, 1389, 1400, + 1389, 1390, 1400, 1400, 1390, 1401, + 1390, 1391, 1401, 1401, 1391, 1402, + 1391, 1392, 1402, 1402, 1392, 1403, + 1392, 1393, 1403, 1403, 1393, 1404, + 1393, 1394, 1404, 1404, 1394, 1405, + 1394, 1395, 1405, 1405, 1395, 1406, + 1395, 1396, 1406, 1406, 1396, 1407, + 1397, 1398, 1408, 1408, 1398, 1409, + 1398, 1399, 1409, 1409, 1399, 1410, + 1399, 1400, 1410, 1410, 1400, 1411, + 1400, 1401, 1411, 1411, 1401, 1412, + 1401, 1402, 1412, 1412, 1402, 1413, + 1402, 1403, 1413, 1413, 1403, 1414, + 1403, 1404, 1414, 1414, 1404, 1415, + 1404, 1405, 1415, 1415, 1405, 1416, + 1405, 1406, 1416, 1416, 1406, 1417, + 1406, 1407, 1417, 1417, 1407, 1418, + 1408, 1409, 1419, 1419, 1409, 1420, + 1409, 1410, 1420, 1420, 1410, 1421, + 1410, 1411, 1421, 1421, 1411, 1422, + 1411, 1412, 1422, 1422, 1412, 1423, + 1412, 1413, 1423, 1423, 1413, 1424, + 1413, 1414, 1424, 1424, 1414, 1425, + 1414, 1415, 1425, 1425, 1415, 1426, + 1415, 1416, 1426, 1426, 1416, 1427, + 1416, 1417, 1427, 1427, 1417, 1428, + 1417, 1418, 1428, 1428, 1418, 1429, + 1419, 1420, 1430, 1430, 1420, 1431, + 1420, 1421, 1431, 1431, 1421, 1432, + 1421, 1422, 1432, 1432, 1422, 1433, + 1422, 1423, 1433, 1433, 1423, 1434, + 1423, 1424, 1434, 1434, 1424, 1435, + 1424, 1425, 1435, 1435, 1425, 1436, + 1425, 1426, 1436, 1436, 1426, 1437, + 1426, 1427, 1437, 1437, 1427, 1438, + 1427, 1428, 1438, 1438, 1428, 1439, + 1428, 1429, 1439, 1439, 1429, 1440, + 1430, 1431, 1441, 1441, 1431, 1442, + 1431, 1432, 1442, 1442, 1432, 1443, + 1432, 1433, 1443, 1443, 1433, 1444, + 1433, 1434, 1444, 1444, 1434, 1445, + 1434, 1435, 1445, 1445, 1435, 1446, + 1435, 1436, 1446, 1446, 1436, 1447, + 1436, 1437, 1447, 1447, 1437, 1448, + 1437, 1438, 1448, 1448, 1438, 1449, + 1438, 1439, 1449, 1449, 1439, 1450, + 1439, 1440, 1450, 1450, 1440, 1451, + 1452, 1453, 1463, 1463, 1453, 1464, + 1453, 1454, 1464, 1464, 1454, 1465, + 1454, 1455, 1465, 1465, 1455, 1466, + 1455, 1456, 1466, 1466, 1456, 1467, + 1456, 1457, 1467, 1467, 1457, 1468, + 1457, 1458, 1468, 1468, 1458, 1469, + 1458, 1459, 1469, 1469, 1459, 1470, + 1459, 1460, 1470, 1470, 1460, 1471, + 1460, 1461, 1471, 1471, 1461, 1472, + 1461, 1462, 1472, 1472, 1462, 1473, + 1463, 1464, 1474, 1474, 1464, 1475, + 1464, 1465, 1475, 1475, 1465, 1476, + 1465, 1466, 1476, 1476, 1466, 1477, + 1466, 1467, 1477, 1477, 1467, 1478, + 1467, 1468, 1478, 1478, 1468, 1479, + 1468, 1469, 1479, 1479, 1469, 1480, + 1469, 1470, 1480, 1480, 1470, 1481, + 1470, 1471, 1481, 1481, 1471, 1482, + 1471, 1472, 1482, 1482, 1472, 1483, + 1472, 1473, 1483, 1483, 1473, 1484, + 1474, 1475, 1485, 1485, 1475, 1486, + 1475, 1476, 1486, 1486, 1476, 1487, + 1476, 1477, 1487, 1487, 1477, 1488, + 1477, 1478, 1488, 1488, 1478, 1489, + 1478, 1479, 1489, 1489, 1479, 1490, + 1479, 1480, 1490, 1490, 1480, 1491, + 1480, 1481, 1491, 1491, 1481, 1492, + 1481, 1482, 1492, 1492, 1482, 1493, + 1482, 1483, 1493, 1493, 1483, 1494, + 1483, 1484, 1494, 1494, 1484, 1495, + 1485, 1486, 1496, 1496, 1486, 1497, + 1486, 1487, 1497, 1497, 1487, 1498, + 1487, 1488, 1498, 1498, 1488, 1499, + 1488, 1489, 1499, 1499, 1489, 1500, + 1489, 1490, 1500, 1500, 1490, 1501, + 1490, 1491, 1501, 1501, 1491, 1502, + 1491, 1492, 1502, 1502, 1492, 1503, + 1492, 1493, 1503, 1503, 1493, 1504, + 1493, 1494, 1504, 1504, 1494, 1505, + 1494, 1495, 1505, 1505, 1495, 1506, + 1496, 1497, 1507, 1507, 1497, 1508, + 1497, 1498, 1508, 1508, 1498, 1509, + 1498, 1499, 1509, 1509, 1499, 1510, + 1499, 1500, 1510, 1510, 1500, 1511, + 1500, 1501, 1511, 1511, 1501, 1512, + 1501, 1502, 1512, 1512, 1502, 1513, + 1502, 1503, 1513, 1513, 1503, 1514, + 1503, 1504, 1514, 1514, 1504, 1515, + 1504, 1505, 1515, 1515, 1505, 1516, + 1505, 1506, 1516, 1516, 1506, 1517, + 1507, 1508, 1518, 1518, 1508, 1519, + 1508, 1509, 1519, 1519, 1509, 1520, + 1509, 1510, 1520, 1520, 1510, 1521, + 1510, 1511, 1521, 1521, 1511, 1522, + 1511, 1512, 1522, 1522, 1512, 1523, + 1512, 1513, 1523, 1523, 1513, 1524, + 1513, 1514, 1524, 1524, 1514, 1525, + 1514, 1515, 1525, 1525, 1515, 1526, + 1515, 1516, 1526, 1526, 1516, 1527, + 1516, 1517, 1527, 1527, 1517, 1528, + 1518, 1519, 1529, 1529, 1519, 1530, + 1519, 1520, 1530, 1530, 1520, 1531, + 1520, 1521, 1531, 1531, 1521, 1532, + 1521, 1522, 1532, 1532, 1522, 1533, + 1522, 1523, 1533, 1533, 1523, 1534, + 1523, 1524, 1534, 1534, 1524, 1535, + 1524, 1525, 1535, 1535, 1525, 1536, + 1525, 1526, 1536, 1536, 1526, 1537, + 1526, 1527, 1537, 1537, 1527, 1538, + 1527, 1528, 1538, 1538, 1528, 1539, + 1529, 1530, 1540, 1540, 1530, 1541, + 1530, 1531, 1541, 1541, 1531, 1542, + 1531, 1532, 1542, 1542, 1532, 1543, + 1532, 1533, 1543, 1543, 1533, 1544, + 1533, 1534, 1544, 1544, 1534, 1545, + 1534, 1535, 1545, 1545, 1535, 1546, + 1535, 1536, 1546, 1546, 1536, 1547, + 1536, 1537, 1547, 1547, 1537, 1548, + 1537, 1538, 1548, 1548, 1538, 1549, + 1538, 1539, 1549, 1549, 1539, 1550, + 1540, 1541, 1551, 1551, 1541, 1552, + 1541, 1542, 1552, 1552, 1542, 1553, + 1542, 1543, 1553, 1553, 1543, 1554, + 1543, 1544, 1554, 1554, 1544, 1555, + 1544, 1545, 1555, 1555, 1545, 1556, + 1545, 1546, 1556, 1556, 1546, 1557, + 1546, 1547, 1557, 1557, 1547, 1558, + 1547, 1548, 1558, 1558, 1548, 1559, + 1548, 1549, 1559, 1559, 1549, 1560, + 1549, 1550, 1560, 1560, 1550, 1561, + 1551, 1552, 1562, 1562, 1552, 1563, + 1552, 1553, 1563, 1563, 1553, 1564, + 1553, 1554, 1564, 1564, 1554, 1565, + 1554, 1555, 1565, 1565, 1555, 1566, + 1555, 1556, 1566, 1566, 1556, 1567, + 1556, 1557, 1567, 1567, 1557, 1568, + 1557, 1558, 1568, 1568, 1558, 1569, + 1558, 1559, 1569, 1569, 1559, 1570, + 1559, 1560, 1570, 1570, 1560, 1571, + 1560, 1561, 1571, 1571, 1561, 1572, + 1573, 1574, 1584, 1584, 1574, 1585, + 1574, 1575, 1585, 1585, 1575, 1586, + 1575, 1576, 1586, 1586, 1576, 1587, + 1576, 1577, 1587, 1587, 1577, 1588, + 1577, 1578, 1588, 1588, 1578, 1589, + 1578, 1579, 1589, 1589, 1579, 1590, + 1579, 1580, 1590, 1590, 1580, 1591, + 1580, 1581, 1591, 1591, 1581, 1592, + 1581, 1582, 1592, 1592, 1582, 1593, + 1582, 1583, 1593, 1593, 1583, 1594, + 1584, 1585, 1595, 1595, 1585, 1596, + 1585, 1586, 1596, 1596, 1586, 1597, + 1586, 1587, 1597, 1597, 1587, 1598, + 1587, 1588, 1598, 1598, 1588, 1599, + 1588, 1589, 1599, 1599, 1589, 1600, + 1589, 1590, 1600, 1600, 1590, 1601, + 1590, 1591, 1601, 1601, 1591, 1602, + 1591, 1592, 1602, 1602, 1592, 1603, + 1592, 1593, 1603, 1603, 1593, 1604, + 1593, 1594, 1604, 1604, 1594, 1605, + 1595, 1596, 1606, 1606, 1596, 1607, + 1596, 1597, 1607, 1607, 1597, 1608, + 1597, 1598, 1608, 1608, 1598, 1609, + 1598, 1599, 1609, 1609, 1599, 1610, + 1599, 1600, 1610, 1610, 1600, 1611, + 1600, 1601, 1611, 1611, 1601, 1612, + 1601, 1602, 1612, 1612, 1602, 1613, + 1602, 1603, 1613, 1613, 1603, 1614, + 1603, 1604, 1614, 1614, 1604, 1615, + 1604, 1605, 1615, 1615, 1605, 1616, + 1606, 1607, 1617, 1617, 1607, 1618, + 1607, 1608, 1618, 1618, 1608, 1619, + 1608, 1609, 1619, 1619, 1609, 1620, + 1609, 1610, 1620, 1620, 1610, 1621, + 1610, 1611, 1621, 1621, 1611, 1622, + 1611, 1612, 1622, 1622, 1612, 1623, + 1612, 1613, 1623, 1623, 1613, 1624, + 1613, 1614, 1624, 1624, 1614, 1625, + 1614, 1615, 1625, 1625, 1615, 1626, + 1615, 1616, 1626, 1626, 1616, 1627, + 1617, 1618, 1628, 1628, 1618, 1629, + 1618, 1619, 1629, 1629, 1619, 1630, + 1619, 1620, 1630, 1630, 1620, 1631, + 1620, 1621, 1631, 1631, 1621, 1632, + 1621, 1622, 1632, 1632, 1622, 1633, + 1622, 1623, 1633, 1633, 1623, 1634, + 1623, 1624, 1634, 1634, 1624, 1635, + 1624, 1625, 1635, 1635, 1625, 1636, + 1625, 1626, 1636, 1636, 1626, 1637, + 1626, 1627, 1637, 1637, 1627, 1638, + 1628, 1629, 1639, 1639, 1629, 1640, + 1629, 1630, 1640, 1640, 1630, 1641, + 1630, 1631, 1641, 1641, 1631, 1642, + 1631, 1632, 1642, 1642, 1632, 1643, + 1632, 1633, 1643, 1643, 1633, 1644, + 1633, 1634, 1644, 1644, 1634, 1645, + 1634, 1635, 1645, 1645, 1635, 1646, + 1635, 1636, 1646, 1646, 1636, 1647, + 1636, 1637, 1647, 1647, 1637, 1648, + 1637, 1638, 1648, 1648, 1638, 1649, + 1639, 1640, 1650, 1650, 1640, 1651, + 1640, 1641, 1651, 1651, 1641, 1652, + 1641, 1642, 1652, 1652, 1642, 1653, + 1642, 1643, 1653, 1653, 1643, 1654, + 1643, 1644, 1654, 1654, 1644, 1655, + 1644, 1645, 1655, 1655, 1645, 1656, + 1645, 1646, 1656, 1656, 1646, 1657, + 1646, 1647, 1657, 1657, 1647, 1658, + 1647, 1648, 1658, 1658, 1648, 1659, + 1648, 1649, 1659, 1659, 1649, 1660, + 1650, 1651, 1661, 1661, 1651, 1662, + 1651, 1652, 1662, 1662, 1652, 1663, + 1652, 1653, 1663, 1663, 1653, 1664, + 1653, 1654, 1664, 1664, 1654, 1665, + 1654, 1655, 1665, 1665, 1655, 1666, + 1655, 1656, 1666, 1666, 1656, 1667, + 1656, 1657, 1667, 1667, 1657, 1668, + 1657, 1658, 1668, 1668, 1658, 1669, + 1658, 1659, 1669, 1669, 1659, 1670, + 1659, 1660, 1670, 1670, 1660, 1671, + 1661, 1662, 1672, 1672, 1662, 1673, + 1662, 1663, 1673, 1673, 1663, 1674, + 1663, 1664, 1674, 1674, 1664, 1675, + 1664, 1665, 1675, 1675, 1665, 1676, + 1665, 1666, 1676, 1676, 1666, 1677, + 1666, 1667, 1677, 1677, 1667, 1678, + 1667, 1668, 1678, 1678, 1668, 1679, + 1668, 1669, 1679, 1679, 1669, 1680, + 1669, 1670, 1680, 1680, 1670, 1681, + 1670, 1671, 1681, 1681, 1671, 1682, + 1672, 1673, 1683, 1683, 1673, 1684, + 1673, 1674, 1684, 1684, 1674, 1685, + 1674, 1675, 1685, 1685, 1675, 1686, + 1675, 1676, 1686, 1686, 1676, 1687, + 1676, 1677, 1687, 1687, 1677, 1688, + 1677, 1678, 1688, 1688, 1678, 1689, + 1678, 1679, 1689, 1689, 1679, 1690, + 1679, 1680, 1690, 1690, 1680, 1691, + 1680, 1681, 1691, 1691, 1681, 1692, + 1681, 1682, 1692, 1692, 1682, 1693, + 1694, 1695, 1705, 1705, 1695, 1706, + 1695, 1696, 1706, 1706, 1696, 1707, + 1696, 1697, 1707, 1707, 1697, 1708, + 1697, 1698, 1708, 1708, 1698, 1709, + 1698, 1699, 1709, 1709, 1699, 1710, + 1699, 1700, 1710, 1710, 1700, 1711, + 1700, 1701, 1711, 1711, 1701, 1712, + 1701, 1702, 1712, 1712, 1702, 1713, + 1702, 1703, 1713, 1713, 1703, 1714, + 1703, 1704, 1714, 1714, 1704, 1715, + 1705, 1706, 1716, 1716, 1706, 1717, + 1706, 1707, 1717, 1717, 1707, 1718, + 1707, 1708, 1718, 1718, 1708, 1719, + 1708, 1709, 1719, 1719, 1709, 1720, + 1709, 1710, 1720, 1720, 1710, 1721, + 1710, 1711, 1721, 1721, 1711, 1722, + 1711, 1712, 1722, 1722, 1712, 1723, + 1712, 1713, 1723, 1723, 1713, 1724, + 1713, 1714, 1724, 1724, 1714, 1725, + 1714, 1715, 1725, 1725, 1715, 1726, + 1716, 1717, 1727, 1727, 1717, 1728, + 1717, 1718, 1728, 1728, 1718, 1729, + 1718, 1719, 1729, 1729, 1719, 1730, + 1719, 1720, 1730, 1730, 1720, 1731, + 1720, 1721, 1731, 1731, 1721, 1732, + 1721, 1722, 1732, 1732, 1722, 1733, + 1722, 1723, 1733, 1733, 1723, 1734, + 1723, 1724, 1734, 1734, 1724, 1735, + 1724, 1725, 1735, 1735, 1725, 1736, + 1725, 1726, 1736, 1736, 1726, 1737, + 1727, 1728, 1738, 1738, 1728, 1739, + 1728, 1729, 1739, 1739, 1729, 1740, + 1729, 1730, 1740, 1740, 1730, 1741, + 1730, 1731, 1741, 1741, 1731, 1742, + 1731, 1732, 1742, 1742, 1732, 1743, + 1732, 1733, 1743, 1743, 1733, 1744, + 1733, 1734, 1744, 1744, 1734, 1745, + 1734, 1735, 1745, 1745, 1735, 1746, + 1735, 1736, 1746, 1746, 1736, 1747, + 1736, 1737, 1747, 1747, 1737, 1748, + 1738, 1739, 1749, 1749, 1739, 1750, + 1739, 1740, 1750, 1750, 1740, 1751, + 1740, 1741, 1751, 1751, 1741, 1752, + 1741, 1742, 1752, 1752, 1742, 1753, + 1742, 1743, 1753, 1753, 1743, 1754, + 1743, 1744, 1754, 1754, 1744, 1755, + 1744, 1745, 1755, 1755, 1745, 1756, + 1745, 1746, 1756, 1756, 1746, 1757, + 1746, 1747, 1757, 1757, 1747, 1758, + 1747, 1748, 1758, 1758, 1748, 1759, + 1749, 1750, 1760, 1760, 1750, 1761, + 1750, 1751, 1761, 1761, 1751, 1762, + 1751, 1752, 1762, 1762, 1752, 1763, + 1752, 1753, 1763, 1763, 1753, 1764, + 1753, 1754, 1764, 1764, 1754, 1765, + 1754, 1755, 1765, 1765, 1755, 1766, + 1755, 1756, 1766, 1766, 1756, 1767, + 1756, 1757, 1767, 1767, 1757, 1768, + 1757, 1758, 1768, 1768, 1758, 1769, + 1758, 1759, 1769, 1769, 1759, 1770, + 1760, 1761, 1771, 1771, 1761, 1772, + 1761, 1762, 1772, 1772, 1762, 1773, + 1762, 1763, 1773, 1773, 1763, 1774, + 1763, 1764, 1774, 1774, 1764, 1775, + 1764, 1765, 1775, 1775, 1765, 1776, + 1765, 1766, 1776, 1776, 1766, 1777, + 1766, 1767, 1777, 1777, 1767, 1778, + 1767, 1768, 1778, 1778, 1768, 1779, + 1768, 1769, 1779, 1779, 1769, 1780, + 1769, 1770, 1780, 1780, 1770, 1781, + 1771, 1772, 1782, 1782, 1772, 1783, + 1772, 1773, 1783, 1783, 1773, 1784, + 1773, 1774, 1784, 1784, 1774, 1785, + 1774, 1775, 1785, 1785, 1775, 1786, + 1775, 1776, 1786, 1786, 1776, 1787, + 1776, 1777, 1787, 1787, 1777, 1788, + 1777, 1778, 1788, 1788, 1778, 1789, + 1778, 1779, 1789, 1789, 1779, 1790, + 1779, 1780, 1790, 1790, 1780, 1791, + 1780, 1781, 1791, 1791, 1781, 1792, + 1782, 1783, 1793, 1793, 1783, 1794, + 1783, 1784, 1794, 1794, 1784, 1795, + 1784, 1785, 1795, 1795, 1785, 1796, + 1785, 1786, 1796, 1796, 1786, 1797, + 1786, 1787, 1797, 1797, 1787, 1798, + 1787, 1788, 1798, 1798, 1788, 1799, + 1788, 1789, 1799, 1799, 1789, 1800, + 1789, 1790, 1800, 1800, 1790, 1801, + 1790, 1791, 1801, 1801, 1791, 1802, + 1791, 1792, 1802, 1802, 1792, 1803, + 1793, 1794, 1804, 1804, 1794, 1805, + 1794, 1795, 1805, 1805, 1795, 1806, + 1795, 1796, 1806, 1806, 1796, 1807, + 1796, 1797, 1807, 1807, 1797, 1808, + 1797, 1798, 1808, 1808, 1798, 1809, + 1798, 1799, 1809, 1809, 1799, 1810, + 1799, 1800, 1810, 1810, 1800, 1811, + 1800, 1801, 1811, 1811, 1801, 1812, + 1801, 1802, 1812, 1812, 1802, 1813, + 1802, 1803, 1813, 1813, 1803, 1814, + 1815, 1816, 1826, 1826, 1816, 1827, + 1816, 1817, 1827, 1827, 1817, 1828, + 1817, 1818, 1828, 1828, 1818, 1829, + 1818, 1819, 1829, 1829, 1819, 1830, + 1819, 1820, 1830, 1830, 1820, 1831, + 1820, 1821, 1831, 1831, 1821, 1832, + 1821, 1822, 1832, 1832, 1822, 1833, + 1822, 1823, 1833, 1833, 1823, 1834, + 1823, 1824, 1834, 1834, 1824, 1835, + 1824, 1825, 1835, 1835, 1825, 1836, + 1826, 1827, 1837, 1837, 1827, 1838, + 1827, 1828, 1838, 1838, 1828, 1839, + 1828, 1829, 1839, 1839, 1829, 1840, + 1829, 1830, 1840, 1840, 1830, 1841, + 1830, 1831, 1841, 1841, 1831, 1842, + 1831, 1832, 1842, 1842, 1832, 1843, + 1832, 1833, 1843, 1843, 1833, 1844, + 1833, 1834, 1844, 1844, 1834, 1845, + 1834, 1835, 1845, 1845, 1835, 1846, + 1835, 1836, 1846, 1846, 1836, 1847, + 1837, 1838, 1848, 1848, 1838, 1849, + 1838, 1839, 1849, 1849, 1839, 1850, + 1839, 1840, 1850, 1850, 1840, 1851, + 1840, 1841, 1851, 1851, 1841, 1852, + 1841, 1842, 1852, 1852, 1842, 1853, + 1842, 1843, 1853, 1853, 1843, 1854, + 1843, 1844, 1854, 1854, 1844, 1855, + 1844, 1845, 1855, 1855, 1845, 1856, + 1845, 1846, 1856, 1856, 1846, 1857, + 1846, 1847, 1857, 1857, 1847, 1858, + 1848, 1849, 1859, 1859, 1849, 1860, + 1849, 1850, 1860, 1860, 1850, 1861, + 1850, 1851, 1861, 1861, 1851, 1862, + 1851, 1852, 1862, 1862, 1852, 1863, + 1852, 1853, 1863, 1863, 1853, 1864, + 1853, 1854, 1864, 1864, 1854, 1865, + 1854, 1855, 1865, 1865, 1855, 1866, + 1855, 1856, 1866, 1866, 1856, 1867, + 1856, 1857, 1867, 1867, 1857, 1868, + 1857, 1858, 1868, 1868, 1858, 1869, + 1859, 1860, 1870, 1870, 1860, 1871, + 1860, 1861, 1871, 1871, 1861, 1872, + 1861, 1862, 1872, 1872, 1862, 1873, + 1862, 1863, 1873, 1873, 1863, 1874, + 1863, 1864, 1874, 1874, 1864, 1875, + 1864, 1865, 1875, 1875, 1865, 1876, + 1865, 1866, 1876, 1876, 1866, 1877, + 1866, 1867, 1877, 1877, 1867, 1878, + 1867, 1868, 1878, 1878, 1868, 1879, + 1868, 1869, 1879, 1879, 1869, 1880, + 1870, 1871, 1881, 1881, 1871, 1882, + 1871, 1872, 1882, 1882, 1872, 1883, + 1872, 1873, 1883, 1883, 1873, 1884, + 1873, 1874, 1884, 1884, 1874, 1885, + 1874, 1875, 1885, 1885, 1875, 1886, + 1875, 1876, 1886, 1886, 1876, 1887, + 1876, 1877, 1887, 1887, 1877, 1888, + 1877, 1878, 1888, 1888, 1878, 1889, + 1878, 1879, 1889, 1889, 1879, 1890, + 1879, 1880, 1890, 1890, 1880, 1891, + 1881, 1882, 1892, 1892, 1882, 1893, + 1882, 1883, 1893, 1893, 1883, 1894, + 1883, 1884, 1894, 1894, 1884, 1895, + 1884, 1885, 1895, 1895, 1885, 1896, + 1885, 1886, 1896, 1896, 1886, 1897, + 1886, 1887, 1897, 1897, 1887, 1898, + 1887, 1888, 1898, 1898, 1888, 1899, + 1888, 1889, 1899, 1899, 1889, 1900, + 1889, 1890, 1900, 1900, 1890, 1901, + 1890, 1891, 1901, 1901, 1891, 1902, + 1892, 1893, 1903, 1903, 1893, 1904, + 1893, 1894, 1904, 1904, 1894, 1905, + 1894, 1895, 1905, 1905, 1895, 1906, + 1895, 1896, 1906, 1906, 1896, 1907, + 1896, 1897, 1907, 1907, 1897, 1908, + 1897, 1898, 1908, 1908, 1898, 1909, + 1898, 1899, 1909, 1909, 1899, 1910, + 1899, 1900, 1910, 1910, 1900, 1911, + 1900, 1901, 1911, 1911, 1901, 1912, + 1901, 1902, 1912, 1912, 1902, 1913, + 1903, 1904, 1914, 1914, 1904, 1915, + 1904, 1905, 1915, 1915, 1905, 1916, + 1905, 1906, 1916, 1916, 1906, 1917, + 1906, 1907, 1917, 1917, 1907, 1918, + 1907, 1908, 1918, 1918, 1908, 1919, + 1908, 1909, 1919, 1919, 1909, 1920, + 1909, 1910, 1920, 1920, 1910, 1921, + 1910, 1911, 1921, 1921, 1911, 1922, + 1911, 1912, 1922, 1922, 1912, 1923, + 1912, 1913, 1923, 1923, 1913, 1924, + 1914, 1915, 1925, 1925, 1915, 1926, + 1915, 1916, 1926, 1926, 1916, 1927, + 1916, 1917, 1927, 1927, 1917, 1928, + 1917, 1918, 1928, 1928, 1918, 1929, + 1918, 1919, 1929, 1929, 1919, 1930, + 1919, 1920, 1930, 1930, 1920, 1931, + 1920, 1921, 1931, 1931, 1921, 1932, + 1921, 1922, 1932, 1932, 1922, 1933, + 1922, 1923, 1933, 1933, 1923, 1934, + 1923, 1924, 1934, 1934, 1924, 1935, + 1936, 1937, 1947, 1947, 1937, 1948, + 1937, 1938, 1948, 1948, 1938, 1949, + 1938, 1939, 1949, 1949, 1939, 1950, + 1939, 1940, 1950, 1950, 1940, 1951, + 1940, 1941, 1951, 1951, 1941, 1952, + 1941, 1942, 1952, 1952, 1942, 1953, + 1942, 1943, 1953, 1953, 1943, 1954, + 1943, 1944, 1954, 1954, 1944, 1955, + 1944, 1945, 1955, 1955, 1945, 1956, + 1945, 1946, 1956, 1956, 1946, 1957, + 1947, 1948, 1958, 1958, 1948, 1959, + 1948, 1949, 1959, 1959, 1949, 1960, + 1949, 1950, 1960, 1960, 1950, 1961, + 1950, 1951, 1961, 1961, 1951, 1962, + 1951, 1952, 1962, 1962, 1952, 1963, + 1952, 1953, 1963, 1963, 1953, 1964, + 1953, 1954, 1964, 1964, 1954, 1965, + 1954, 1955, 1965, 1965, 1955, 1966, + 1955, 1956, 1966, 1966, 1956, 1967, + 1956, 1957, 1967, 1967, 1957, 1968, + 1958, 1959, 1969, 1969, 1959, 1970, + 1959, 1960, 1970, 1970, 1960, 1971, + 1960, 1961, 1971, 1971, 1961, 1972, + 1961, 1962, 1972, 1972, 1962, 1973, + 1962, 1963, 1973, 1973, 1963, 1974, + 1963, 1964, 1974, 1974, 1964, 1975, + 1964, 1965, 1975, 1975, 1965, 1976, + 1965, 1966, 1976, 1976, 1966, 1977, + 1966, 1967, 1977, 1977, 1967, 1978, + 1967, 1968, 1978, 1978, 1968, 1979, + 1969, 1970, 1980, 1980, 1970, 1981, + 1970, 1971, 1981, 1981, 1971, 1982, + 1971, 1972, 1982, 1982, 1972, 1983, + 1972, 1973, 1983, 1983, 1973, 1984, + 1973, 1974, 1984, 1984, 1974, 1985, + 1974, 1975, 1985, 1985, 1975, 1986, + 1975, 1976, 1986, 1986, 1976, 1987, + 1976, 1977, 1987, 1987, 1977, 1988, + 1977, 1978, 1988, 1988, 1978, 1989, + 1978, 1979, 1989, 1989, 1979, 1990, + 1980, 1981, 1991, 1991, 1981, 1992, + 1981, 1982, 1992, 1992, 1982, 1993, + 1982, 1983, 1993, 1993, 1983, 1994, + 1983, 1984, 1994, 1994, 1984, 1995, + 1984, 1985, 1995, 1995, 1985, 1996, + 1985, 1986, 1996, 1996, 1986, 1997, + 1986, 1987, 1997, 1997, 1987, 1998, + 1987, 1988, 1998, 1998, 1988, 1999, + 1988, 1989, 1999, 1999, 1989, 2000, + 1989, 1990, 2000, 2000, 1990, 2001, + 1991, 1992, 2002, 2002, 1992, 2003, + 1992, 1993, 2003, 2003, 1993, 2004, + 1993, 1994, 2004, 2004, 1994, 2005, + 1994, 1995, 2005, 2005, 1995, 2006, + 1995, 1996, 2006, 2006, 1996, 2007, + 1996, 1997, 2007, 2007, 1997, 2008, + 1997, 1998, 2008, 2008, 1998, 2009, + 1998, 1999, 2009, 2009, 1999, 2010, + 1999, 2000, 2010, 2010, 2000, 2011, + 2000, 2001, 2011, 2011, 2001, 2012, + 2002, 2003, 2013, 2013, 2003, 2014, + 2003, 2004, 2014, 2014, 2004, 2015, + 2004, 2005, 2015, 2015, 2005, 2016, + 2005, 2006, 2016, 2016, 2006, 2017, + 2006, 2007, 2017, 2017, 2007, 2018, + 2007, 2008, 2018, 2018, 2008, 2019, + 2008, 2009, 2019, 2019, 2009, 2020, + 2009, 2010, 2020, 2020, 2010, 2021, + 2010, 2011, 2021, 2021, 2011, 2022, + 2011, 2012, 2022, 2022, 2012, 2023, + 2013, 2014, 2024, 2024, 2014, 2025, + 2014, 2015, 2025, 2025, 2015, 2026, + 2015, 2016, 2026, 2026, 2016, 2027, + 2016, 2017, 2027, 2027, 2017, 2028, + 2017, 2018, 2028, 2028, 2018, 2029, + 2018, 2019, 2029, 2029, 2019, 2030, + 2019, 2020, 2030, 2030, 2020, 2031, + 2020, 2021, 2031, 2031, 2021, 2032, + 2021, 2022, 2032, 2032, 2022, 2033, + 2022, 2023, 2033, 2033, 2023, 2034, + 2024, 2025, 2035, 2035, 2025, 2036, + 2025, 2026, 2036, 2036, 2026, 2037, + 2026, 2027, 2037, 2037, 2027, 2038, + 2027, 2028, 2038, 2038, 2028, 2039, + 2028, 2029, 2039, 2039, 2029, 2040, + 2029, 2030, 2040, 2040, 2030, 2041, + 2030, 2031, 2041, 2041, 2031, 2042, + 2031, 2032, 2042, 2042, 2032, 2043, + 2032, 2033, 2043, 2043, 2033, 2044, + 2033, 2034, 2044, 2044, 2034, 2045, + 2035, 2036, 2046, 2046, 2036, 2047, + 2036, 2037, 2047, 2047, 2037, 2048, + 2037, 2038, 2048, 2048, 2038, 2049, + 2038, 2039, 2049, 2049, 2039, 2050, + 2039, 2040, 2050, 2050, 2040, 2051, + 2040, 2041, 2051, 2051, 2041, 2052, + 2041, 2042, 2052, 2052, 2042, 2053, + 2042, 2043, 2053, 2053, 2043, 2054, + 2043, 2044, 2054, 2054, 2044, 2055, + 2044, 2045, 2055, 2055, 2045, 2056, + 2057, 2058, 2068, 2068, 2058, 2069, + 2058, 2059, 2069, 2069, 2059, 2070, + 2059, 2060, 2070, 2070, 2060, 2071, + 2060, 2061, 2071, 2071, 2061, 2072, + 2061, 2062, 2072, 2072, 2062, 2073, + 2062, 2063, 2073, 2073, 2063, 2074, + 2063, 2064, 2074, 2074, 2064, 2075, + 2064, 2065, 2075, 2075, 2065, 2076, + 2065, 2066, 2076, 2076, 2066, 2077, + 2066, 2067, 2077, 2077, 2067, 2078, + 2068, 2069, 2079, 2079, 2069, 2080, + 2069, 2070, 2080, 2080, 2070, 2081, + 2070, 2071, 2081, 2081, 2071, 2082, + 2071, 2072, 2082, 2082, 2072, 2083, + 2072, 2073, 2083, 2083, 2073, 2084, + 2073, 2074, 2084, 2084, 2074, 2085, + 2074, 2075, 2085, 2085, 2075, 2086, + 2075, 2076, 2086, 2086, 2076, 2087, + 2076, 2077, 2087, 2087, 2077, 2088, + 2077, 2078, 2088, 2088, 2078, 2089, + 2079, 2080, 2090, 2090, 2080, 2091, + 2080, 2081, 2091, 2091, 2081, 2092, + 2081, 2082, 2092, 2092, 2082, 2093, + 2082, 2083, 2093, 2093, 2083, 2094, + 2083, 2084, 2094, 2094, 2084, 2095, + 2084, 2085, 2095, 2095, 2085, 2096, + 2085, 2086, 2096, 2096, 2086, 2097, + 2086, 2087, 2097, 2097, 2087, 2098, + 2087, 2088, 2098, 2098, 2088, 2099, + 2088, 2089, 2099, 2099, 2089, 2100, + 2090, 2091, 2101, 2101, 2091, 2102, + 2091, 2092, 2102, 2102, 2092, 2103, + 2092, 2093, 2103, 2103, 2093, 2104, + 2093, 2094, 2104, 2104, 2094, 2105, + 2094, 2095, 2105, 2105, 2095, 2106, + 2095, 2096, 2106, 2106, 2096, 2107, + 2096, 2097, 2107, 2107, 2097, 2108, + 2097, 2098, 2108, 2108, 2098, 2109, + 2098, 2099, 2109, 2109, 2099, 2110, + 2099, 2100, 2110, 2110, 2100, 2111, + 2101, 2102, 2112, 2112, 2102, 2113, + 2102, 2103, 2113, 2113, 2103, 2114, + 2103, 2104, 2114, 2114, 2104, 2115, + 2104, 2105, 2115, 2115, 2105, 2116, + 2105, 2106, 2116, 2116, 2106, 2117, + 2106, 2107, 2117, 2117, 2107, 2118, + 2107, 2108, 2118, 2118, 2108, 2119, + 2108, 2109, 2119, 2119, 2109, 2120, + 2109, 2110, 2120, 2120, 2110, 2121, + 2110, 2111, 2121, 2121, 2111, 2122, + 2112, 2113, 2123, 2123, 2113, 2124, + 2113, 2114, 2124, 2124, 2114, 2125, + 2114, 2115, 2125, 2125, 2115, 2126, + 2115, 2116, 2126, 2126, 2116, 2127, + 2116, 2117, 2127, 2127, 2117, 2128, + 2117, 2118, 2128, 2128, 2118, 2129, + 2118, 2119, 2129, 2129, 2119, 2130, + 2119, 2120, 2130, 2130, 2120, 2131, + 2120, 2121, 2131, 2131, 2121, 2132, + 2121, 2122, 2132, 2132, 2122, 2133, + 2123, 2124, 2134, 2134, 2124, 2135, + 2124, 2125, 2135, 2135, 2125, 2136, + 2125, 2126, 2136, 2136, 2126, 2137, + 2126, 2127, 2137, 2137, 2127, 2138, + 2127, 2128, 2138, 2138, 2128, 2139, + 2128, 2129, 2139, 2139, 2129, 2140, + 2129, 2130, 2140, 2140, 2130, 2141, + 2130, 2131, 2141, 2141, 2131, 2142, + 2131, 2132, 2142, 2142, 2132, 2143, + 2132, 2133, 2143, 2143, 2133, 2144, + 2134, 2135, 2145, 2145, 2135, 2146, + 2135, 2136, 2146, 2146, 2136, 2147, + 2136, 2137, 2147, 2147, 2137, 2148, + 2137, 2138, 2148, 2148, 2138, 2149, + 2138, 2139, 2149, 2149, 2139, 2150, + 2139, 2140, 2150, 2150, 2140, 2151, + 2140, 2141, 2151, 2151, 2141, 2152, + 2141, 2142, 2152, 2152, 2142, 2153, + 2142, 2143, 2153, 2153, 2143, 2154, + 2143, 2144, 2154, 2154, 2144, 2155, + 2145, 2146, 2156, 2156, 2146, 2157, + 2146, 2147, 2157, 2157, 2147, 2158, + 2147, 2148, 2158, 2158, 2148, 2159, + 2148, 2149, 2159, 2159, 2149, 2160, + 2149, 2150, 2160, 2160, 2150, 2161, + 2150, 2151, 2161, 2161, 2151, 2162, + 2151, 2152, 2162, 2162, 2152, 2163, + 2152, 2153, 2163, 2163, 2153, 2164, + 2153, 2154, 2164, 2164, 2154, 2165, + 2154, 2155, 2165, 2165, 2155, 2166, + 2156, 2157, 2167, 2167, 2157, 2168, + 2157, 2158, 2168, 2168, 2158, 2169, + 2158, 2159, 2169, 2169, 2159, 2170, + 2159, 2160, 2170, 2170, 2160, 2171, + 2160, 2161, 2171, 2171, 2161, 2172, + 2161, 2162, 2172, 2172, 2162, 2173, + 2162, 2163, 2173, 2173, 2163, 2174, + 2163, 2164, 2174, 2174, 2164, 2175, + 2164, 2165, 2175, 2175, 2165, 2176, + 2165, 2166, 2176, 2176, 2166, 2177, + 2178, 2179, 2189, 2189, 2179, 2190, + 2179, 2180, 2190, 2190, 2180, 2191, + 2180, 2181, 2191, 2191, 2181, 2192, + 2181, 2182, 2192, 2192, 2182, 2193, + 2182, 2183, 2193, 2193, 2183, 2194, + 2183, 2184, 2194, 2194, 2184, 2195, + 2184, 2185, 2195, 2195, 2185, 2196, + 2185, 2186, 2196, 2196, 2186, 2197, + 2186, 2187, 2197, 2197, 2187, 2198, + 2187, 2188, 2198, 2198, 2188, 2199, + 2189, 2190, 2200, 2200, 2190, 2201, + 2190, 2191, 2201, 2201, 2191, 2202, + 2191, 2192, 2202, 2202, 2192, 2203, + 2192, 2193, 2203, 2203, 2193, 2204, + 2193, 2194, 2204, 2204, 2194, 2205, + 2194, 2195, 2205, 2205, 2195, 2206, + 2195, 2196, 2206, 2206, 2196, 2207, + 2196, 2197, 2207, 2207, 2197, 2208, + 2197, 2198, 2208, 2208, 2198, 2209, + 2198, 2199, 2209, 2209, 2199, 2210, + 2200, 2201, 2211, 2211, 2201, 2212, + 2201, 2202, 2212, 2212, 2202, 2213, + 2202, 2203, 2213, 2213, 2203, 2214, + 2203, 2204, 2214, 2214, 2204, 2215, + 2204, 2205, 2215, 2215, 2205, 2216, + 2205, 2206, 2216, 2216, 2206, 2217, + 2206, 2207, 2217, 2217, 2207, 2218, + 2207, 2208, 2218, 2218, 2208, 2219, + 2208, 2209, 2219, 2219, 2209, 2220, + 2209, 2210, 2220, 2220, 2210, 2221, + 2211, 2212, 2222, 2222, 2212, 2223, + 2212, 2213, 2223, 2223, 2213, 2224, + 2213, 2214, 2224, 2224, 2214, 2225, + 2214, 2215, 2225, 2225, 2215, 2226, + 2215, 2216, 2226, 2226, 2216, 2227, + 2216, 2217, 2227, 2227, 2217, 2228, + 2217, 2218, 2228, 2228, 2218, 2229, + 2218, 2219, 2229, 2229, 2219, 2230, + 2219, 2220, 2230, 2230, 2220, 2231, + 2220, 2221, 2231, 2231, 2221, 2232, + 2222, 2223, 2233, 2233, 2223, 2234, + 2223, 2224, 2234, 2234, 2224, 2235, + 2224, 2225, 2235, 2235, 2225, 2236, + 2225, 2226, 2236, 2236, 2226, 2237, + 2226, 2227, 2237, 2237, 2227, 2238, + 2227, 2228, 2238, 2238, 2228, 2239, + 2228, 2229, 2239, 2239, 2229, 2240, + 2229, 2230, 2240, 2240, 2230, 2241, + 2230, 2231, 2241, 2241, 2231, 2242, + 2231, 2232, 2242, 2242, 2232, 2243, + 2233, 2234, 2244, 2244, 2234, 2245, + 2234, 2235, 2245, 2245, 2235, 2246, + 2235, 2236, 2246, 2246, 2236, 2247, + 2236, 2237, 2247, 2247, 2237, 2248, + 2237, 2238, 2248, 2248, 2238, 2249, + 2238, 2239, 2249, 2249, 2239, 2250, + 2239, 2240, 2250, 2250, 2240, 2251, + 2240, 2241, 2251, 2251, 2241, 2252, + 2241, 2242, 2252, 2252, 2242, 2253, + 2242, 2243, 2253, 2253, 2243, 2254, + 2244, 2245, 2255, 2255, 2245, 2256, + 2245, 2246, 2256, 2256, 2246, 2257, + 2246, 2247, 2257, 2257, 2247, 2258, + 2247, 2248, 2258, 2258, 2248, 2259, + 2248, 2249, 2259, 2259, 2249, 2260, + 2249, 2250, 2260, 2260, 2250, 2261, + 2250, 2251, 2261, 2261, 2251, 2262, + 2251, 2252, 2262, 2262, 2252, 2263, + 2252, 2253, 2263, 2263, 2253, 2264, + 2253, 2254, 2264, 2264, 2254, 2265, + 2255, 2256, 2266, 2266, 2256, 2267, + 2256, 2257, 2267, 2267, 2257, 2268, + 2257, 2258, 2268, 2268, 2258, 2269, + 2258, 2259, 2269, 2269, 2259, 2270, + 2259, 2260, 2270, 2270, 2260, 2271, + 2260, 2261, 2271, 2271, 2261, 2272, + 2261, 2262, 2272, 2272, 2262, 2273, + 2262, 2263, 2273, 2273, 2263, 2274, + 2263, 2264, 2274, 2274, 2264, 2275, + 2264, 2265, 2275, 2275, 2265, 2276, + 2266, 2267, 2277, 2277, 2267, 2278, + 2267, 2268, 2278, 2278, 2268, 2279, + 2268, 2269, 2279, 2279, 2269, 2280, + 2269, 2270, 2280, 2280, 2270, 2281, + 2270, 2271, 2281, 2281, 2271, 2282, + 2271, 2272, 2282, 2282, 2272, 2283, + 2272, 2273, 2283, 2283, 2273, 2284, + 2273, 2274, 2284, 2284, 2274, 2285, + 2274, 2275, 2285, 2285, 2275, 2286, + 2275, 2276, 2286, 2286, 2276, 2287, + 2277, 2278, 2288, 2288, 2278, 2289, + 2278, 2279, 2289, 2289, 2279, 2290, + 2279, 2280, 2290, 2290, 2280, 2291, + 2280, 2281, 2291, 2291, 2281, 2292, + 2281, 2282, 2292, 2292, 2282, 2293, + 2282, 2283, 2293, 2293, 2283, 2294, + 2283, 2284, 2294, 2294, 2284, 2295, + 2284, 2285, 2295, 2295, 2285, 2296, + 2285, 2286, 2296, 2296, 2286, 2297, + 2286, 2287, 2297, 2297, 2287, 2298, + 2299, 2300, 2310, 2310, 2300, 2311, + 2300, 2301, 2311, 2311, 2301, 2312, + 2301, 2302, 2312, 2312, 2302, 2313, + 2302, 2303, 2313, 2313, 2303, 2314, + 2303, 2304, 2314, 2314, 2304, 2315, + 2304, 2305, 2315, 2315, 2305, 2316, + 2305, 2306, 2316, 2316, 2306, 2317, + 2306, 2307, 2317, 2317, 2307, 2318, + 2307, 2308, 2318, 2318, 2308, 2319, + 2308, 2309, 2319, 2319, 2309, 2320, + 2310, 2311, 2321, 2321, 2311, 2322, + 2311, 2312, 2322, 2322, 2312, 2323, + 2312, 2313, 2323, 2323, 2313, 2324, + 2313, 2314, 2324, 2324, 2314, 2325, + 2314, 2315, 2325, 2325, 2315, 2326, + 2315, 2316, 2326, 2326, 2316, 2327, + 2316, 2317, 2327, 2327, 2317, 2328, + 2317, 2318, 2328, 2328, 2318, 2329, + 2318, 2319, 2329, 2329, 2319, 2330, + 2319, 2320, 2330, 2330, 2320, 2331, + 2321, 2322, 2332, 2332, 2322, 2333, + 2322, 2323, 2333, 2333, 2323, 2334, + 2323, 2324, 2334, 2334, 2324, 2335, + 2324, 2325, 2335, 2335, 2325, 2336, + 2325, 2326, 2336, 2336, 2326, 2337, + 2326, 2327, 2337, 2337, 2327, 2338, + 2327, 2328, 2338, 2338, 2328, 2339, + 2328, 2329, 2339, 2339, 2329, 2340, + 2329, 2330, 2340, 2340, 2330, 2341, + 2330, 2331, 2341, 2341, 2331, 2342, + 2332, 2333, 2343, 2343, 2333, 2344, + 2333, 2334, 2344, 2344, 2334, 2345, + 2334, 2335, 2345, 2345, 2335, 2346, + 2335, 2336, 2346, 2346, 2336, 2347, + 2336, 2337, 2347, 2347, 2337, 2348, + 2337, 2338, 2348, 2348, 2338, 2349, + 2338, 2339, 2349, 2349, 2339, 2350, + 2339, 2340, 2350, 2350, 2340, 2351, + 2340, 2341, 2351, 2351, 2341, 2352, + 2341, 2342, 2352, 2352, 2342, 2353, + 2343, 2344, 2354, 2354, 2344, 2355, + 2344, 2345, 2355, 2355, 2345, 2356, + 2345, 2346, 2356, 2356, 2346, 2357, + 2346, 2347, 2357, 2357, 2347, 2358, + 2347, 2348, 2358, 2358, 2348, 2359, + 2348, 2349, 2359, 2359, 2349, 2360, + 2349, 2350, 2360, 2360, 2350, 2361, + 2350, 2351, 2361, 2361, 2351, 2362, + 2351, 2352, 2362, 2362, 2352, 2363, + 2352, 2353, 2363, 2363, 2353, 2364, + 2354, 2355, 2365, 2365, 2355, 2366, + 2355, 2356, 2366, 2366, 2356, 2367, + 2356, 2357, 2367, 2367, 2357, 2368, + 2357, 2358, 2368, 2368, 2358, 2369, + 2358, 2359, 2369, 2369, 2359, 2370, + 2359, 2360, 2370, 2370, 2360, 2371, + 2360, 2361, 2371, 2371, 2361, 2372, + 2361, 2362, 2372, 2372, 2362, 2373, + 2362, 2363, 2373, 2373, 2363, 2374, + 2363, 2364, 2374, 2374, 2364, 2375, + 2365, 2366, 2376, 2376, 2366, 2377, + 2366, 2367, 2377, 2377, 2367, 2378, + 2367, 2368, 2378, 2378, 2368, 2379, + 2368, 2369, 2379, 2379, 2369, 2380, + 2369, 2370, 2380, 2380, 2370, 2381, + 2370, 2371, 2381, 2381, 2371, 2382, + 2371, 2372, 2382, 2382, 2372, 2383, + 2372, 2373, 2383, 2383, 2373, 2384, + 2373, 2374, 2384, 2384, 2374, 2385, + 2374, 2375, 2385, 2385, 2375, 2386, + 2376, 2377, 2387, 2387, 2377, 2388, + 2377, 2378, 2388, 2388, 2378, 2389, + 2378, 2379, 2389, 2389, 2379, 2390, + 2379, 2380, 2390, 2390, 2380, 2391, + 2380, 2381, 2391, 2391, 2381, 2392, + 2381, 2382, 2392, 2392, 2382, 2393, + 2382, 2383, 2393, 2393, 2383, 2394, + 2383, 2384, 2394, 2394, 2384, 2395, + 2384, 2385, 2395, 2395, 2385, 2396, + 2385, 2386, 2396, 2396, 2386, 2397, + 2387, 2388, 2398, 2398, 2388, 2399, + 2388, 2389, 2399, 2399, 2389, 2400, + 2389, 2390, 2400, 2400, 2390, 2401, + 2390, 2391, 2401, 2401, 2391, 2402, + 2391, 2392, 2402, 2402, 2392, 2403, + 2392, 2393, 2403, 2403, 2393, 2404, + 2393, 2394, 2404, 2404, 2394, 2405, + 2394, 2395, 2405, 2405, 2395, 2406, + 2395, 2396, 2406, 2406, 2396, 2407, + 2396, 2397, 2407, 2407, 2397, 2408, + 2398, 2399, 2409, 2409, 2399, 2410, + 2399, 2400, 2410, 2410, 2400, 2411, + 2400, 2401, 2411, 2411, 2401, 2412, + 2401, 2402, 2412, 2412, 2402, 2413, + 2402, 2403, 2413, 2413, 2403, 2414, + 2403, 2404, 2414, 2414, 2404, 2415, + 2404, 2405, 2415, 2415, 2405, 2416, + 2405, 2406, 2416, 2416, 2406, 2417, + 2406, 2407, 2417, 2417, 2407, 2418, + 2407, 2408, 2418, 2418, 2408, 2419, + 2420, 2421, 2431, 2431, 2421, 2432, + 2421, 2422, 2432, 2432, 2422, 2433, + 2422, 2423, 2433, 2433, 2423, 2434, + 2423, 2424, 2434, 2434, 2424, 2435, + 2424, 2425, 2435, 2435, 2425, 2436, + 2425, 2426, 2436, 2436, 2426, 2437, + 2426, 2427, 2437, 2437, 2427, 2438, + 2427, 2428, 2438, 2438, 2428, 2439, + 2428, 2429, 2439, 2439, 2429, 2440, + 2429, 2430, 2440, 2440, 2430, 2441, + 2431, 2432, 2442, 2442, 2432, 2443, + 2432, 2433, 2443, 2443, 2433, 2444, + 2433, 2434, 2444, 2444, 2434, 2445, + 2434, 2435, 2445, 2445, 2435, 2446, + 2435, 2436, 2446, 2446, 2436, 2447, + 2436, 2437, 2447, 2447, 2437, 2448, + 2437, 2438, 2448, 2448, 2438, 2449, + 2438, 2439, 2449, 2449, 2439, 2450, + 2439, 2440, 2450, 2450, 2440, 2451, + 2440, 2441, 2451, 2451, 2441, 2452, + 2442, 2443, 2453, 2453, 2443, 2454, + 2443, 2444, 2454, 2454, 2444, 2455, + 2444, 2445, 2455, 2455, 2445, 2456, + 2445, 2446, 2456, 2456, 2446, 2457, + 2446, 2447, 2457, 2457, 2447, 2458, + 2447, 2448, 2458, 2458, 2448, 2459, + 2448, 2449, 2459, 2459, 2449, 2460, + 2449, 2450, 2460, 2460, 2450, 2461, + 2450, 2451, 2461, 2461, 2451, 2462, + 2451, 2452, 2462, 2462, 2452, 2463, + 2453, 2454, 2464, 2464, 2454, 2465, + 2454, 2455, 2465, 2465, 2455, 2466, + 2455, 2456, 2466, 2466, 2456, 2467, + 2456, 2457, 2467, 2467, 2457, 2468, + 2457, 2458, 2468, 2468, 2458, 2469, + 2458, 2459, 2469, 2469, 2459, 2470, + 2459, 2460, 2470, 2470, 2460, 2471, + 2460, 2461, 2471, 2471, 2461, 2472, + 2461, 2462, 2472, 2472, 2462, 2473, + 2462, 2463, 2473, 2473, 2463, 2474, + 2464, 2465, 2475, 2475, 2465, 2476, + 2465, 2466, 2476, 2476, 2466, 2477, + 2466, 2467, 2477, 2477, 2467, 2478, + 2467, 2468, 2478, 2478, 2468, 2479, + 2468, 2469, 2479, 2479, 2469, 2480, + 2469, 2470, 2480, 2480, 2470, 2481, + 2470, 2471, 2481, 2481, 2471, 2482, + 2471, 2472, 2482, 2482, 2472, 2483, + 2472, 2473, 2483, 2483, 2473, 2484, + 2473, 2474, 2484, 2484, 2474, 2485, + 2475, 2476, 2486, 2486, 2476, 2487, + 2476, 2477, 2487, 2487, 2477, 2488, + 2477, 2478, 2488, 2488, 2478, 2489, + 2478, 2479, 2489, 2489, 2479, 2490, + 2479, 2480, 2490, 2490, 2480, 2491, + 2480, 2481, 2491, 2491, 2481, 2492, + 2481, 2482, 2492, 2492, 2482, 2493, + 2482, 2483, 2493, 2493, 2483, 2494, + 2483, 2484, 2494, 2494, 2484, 2495, + 2484, 2485, 2495, 2495, 2485, 2496, + 2486, 2487, 2497, 2497, 2487, 2498, + 2487, 2488, 2498, 2498, 2488, 2499, + 2488, 2489, 2499, 2499, 2489, 2500, + 2489, 2490, 2500, 2500, 2490, 2501, + 2490, 2491, 2501, 2501, 2491, 2502, + 2491, 2492, 2502, 2502, 2492, 2503, + 2492, 2493, 2503, 2503, 2493, 2504, + 2493, 2494, 2504, 2504, 2494, 2505, + 2494, 2495, 2505, 2505, 2495, 2506, + 2495, 2496, 2506, 2506, 2496, 2507, + 2497, 2498, 2508, 2508, 2498, 2509, + 2498, 2499, 2509, 2509, 2499, 2510, + 2499, 2500, 2510, 2510, 2500, 2511, + 2500, 2501, 2511, 2511, 2501, 2512, + 2501, 2502, 2512, 2512, 2502, 2513, + 2502, 2503, 2513, 2513, 2503, 2514, + 2503, 2504, 2514, 2514, 2504, 2515, + 2504, 2505, 2515, 2515, 2505, 2516, + 2505, 2506, 2516, 2516, 2506, 2517, + 2506, 2507, 2517, 2517, 2507, 2518, + 2508, 2509, 2519, 2519, 2509, 2520, + 2509, 2510, 2520, 2520, 2510, 2521, + 2510, 2511, 2521, 2521, 2511, 2522, + 2511, 2512, 2522, 2522, 2512, 2523, + 2512, 2513, 2523, 2523, 2513, 2524, + 2513, 2514, 2524, 2524, 2514, 2525, + 2514, 2515, 2525, 2525, 2515, 2526, + 2515, 2516, 2526, 2526, 2516, 2527, + 2516, 2517, 2527, 2527, 2517, 2528, + 2517, 2518, 2528, 2528, 2518, 2529, + 2519, 2520, 2530, 2530, 2520, 2531, + 2520, 2521, 2531, 2531, 2521, 2532, + 2521, 2522, 2532, 2532, 2522, 2533, + 2522, 2523, 2533, 2533, 2523, 2534, + 2523, 2524, 2534, 2534, 2524, 2535, + 2524, 2525, 2535, 2535, 2525, 2536, + 2525, 2526, 2536, 2536, 2526, 2537, + 2526, 2527, 2537, 2537, 2527, 2538, + 2527, 2528, 2538, 2538, 2528, 2539, + 2528, 2529, 2539, 2539, 2529, 2540, + 2541, 2542, 2552, 2552, 2542, 2553, + 2542, 2543, 2553, 2553, 2543, 2554, + 2543, 2544, 2554, 2554, 2544, 2555, + 2544, 2545, 2555, 2555, 2545, 2556, + 2545, 2546, 2556, 2556, 2546, 2557, + 2546, 2547, 2557, 2557, 2547, 2558, + 2547, 2548, 2558, 2558, 2548, 2559, + 2548, 2549, 2559, 2559, 2549, 2560, + 2549, 2550, 2560, 2560, 2550, 2561, + 2550, 2551, 2561, 2561, 2551, 2562, + 2552, 2553, 2563, 2563, 2553, 2564, + 2553, 2554, 2564, 2564, 2554, 2565, + 2554, 2555, 2565, 2565, 2555, 2566, + 2555, 2556, 2566, 2566, 2556, 2567, + 2556, 2557, 2567, 2567, 2557, 2568, + 2557, 2558, 2568, 2568, 2558, 2569, + 2558, 2559, 2569, 2569, 2559, 2570, + 2559, 2560, 2570, 2570, 2560, 2571, + 2560, 2561, 2571, 2571, 2561, 2572, + 2561, 2562, 2572, 2572, 2562, 2573, + 2563, 2564, 2574, 2574, 2564, 2575, + 2564, 2565, 2575, 2575, 2565, 2576, + 2565, 2566, 2576, 2576, 2566, 2577, + 2566, 2567, 2577, 2577, 2567, 2578, + 2567, 2568, 2578, 2578, 2568, 2579, + 2568, 2569, 2579, 2579, 2569, 2580, + 2569, 2570, 2580, 2580, 2570, 2581, + 2570, 2571, 2581, 2581, 2571, 2582, + 2571, 2572, 2582, 2582, 2572, 2583, + 2572, 2573, 2583, 2583, 2573, 2584, + 2574, 2575, 2585, 2585, 2575, 2586, + 2575, 2576, 2586, 2586, 2576, 2587, + 2576, 2577, 2587, 2587, 2577, 2588, + 2577, 2578, 2588, 2588, 2578, 2589, + 2578, 2579, 2589, 2589, 2579, 2590, + 2579, 2580, 2590, 2590, 2580, 2591, + 2580, 2581, 2591, 2591, 2581, 2592, + 2581, 2582, 2592, 2592, 2582, 2593, + 2582, 2583, 2593, 2593, 2583, 2594, + 2583, 2584, 2594, 2594, 2584, 2595, + 2585, 2586, 2596, 2596, 2586, 2597, + 2586, 2587, 2597, 2597, 2587, 2598, + 2587, 2588, 2598, 2598, 2588, 2599, + 2588, 2589, 2599, 2599, 2589, 2600, + 2589, 2590, 2600, 2600, 2590, 2601, + 2590, 2591, 2601, 2601, 2591, 2602, + 2591, 2592, 2602, 2602, 2592, 2603, + 2592, 2593, 2603, 2603, 2593, 2604, + 2593, 2594, 2604, 2604, 2594, 2605, + 2594, 2595, 2605, 2605, 2595, 2606, + 2596, 2597, 2607, 2607, 2597, 2608, + 2597, 2598, 2608, 2608, 2598, 2609, + 2598, 2599, 2609, 2609, 2599, 2610, + 2599, 2600, 2610, 2610, 2600, 2611, + 2600, 2601, 2611, 2611, 2601, 2612, + 2601, 2602, 2612, 2612, 2602, 2613, + 2602, 2603, 2613, 2613, 2603, 2614, + 2603, 2604, 2614, 2614, 2604, 2615, + 2604, 2605, 2615, 2615, 2605, 2616, + 2605, 2606, 2616, 2616, 2606, 2617, + 2607, 2608, 2618, 2618, 2608, 2619, + 2608, 2609, 2619, 2619, 2609, 2620, + 2609, 2610, 2620, 2620, 2610, 2621, + 2610, 2611, 2621, 2621, 2611, 2622, + 2611, 2612, 2622, 2622, 2612, 2623, + 2612, 2613, 2623, 2623, 2613, 2624, + 2613, 2614, 2624, 2624, 2614, 2625, + 2614, 2615, 2625, 2625, 2615, 2626, + 2615, 2616, 2626, 2626, 2616, 2627, + 2616, 2617, 2627, 2627, 2617, 2628, + 2618, 2619, 2629, 2629, 2619, 2630, + 2619, 2620, 2630, 2630, 2620, 2631, + 2620, 2621, 2631, 2631, 2621, 2632, + 2621, 2622, 2632, 2632, 2622, 2633, + 2622, 2623, 2633, 2633, 2623, 2634, + 2623, 2624, 2634, 2634, 2624, 2635, + 2624, 2625, 2635, 2635, 2625, 2636, + 2625, 2626, 2636, 2636, 2626, 2637, + 2626, 2627, 2637, 2637, 2627, 2638, + 2627, 2628, 2638, 2638, 2628, 2639, + 2629, 2630, 2640, 2640, 2630, 2641, + 2630, 2631, 2641, 2641, 2631, 2642, + 2631, 2632, 2642, 2642, 2632, 2643, + 2632, 2633, 2643, 2643, 2633, 2644, + 2633, 2634, 2644, 2644, 2634, 2645, + 2634, 2635, 2645, 2645, 2635, 2646, + 2635, 2636, 2646, 2646, 2636, 2647, + 2636, 2637, 2647, 2647, 2637, 2648, + 2637, 2638, 2648, 2648, 2638, 2649, + 2638, 2639, 2649, 2649, 2639, 2650, + 2640, 2641, 2651, 2651, 2641, 2652, + 2641, 2642, 2652, 2652, 2642, 2653, + 2642, 2643, 2653, 2653, 2643, 2654, + 2643, 2644, 2654, 2654, 2644, 2655, + 2644, 2645, 2655, 2655, 2645, 2656, + 2645, 2646, 2656, 2656, 2646, 2657, + 2646, 2647, 2657, 2657, 2647, 2658, + 2647, 2648, 2658, 2658, 2648, 2659, + 2648, 2649, 2659, 2659, 2649, 2660, + 2649, 2650, 2660, 2660, 2650, 2661, + 2662, 2663, 2673, 2673, 2663, 2674, + 2663, 2664, 2674, 2674, 2664, 2675, + 2664, 2665, 2675, 2675, 2665, 2676, + 2665, 2666, 2676, 2676, 2666, 2677, + 2666, 2667, 2677, 2677, 2667, 2678, + 2667, 2668, 2678, 2678, 2668, 2679, + 2668, 2669, 2679, 2679, 2669, 2680, + 2669, 2670, 2680, 2680, 2670, 2681, + 2670, 2671, 2681, 2681, 2671, 2682, + 2671, 2672, 2682, 2682, 2672, 2683, + 2673, 2674, 2684, 2684, 2674, 2685, + 2674, 2675, 2685, 2685, 2675, 2686, + 2675, 2676, 2686, 2686, 2676, 2687, + 2676, 2677, 2687, 2687, 2677, 2688, + 2677, 2678, 2688, 2688, 2678, 2689, + 2678, 2679, 2689, 2689, 2679, 2690, + 2679, 2680, 2690, 2690, 2680, 2691, + 2680, 2681, 2691, 2691, 2681, 2692, + 2681, 2682, 2692, 2692, 2682, 2693, + 2682, 2683, 2693, 2693, 2683, 2694, + 2684, 2685, 2695, 2695, 2685, 2696, + 2685, 2686, 2696, 2696, 2686, 2697, + 2686, 2687, 2697, 2697, 2687, 2698, + 2687, 2688, 2698, 2698, 2688, 2699, + 2688, 2689, 2699, 2699, 2689, 2700, + 2689, 2690, 2700, 2700, 2690, 2701, + 2690, 2691, 2701, 2701, 2691, 2702, + 2691, 2692, 2702, 2702, 2692, 2703, + 2692, 2693, 2703, 2703, 2693, 2704, + 2693, 2694, 2704, 2704, 2694, 2705, + 2695, 2696, 2706, 2706, 2696, 2707, + 2696, 2697, 2707, 2707, 2697, 2708, + 2697, 2698, 2708, 2708, 2698, 2709, + 2698, 2699, 2709, 2709, 2699, 2710, + 2699, 2700, 2710, 2710, 2700, 2711, + 2700, 2701, 2711, 2711, 2701, 2712, + 2701, 2702, 2712, 2712, 2702, 2713, + 2702, 2703, 2713, 2713, 2703, 2714, + 2703, 2704, 2714, 2714, 2704, 2715, + 2704, 2705, 2715, 2715, 2705, 2716, + 2706, 2707, 2717, 2717, 2707, 2718, + 2707, 2708, 2718, 2718, 2708, 2719, + 2708, 2709, 2719, 2719, 2709, 2720, + 2709, 2710, 2720, 2720, 2710, 2721, + 2710, 2711, 2721, 2721, 2711, 2722, + 2711, 2712, 2722, 2722, 2712, 2723, + 2712, 2713, 2723, 2723, 2713, 2724, + 2713, 2714, 2724, 2724, 2714, 2725, + 2714, 2715, 2725, 2725, 2715, 2726, + 2715, 2716, 2726, 2726, 2716, 2727, + 2717, 2718, 2728, 2728, 2718, 2729, + 2718, 2719, 2729, 2729, 2719, 2730, + 2719, 2720, 2730, 2730, 2720, 2731, + 2720, 2721, 2731, 2731, 2721, 2732, + 2721, 2722, 2732, 2732, 2722, 2733, + 2722, 2723, 2733, 2733, 2723, 2734, + 2723, 2724, 2734, 2734, 2724, 2735, + 2724, 2725, 2735, 2735, 2725, 2736, + 2725, 2726, 2736, 2736, 2726, 2737, + 2726, 2727, 2737, 2737, 2727, 2738, + 2728, 2729, 2739, 2739, 2729, 2740, + 2729, 2730, 2740, 2740, 2730, 2741, + 2730, 2731, 2741, 2741, 2731, 2742, + 2731, 2732, 2742, 2742, 2732, 2743, + 2732, 2733, 2743, 2743, 2733, 2744, + 2733, 2734, 2744, 2744, 2734, 2745, + 2734, 2735, 2745, 2745, 2735, 2746, + 2735, 2736, 2746, 2746, 2736, 2747, + 2736, 2737, 2747, 2747, 2737, 2748, + 2737, 2738, 2748, 2748, 2738, 2749, + 2739, 2740, 2750, 2750, 2740, 2751, + 2740, 2741, 2751, 2751, 2741, 2752, + 2741, 2742, 2752, 2752, 2742, 2753, + 2742, 2743, 2753, 2753, 2743, 2754, + 2743, 2744, 2754, 2754, 2744, 2755, + 2744, 2745, 2755, 2755, 2745, 2756, + 2745, 2746, 2756, 2756, 2746, 2757, + 2746, 2747, 2757, 2757, 2747, 2758, + 2747, 2748, 2758, 2758, 2748, 2759, + 2748, 2749, 2759, 2759, 2749, 2760, + 2750, 2751, 2761, 2761, 2751, 2762, + 2751, 2752, 2762, 2762, 2752, 2763, + 2752, 2753, 2763, 2763, 2753, 2764, + 2753, 2754, 2764, 2764, 2754, 2765, + 2754, 2755, 2765, 2765, 2755, 2766, + 2755, 2756, 2766, 2766, 2756, 2767, + 2756, 2757, 2767, 2767, 2757, 2768, + 2757, 2758, 2768, 2768, 2758, 2769, + 2758, 2759, 2769, 2769, 2759, 2770, + 2759, 2760, 2770, 2770, 2760, 2771, + 2761, 2762, 2772, 2772, 2762, 2773, + 2762, 2763, 2773, 2773, 2763, 2774, + 2763, 2764, 2774, 2774, 2764, 2775, + 2764, 2765, 2775, 2775, 2765, 2776, + 2765, 2766, 2776, 2776, 2766, 2777, + 2766, 2767, 2777, 2777, 2767, 2778, + 2767, 2768, 2778, 2778, 2768, 2779, + 2768, 2769, 2779, 2779, 2769, 2780, + 2769, 2770, 2780, 2780, 2770, 2781, + 2770, 2771, 2781, 2781, 2771, 2782, + 2783, 2784, 2794, 2794, 2784, 2795, + 2784, 2785, 2795, 2795, 2785, 2796, + 2785, 2786, 2796, 2796, 2786, 2797, + 2786, 2787, 2797, 2797, 2787, 2798, + 2787, 2788, 2798, 2798, 2788, 2799, + 2788, 2789, 2799, 2799, 2789, 2800, + 2789, 2790, 2800, 2800, 2790, 2801, + 2790, 2791, 2801, 2801, 2791, 2802, + 2791, 2792, 2802, 2802, 2792, 2803, + 2792, 2793, 2803, 2803, 2793, 2804, + 2794, 2795, 2805, 2805, 2795, 2806, + 2795, 2796, 2806, 2806, 2796, 2807, + 2796, 2797, 2807, 2807, 2797, 2808, + 2797, 2798, 2808, 2808, 2798, 2809, + 2798, 2799, 2809, 2809, 2799, 2810, + 2799, 2800, 2810, 2810, 2800, 2811, + 2800, 2801, 2811, 2811, 2801, 2812, + 2801, 2802, 2812, 2812, 2802, 2813, + 2802, 2803, 2813, 2813, 2803, 2814, + 2803, 2804, 2814, 2814, 2804, 2815, + 2805, 2806, 2816, 2816, 2806, 2817, + 2806, 2807, 2817, 2817, 2807, 2818, + 2807, 2808, 2818, 2818, 2808, 2819, + 2808, 2809, 2819, 2819, 2809, 2820, + 2809, 2810, 2820, 2820, 2810, 2821, + 2810, 2811, 2821, 2821, 2811, 2822, + 2811, 2812, 2822, 2822, 2812, 2823, + 2812, 2813, 2823, 2823, 2813, 2824, + 2813, 2814, 2824, 2824, 2814, 2825, + 2814, 2815, 2825, 2825, 2815, 2826, + 2816, 2817, 2827, 2827, 2817, 2828, + 2817, 2818, 2828, 2828, 2818, 2829, + 2818, 2819, 2829, 2829, 2819, 2830, + 2819, 2820, 2830, 2830, 2820, 2831, + 2820, 2821, 2831, 2831, 2821, 2832, + 2821, 2822, 2832, 2832, 2822, 2833, + 2822, 2823, 2833, 2833, 2823, 2834, + 2823, 2824, 2834, 2834, 2824, 2835, + 2824, 2825, 2835, 2835, 2825, 2836, + 2825, 2826, 2836, 2836, 2826, 2837, + 2827, 2828, 2838, 2838, 2828, 2839, + 2828, 2829, 2839, 2839, 2829, 2840, + 2829, 2830, 2840, 2840, 2830, 2841, + 2830, 2831, 2841, 2841, 2831, 2842, + 2831, 2832, 2842, 2842, 2832, 2843, + 2832, 2833, 2843, 2843, 2833, 2844, + 2833, 2834, 2844, 2844, 2834, 2845, + 2834, 2835, 2845, 2845, 2835, 2846, + 2835, 2836, 2846, 2846, 2836, 2847, + 2836, 2837, 2847, 2847, 2837, 2848, + 2838, 2839, 2849, 2849, 2839, 2850, + 2839, 2840, 2850, 2850, 2840, 2851, + 2840, 2841, 2851, 2851, 2841, 2852, + 2841, 2842, 2852, 2852, 2842, 2853, + 2842, 2843, 2853, 2853, 2843, 2854, + 2843, 2844, 2854, 2854, 2844, 2855, + 2844, 2845, 2855, 2855, 2845, 2856, + 2845, 2846, 2856, 2856, 2846, 2857, + 2846, 2847, 2857, 2857, 2847, 2858, + 2847, 2848, 2858, 2858, 2848, 2859, + 2849, 2850, 2860, 2860, 2850, 2861, + 2850, 2851, 2861, 2861, 2851, 2862, + 2851, 2852, 2862, 2862, 2852, 2863, + 2852, 2853, 2863, 2863, 2853, 2864, + 2853, 2854, 2864, 2864, 2854, 2865, + 2854, 2855, 2865, 2865, 2855, 2866, + 2855, 2856, 2866, 2866, 2856, 2867, + 2856, 2857, 2867, 2867, 2857, 2868, + 2857, 2858, 2868, 2868, 2858, 2869, + 2858, 2859, 2869, 2869, 2859, 2870, + 2860, 2861, 2871, 2871, 2861, 2872, + 2861, 2862, 2872, 2872, 2862, 2873, + 2862, 2863, 2873, 2873, 2863, 2874, + 2863, 2864, 2874, 2874, 2864, 2875, + 2864, 2865, 2875, 2875, 2865, 2876, + 2865, 2866, 2876, 2876, 2866, 2877, + 2866, 2867, 2877, 2877, 2867, 2878, + 2867, 2868, 2878, 2878, 2868, 2879, + 2868, 2869, 2879, 2879, 2869, 2880, + 2869, 2870, 2880, 2880, 2870, 2881, + 2871, 2872, 2882, 2882, 2872, 2883, + 2872, 2873, 2883, 2883, 2873, 2884, + 2873, 2874, 2884, 2884, 2874, 2885, + 2874, 2875, 2885, 2885, 2875, 2886, + 2875, 2876, 2886, 2886, 2876, 2887, + 2876, 2877, 2887, 2887, 2877, 2888, + 2877, 2878, 2888, 2888, 2878, 2889, + 2878, 2879, 2889, 2889, 2879, 2890, + 2879, 2880, 2890, 2890, 2880, 2891, + 2880, 2881, 2891, 2891, 2881, 2892, + 2882, 2883, 2893, 2893, 2883, 2894, + 2883, 2884, 2894, 2894, 2884, 2895, + 2884, 2885, 2895, 2895, 2885, 2896, + 2885, 2886, 2896, 2896, 2886, 2897, + 2886, 2887, 2897, 2897, 2887, 2898, + 2887, 2888, 2898, 2898, 2888, 2899, + 2888, 2889, 2899, 2899, 2889, 2900, + 2889, 2890, 2900, 2900, 2890, 2901, + 2890, 2891, 2901, 2901, 2891, 2902, + 2891, 2892, 2902, 2902, 2892, 2903, + 2904, 2905, 2915, 2915, 2905, 2916, + 2905, 2906, 2916, 2916, 2906, 2917, + 2906, 2907, 2917, 2917, 2907, 2918, + 2907, 2908, 2918, 2918, 2908, 2919, + 2908, 2909, 2919, 2919, 2909, 2920, + 2909, 2910, 2920, 2920, 2910, 2921, + 2910, 2911, 2921, 2921, 2911, 2922, + 2911, 2912, 2922, 2922, 2912, 2923, + 2912, 2913, 2923, 2923, 2913, 2924, + 2913, 2914, 2924, 2924, 2914, 2925, + 2915, 2916, 2926, 2926, 2916, 2927, + 2916, 2917, 2927, 2927, 2917, 2928, + 2917, 2918, 2928, 2928, 2918, 2929, + 2918, 2919, 2929, 2929, 2919, 2930, + 2919, 2920, 2930, 2930, 2920, 2931, + 2920, 2921, 2931, 2931, 2921, 2932, + 2921, 2922, 2932, 2932, 2922, 2933, + 2922, 2923, 2933, 2933, 2923, 2934, + 2923, 2924, 2934, 2934, 2924, 2935, + 2924, 2925, 2935, 2935, 2925, 2936, + 2926, 2927, 2937, 2937, 2927, 2938, + 2927, 2928, 2938, 2938, 2928, 2939, + 2928, 2929, 2939, 2939, 2929, 2940, + 2929, 2930, 2940, 2940, 2930, 2941, + 2930, 2931, 2941, 2941, 2931, 2942, + 2931, 2932, 2942, 2942, 2932, 2943, + 2932, 2933, 2943, 2943, 2933, 2944, + 2933, 2934, 2944, 2944, 2934, 2945, + 2934, 2935, 2945, 2945, 2935, 2946, + 2935, 2936, 2946, 2946, 2936, 2947, + 2937, 2938, 2948, 2948, 2938, 2949, + 2938, 2939, 2949, 2949, 2939, 2950, + 2939, 2940, 2950, 2950, 2940, 2951, + 2940, 2941, 2951, 2951, 2941, 2952, + 2941, 2942, 2952, 2952, 2942, 2953, + 2942, 2943, 2953, 2953, 2943, 2954, + 2943, 2944, 2954, 2954, 2944, 2955, + 2944, 2945, 2955, 2955, 2945, 2956, + 2945, 2946, 2956, 2956, 2946, 2957, + 2946, 2947, 2957, 2957, 2947, 2958, + 2948, 2949, 2959, 2959, 2949, 2960, + 2949, 2950, 2960, 2960, 2950, 2961, + 2950, 2951, 2961, 2961, 2951, 2962, + 2951, 2952, 2962, 2962, 2952, 2963, + 2952, 2953, 2963, 2963, 2953, 2964, + 2953, 2954, 2964, 2964, 2954, 2965, + 2954, 2955, 2965, 2965, 2955, 2966, + 2955, 2956, 2966, 2966, 2956, 2967, + 2956, 2957, 2967, 2967, 2957, 2968, + 2957, 2958, 2968, 2968, 2958, 2969, + 2959, 2960, 2970, 2970, 2960, 2971, + 2960, 2961, 2971, 2971, 2961, 2972, + 2961, 2962, 2972, 2972, 2962, 2973, + 2962, 2963, 2973, 2973, 2963, 2974, + 2963, 2964, 2974, 2974, 2964, 2975, + 2964, 2965, 2975, 2975, 2965, 2976, + 2965, 2966, 2976, 2976, 2966, 2977, + 2966, 2967, 2977, 2977, 2967, 2978, + 2967, 2968, 2978, 2978, 2968, 2979, + 2968, 2969, 2979, 2979, 2969, 2980, + 2970, 2971, 2981, 2981, 2971, 2982, + 2971, 2972, 2982, 2982, 2972, 2983, + 2972, 2973, 2983, 2983, 2973, 2984, + 2973, 2974, 2984, 2984, 2974, 2985, + 2974, 2975, 2985, 2985, 2975, 2986, + 2975, 2976, 2986, 2986, 2976, 2987, + 2976, 2977, 2987, 2987, 2977, 2988, + 2977, 2978, 2988, 2988, 2978, 2989, + 2978, 2979, 2989, 2989, 2979, 2990, + 2979, 2980, 2990, 2990, 2980, 2991, + 2981, 2982, 2992, 2992, 2982, 2993, + 2982, 2983, 2993, 2993, 2983, 2994, + 2983, 2984, 2994, 2994, 2984, 2995, + 2984, 2985, 2995, 2995, 2985, 2996, + 2985, 2986, 2996, 2996, 2986, 2997, + 2986, 2987, 2997, 2997, 2987, 2998, + 2987, 2988, 2998, 2998, 2988, 2999, + 2988, 2989, 2999, 2999, 2989, 3000, + 2989, 2990, 3000, 3000, 2990, 3001, + 2990, 2991, 3001, 3001, 2991, 3002, + 2992, 2993, 3003, 3003, 2993, 3004, + 2993, 2994, 3004, 3004, 2994, 3005, + 2994, 2995, 3005, 3005, 2995, 3006, + 2995, 2996, 3006, 3006, 2996, 3007, + 2996, 2997, 3007, 3007, 2997, 3008, + 2997, 2998, 3008, 3008, 2998, 3009, + 2998, 2999, 3009, 3009, 2999, 3010, + 2999, 3000, 3010, 3010, 3000, 3011, + 3000, 3001, 3011, 3011, 3001, 3012, + 3001, 3002, 3012, 3012, 3002, 3013, + 3003, 3004, 3014, 3014, 3004, 3015, + 3004, 3005, 3015, 3015, 3005, 3016, + 3005, 3006, 3016, 3016, 3006, 3017, + 3006, 3007, 3017, 3017, 3007, 3018, + 3007, 3008, 3018, 3018, 3008, 3019, + 3008, 3009, 3019, 3019, 3009, 3020, + 3009, 3010, 3020, 3020, 3010, 3021, + 3010, 3011, 3021, 3021, 3011, 3022, + 3011, 3012, 3022, 3022, 3012, 3023, + 3012, 3013, 3023, 3023, 3013, 3024, + 3025, 3026, 3036, 3036, 3026, 3037, + 3026, 3027, 3037, 3037, 3027, 3038, + 3027, 3028, 3038, 3038, 3028, 3039, + 3028, 3029, 3039, 3039, 3029, 3040, + 3029, 3030, 3040, 3040, 3030, 3041, + 3030, 3031, 3041, 3041, 3031, 3042, + 3031, 3032, 3042, 3042, 3032, 3043, + 3032, 3033, 3043, 3043, 3033, 3044, + 3033, 3034, 3044, 3044, 3034, 3045, + 3034, 3035, 3045, 3045, 3035, 3046, + 3036, 3037, 3047, 3047, 3037, 3048, + 3037, 3038, 3048, 3048, 3038, 3049, + 3038, 3039, 3049, 3049, 3039, 3050, + 3039, 3040, 3050, 3050, 3040, 3051, + 3040, 3041, 3051, 3051, 3041, 3052, + 3041, 3042, 3052, 3052, 3042, 3053, + 3042, 3043, 3053, 3053, 3043, 3054, + 3043, 3044, 3054, 3054, 3044, 3055, + 3044, 3045, 3055, 3055, 3045, 3056, + 3045, 3046, 3056, 3056, 3046, 3057, + 3047, 3048, 3058, 3058, 3048, 3059, + 3048, 3049, 3059, 3059, 3049, 3060, + 3049, 3050, 3060, 3060, 3050, 3061, + 3050, 3051, 3061, 3061, 3051, 3062, + 3051, 3052, 3062, 3062, 3052, 3063, + 3052, 3053, 3063, 3063, 3053, 3064, + 3053, 3054, 3064, 3064, 3054, 3065, + 3054, 3055, 3065, 3065, 3055, 3066, + 3055, 3056, 3066, 3066, 3056, 3067, + 3056, 3057, 3067, 3067, 3057, 3068, + 3058, 3059, 3069, 3069, 3059, 3070, + 3059, 3060, 3070, 3070, 3060, 3071, + 3060, 3061, 3071, 3071, 3061, 3072, + 3061, 3062, 3072, 3072, 3062, 3073, + 3062, 3063, 3073, 3073, 3063, 3074, + 3063, 3064, 3074, 3074, 3064, 3075, + 3064, 3065, 3075, 3075, 3065, 3076, + 3065, 3066, 3076, 3076, 3066, 3077, + 3066, 3067, 3077, 3077, 3067, 3078, + 3067, 3068, 3078, 3078, 3068, 3079, + 3069, 3070, 3080, 3080, 3070, 3081, + 3070, 3071, 3081, 3081, 3071, 3082, + 3071, 3072, 3082, 3082, 3072, 3083, + 3072, 3073, 3083, 3083, 3073, 3084, + 3073, 3074, 3084, 3084, 3074, 3085, + 3074, 3075, 3085, 3085, 3075, 3086, + 3075, 3076, 3086, 3086, 3076, 3087, + 3076, 3077, 3087, 3087, 3077, 3088, + 3077, 3078, 3088, 3088, 3078, 3089, + 3078, 3079, 3089, 3089, 3079, 3090, + 3080, 3081, 3091, 3091, 3081, 3092, + 3081, 3082, 3092, 3092, 3082, 3093, + 3082, 3083, 3093, 3093, 3083, 3094, + 3083, 3084, 3094, 3094, 3084, 3095, + 3084, 3085, 3095, 3095, 3085, 3096, + 3085, 3086, 3096, 3096, 3086, 3097, + 3086, 3087, 3097, 3097, 3087, 3098, + 3087, 3088, 3098, 3098, 3088, 3099, + 3088, 3089, 3099, 3099, 3089, 3100, + 3089, 3090, 3100, 3100, 3090, 3101, + 3091, 3092, 3102, 3102, 3092, 3103, + 3092, 3093, 3103, 3103, 3093, 3104, + 3093, 3094, 3104, 3104, 3094, 3105, + 3094, 3095, 3105, 3105, 3095, 3106, + 3095, 3096, 3106, 3106, 3096, 3107, + 3096, 3097, 3107, 3107, 3097, 3108, + 3097, 3098, 3108, 3108, 3098, 3109, + 3098, 3099, 3109, 3109, 3099, 3110, + 3099, 3100, 3110, 3110, 3100, 3111, + 3100, 3101, 3111, 3111, 3101, 3112, + 3102, 3103, 3113, 3113, 3103, 3114, + 3103, 3104, 3114, 3114, 3104, 3115, + 3104, 3105, 3115, 3115, 3105, 3116, + 3105, 3106, 3116, 3116, 3106, 3117, + 3106, 3107, 3117, 3117, 3107, 3118, + 3107, 3108, 3118, 3118, 3108, 3119, + 3108, 3109, 3119, 3119, 3109, 3120, + 3109, 3110, 3120, 3120, 3110, 3121, + 3110, 3111, 3121, 3121, 3111, 3122, + 3111, 3112, 3122, 3122, 3112, 3123, + 3113, 3114, 3124, 3124, 3114, 3125, + 3114, 3115, 3125, 3125, 3115, 3126, + 3115, 3116, 3126, 3126, 3116, 3127, + 3116, 3117, 3127, 3127, 3117, 3128, + 3117, 3118, 3128, 3128, 3118, 3129, + 3118, 3119, 3129, 3129, 3119, 3130, + 3119, 3120, 3130, 3130, 3120, 3131, + 3120, 3121, 3131, 3131, 3121, 3132, + 3121, 3122, 3132, 3132, 3122, 3133, + 3122, 3123, 3133, 3133, 3123, 3134, + 3124, 3125, 3135, 3135, 3125, 3136, + 3125, 3126, 3136, 3136, 3126, 3137, + 3126, 3127, 3137, 3137, 3127, 3138, + 3127, 3128, 3138, 3138, 3128, 3139, + 3128, 3129, 3139, 3139, 3129, 3140, + 3129, 3130, 3140, 3140, 3130, 3141, + 3130, 3131, 3141, 3141, 3131, 3142, + 3131, 3132, 3142, 3142, 3132, 3143, + 3132, 3133, 3143, 3143, 3133, 3144, + 3133, 3134, 3144, 3144, 3134, 3145, + 3146, 3147, 3157, 3157, 3147, 3158, + 3147, 3148, 3158, 3158, 3148, 3159, + 3148, 3149, 3159, 3159, 3149, 3160, + 3149, 3150, 3160, 3160, 3150, 3161, + 3150, 3151, 3161, 3161, 3151, 3162, + 3151, 3152, 3162, 3162, 3152, 3163, + 3152, 3153, 3163, 3163, 3153, 3164, + 3153, 3154, 3164, 3164, 3154, 3165, + 3154, 3155, 3165, 3165, 3155, 3166, + 3155, 3156, 3166, 3166, 3156, 3167, + 3157, 3158, 3168, 3168, 3158, 3169, + 3158, 3159, 3169, 3169, 3159, 3170, + 3159, 3160, 3170, 3170, 3160, 3171, + 3160, 3161, 3171, 3171, 3161, 3172, + 3161, 3162, 3172, 3172, 3162, 3173, + 3162, 3163, 3173, 3173, 3163, 3174, + 3163, 3164, 3174, 3174, 3164, 3175, + 3164, 3165, 3175, 3175, 3165, 3176, + 3165, 3166, 3176, 3176, 3166, 3177, + 3166, 3167, 3177, 3177, 3167, 3178, + 3168, 3169, 3179, 3179, 3169, 3180, + 3169, 3170, 3180, 3180, 3170, 3181, + 3170, 3171, 3181, 3181, 3171, 3182, + 3171, 3172, 3182, 3182, 3172, 3183, + 3172, 3173, 3183, 3183, 3173, 3184, + 3173, 3174, 3184, 3184, 3174, 3185, + 3174, 3175, 3185, 3185, 3175, 3186, + 3175, 3176, 3186, 3186, 3176, 3187, + 3176, 3177, 3187, 3187, 3177, 3188, + 3177, 3178, 3188, 3188, 3178, 3189, + 3179, 3180, 3190, 3190, 3180, 3191, + 3180, 3181, 3191, 3191, 3181, 3192, + 3181, 3182, 3192, 3192, 3182, 3193, + 3182, 3183, 3193, 3193, 3183, 3194, + 3183, 3184, 3194, 3194, 3184, 3195, + 3184, 3185, 3195, 3195, 3185, 3196, + 3185, 3186, 3196, 3196, 3186, 3197, + 3186, 3187, 3197, 3197, 3187, 3198, + 3187, 3188, 3198, 3198, 3188, 3199, + 3188, 3189, 3199, 3199, 3189, 3200, + 3190, 3191, 3201, 3201, 3191, 3202, + 3191, 3192, 3202, 3202, 3192, 3203, + 3192, 3193, 3203, 3203, 3193, 3204, + 3193, 3194, 3204, 3204, 3194, 3205, + 3194, 3195, 3205, 3205, 3195, 3206, + 3195, 3196, 3206, 3206, 3196, 3207, + 3196, 3197, 3207, 3207, 3197, 3208, + 3197, 3198, 3208, 3208, 3198, 3209, + 3198, 3199, 3209, 3209, 3199, 3210, + 3199, 3200, 3210, 3210, 3200, 3211, + 3201, 3202, 3212, 3212, 3202, 3213, + 3202, 3203, 3213, 3213, 3203, 3214, + 3203, 3204, 3214, 3214, 3204, 3215, + 3204, 3205, 3215, 3215, 3205, 3216, + 3205, 3206, 3216, 3216, 3206, 3217, + 3206, 3207, 3217, 3217, 3207, 3218, + 3207, 3208, 3218, 3218, 3208, 3219, + 3208, 3209, 3219, 3219, 3209, 3220, + 3209, 3210, 3220, 3220, 3210, 3221, + 3210, 3211, 3221, 3221, 3211, 3222, + 3212, 3213, 3223, 3223, 3213, 3224, + 3213, 3214, 3224, 3224, 3214, 3225, + 3214, 3215, 3225, 3225, 3215, 3226, + 3215, 3216, 3226, 3226, 3216, 3227, + 3216, 3217, 3227, 3227, 3217, 3228, + 3217, 3218, 3228, 3228, 3218, 3229, + 3218, 3219, 3229, 3229, 3219, 3230, + 3219, 3220, 3230, 3230, 3220, 3231, + 3220, 3221, 3231, 3231, 3221, 3232, + 3221, 3222, 3232, 3232, 3222, 3233, + 3223, 3224, 3234, 3234, 3224, 3235, + 3224, 3225, 3235, 3235, 3225, 3236, + 3225, 3226, 3236, 3236, 3226, 3237, + 3226, 3227, 3237, 3237, 3227, 3238, + 3227, 3228, 3238, 3238, 3228, 3239, + 3228, 3229, 3239, 3239, 3229, 3240, + 3229, 3230, 3240, 3240, 3230, 3241, + 3230, 3231, 3241, 3241, 3231, 3242, + 3231, 3232, 3242, 3242, 3232, 3243, + 3232, 3233, 3243, 3243, 3233, 3244, + 3234, 3235, 3245, 3245, 3235, 3246, + 3235, 3236, 3246, 3246, 3236, 3247, + 3236, 3237, 3247, 3247, 3237, 3248, + 3237, 3238, 3248, 3248, 3238, 3249, + 3238, 3239, 3249, 3249, 3239, 3250, + 3239, 3240, 3250, 3250, 3240, 3251, + 3240, 3241, 3251, 3251, 3241, 3252, + 3241, 3242, 3252, 3252, 3242, 3253, + 3242, 3243, 3253, 3253, 3243, 3254, + 3243, 3244, 3254, 3254, 3244, 3255, + 3245, 3246, 3256, 3256, 3246, 3257, + 3246, 3247, 3257, 3257, 3247, 3258, + 3247, 3248, 3258, 3258, 3248, 3259, + 3248, 3249, 3259, 3259, 3249, 3260, + 3249, 3250, 3260, 3260, 3250, 3261, + 3250, 3251, 3261, 3261, 3251, 3262, + 3251, 3252, 3262, 3262, 3252, 3263, + 3252, 3253, 3263, 3263, 3253, 3264, + 3253, 3254, 3264, 3264, 3254, 3265, + 3254, 3255, 3265, 3265, 3255, 3266, + 3267, 3268, 3278, 3278, 3268, 3279, + 3268, 3269, 3279, 3279, 3269, 3280, + 3269, 3270, 3280, 3280, 3270, 3281, + 3270, 3271, 3281, 3281, 3271, 3282, + 3271, 3272, 3282, 3282, 3272, 3283, + 3272, 3273, 3283, 3283, 3273, 3284, + 3273, 3274, 3284, 3284, 3274, 3285, + 3274, 3275, 3285, 3285, 3275, 3286, + 3275, 3276, 3286, 3286, 3276, 3287, + 3276, 3277, 3287, 3287, 3277, 3288, + 3278, 3279, 3289, 3289, 3279, 3290, + 3279, 3280, 3290, 3290, 3280, 3291, + 3280, 3281, 3291, 3291, 3281, 3292, + 3281, 3282, 3292, 3292, 3282, 3293, + 3282, 3283, 3293, 3293, 3283, 3294, + 3283, 3284, 3294, 3294, 3284, 3295, + 3284, 3285, 3295, 3295, 3285, 3296, + 3285, 3286, 3296, 3296, 3286, 3297, + 3286, 3287, 3297, 3297, 3287, 3298, + 3287, 3288, 3298, 3298, 3288, 3299, + 3289, 3290, 3300, 3300, 3290, 3301, + 3290, 3291, 3301, 3301, 3291, 3302, + 3291, 3292, 3302, 3302, 3292, 3303, + 3292, 3293, 3303, 3303, 3293, 3304, + 3293, 3294, 3304, 3304, 3294, 3305, + 3294, 3295, 3305, 3305, 3295, 3306, + 3295, 3296, 3306, 3306, 3296, 3307, + 3296, 3297, 3307, 3307, 3297, 3308, + 3297, 3298, 3308, 3308, 3298, 3309, + 3298, 3299, 3309, 3309, 3299, 3310, + 3300, 3301, 3311, 3311, 3301, 3312, + 3301, 3302, 3312, 3312, 3302, 3313, + 3302, 3303, 3313, 3313, 3303, 3314, + 3303, 3304, 3314, 3314, 3304, 3315, + 3304, 3305, 3315, 3315, 3305, 3316, + 3305, 3306, 3316, 3316, 3306, 3317, + 3306, 3307, 3317, 3317, 3307, 3318, + 3307, 3308, 3318, 3318, 3308, 3319, + 3308, 3309, 3319, 3319, 3309, 3320, + 3309, 3310, 3320, 3320, 3310, 3321, + 3311, 3312, 3322, 3322, 3312, 3323, + 3312, 3313, 3323, 3323, 3313, 3324, + 3313, 3314, 3324, 3324, 3314, 3325, + 3314, 3315, 3325, 3325, 3315, 3326, + 3315, 3316, 3326, 3326, 3316, 3327, + 3316, 3317, 3327, 3327, 3317, 3328, + 3317, 3318, 3328, 3328, 3318, 3329, + 3318, 3319, 3329, 3329, 3319, 3330, + 3319, 3320, 3330, 3330, 3320, 3331, + 3320, 3321, 3331, 3331, 3321, 3332, + 3322, 3323, 3333, 3333, 3323, 3334, + 3323, 3324, 3334, 3334, 3324, 3335, + 3324, 3325, 3335, 3335, 3325, 3336, + 3325, 3326, 3336, 3336, 3326, 3337, + 3326, 3327, 3337, 3337, 3327, 3338, + 3327, 3328, 3338, 3338, 3328, 3339, + 3328, 3329, 3339, 3339, 3329, 3340, + 3329, 3330, 3340, 3340, 3330, 3341, + 3330, 3331, 3341, 3341, 3331, 3342, + 3331, 3332, 3342, 3342, 3332, 3343, + 3333, 3334, 3344, 3344, 3334, 3345, + 3334, 3335, 3345, 3345, 3335, 3346, + 3335, 3336, 3346, 3346, 3336, 3347, + 3336, 3337, 3347, 3347, 3337, 3348, + 3337, 3338, 3348, 3348, 3338, 3349, + 3338, 3339, 3349, 3349, 3339, 3350, + 3339, 3340, 3350, 3350, 3340, 3351, + 3340, 3341, 3351, 3351, 3341, 3352, + 3341, 3342, 3352, 3352, 3342, 3353, + 3342, 3343, 3353, 3353, 3343, 3354, + 3344, 3345, 3355, 3355, 3345, 3356, + 3345, 3346, 3356, 3356, 3346, 3357, + 3346, 3347, 3357, 3357, 3347, 3358, + 3347, 3348, 3358, 3358, 3348, 3359, + 3348, 3349, 3359, 3359, 3349, 3360, + 3349, 3350, 3360, 3360, 3350, 3361, + 3350, 3351, 3361, 3361, 3351, 3362, + 3351, 3352, 3362, 3362, 3352, 3363, + 3352, 3353, 3363, 3363, 3353, 3364, + 3353, 3354, 3364, 3364, 3354, 3365, + 3355, 3356, 3366, 3366, 3356, 3367, + 3356, 3357, 3367, 3367, 3357, 3368, + 3357, 3358, 3368, 3368, 3358, 3369, + 3358, 3359, 3369, 3369, 3359, 3370, + 3359, 3360, 3370, 3370, 3360, 3371, + 3360, 3361, 3371, 3371, 3361, 3372, + 3361, 3362, 3372, 3372, 3362, 3373, + 3362, 3363, 3373, 3373, 3363, 3374, + 3363, 3364, 3374, 3374, 3364, 3375, + 3364, 3365, 3375, 3375, 3365, 3376, + 3366, 3367, 3377, 3377, 3367, 3378, + 3367, 3368, 3378, 3378, 3368, 3379, + 3368, 3369, 3379, 3379, 3369, 3380, + 3369, 3370, 3380, 3380, 3370, 3381, + 3370, 3371, 3381, 3381, 3371, 3382, + 3371, 3372, 3382, 3382, 3372, 3383, + 3372, 3373, 3383, 3383, 3373, 3384, + 3373, 3374, 3384, 3384, 3374, 3385, + 3374, 3375, 3385, 3385, 3375, 3386, + 3375, 3376, 3386, 3386, 3376, 3387, + 3388, 3389, 3399, 3399, 3389, 3400, + 3389, 3390, 3400, 3400, 3390, 3401, + 3390, 3391, 3401, 3401, 3391, 3402, + 3391, 3392, 3402, 3402, 3392, 3403, + 3392, 3393, 3403, 3403, 3393, 3404, + 3393, 3394, 3404, 3404, 3394, 3405, + 3394, 3395, 3405, 3405, 3395, 3406, + 3395, 3396, 3406, 3406, 3396, 3407, + 3396, 3397, 3407, 3407, 3397, 3408, + 3397, 3398, 3408, 3408, 3398, 3409, + 3399, 3400, 3410, 3410, 3400, 3411, + 3400, 3401, 3411, 3411, 3401, 3412, + 3401, 3402, 3412, 3412, 3402, 3413, + 3402, 3403, 3413, 3413, 3403, 3414, + 3403, 3404, 3414, 3414, 3404, 3415, + 3404, 3405, 3415, 3415, 3405, 3416, + 3405, 3406, 3416, 3416, 3406, 3417, + 3406, 3407, 3417, 3417, 3407, 3418, + 3407, 3408, 3418, 3418, 3408, 3419, + 3408, 3409, 3419, 3419, 3409, 3420, + 3410, 3411, 3421, 3421, 3411, 3422, + 3411, 3412, 3422, 3422, 3412, 3423, + 3412, 3413, 3423, 3423, 3413, 3424, + 3413, 3414, 3424, 3424, 3414, 3425, + 3414, 3415, 3425, 3425, 3415, 3426, + 3415, 3416, 3426, 3426, 3416, 3427, + 3416, 3417, 3427, 3427, 3417, 3428, + 3417, 3418, 3428, 3428, 3418, 3429, + 3418, 3419, 3429, 3429, 3419, 3430, + 3419, 3420, 3430, 3430, 3420, 3431, + 3421, 3422, 3432, 3432, 3422, 3433, + 3422, 3423, 3433, 3433, 3423, 3434, + 3423, 3424, 3434, 3434, 3424, 3435, + 3424, 3425, 3435, 3435, 3425, 3436, + 3425, 3426, 3436, 3436, 3426, 3437, + 3426, 3427, 3437, 3437, 3427, 3438, + 3427, 3428, 3438, 3438, 3428, 3439, + 3428, 3429, 3439, 3439, 3429, 3440, + 3429, 3430, 3440, 3440, 3430, 3441, + 3430, 3431, 3441, 3441, 3431, 3442, + 3432, 3433, 3443, 3443, 3433, 3444, + 3433, 3434, 3444, 3444, 3434, 3445, + 3434, 3435, 3445, 3445, 3435, 3446, + 3435, 3436, 3446, 3446, 3436, 3447, + 3436, 3437, 3447, 3447, 3437, 3448, + 3437, 3438, 3448, 3448, 3438, 3449, + 3438, 3439, 3449, 3449, 3439, 3450, + 3439, 3440, 3450, 3450, 3440, 3451, + 3440, 3441, 3451, 3451, 3441, 3452, + 3441, 3442, 3452, 3452, 3442, 3453, + 3443, 3444, 3454, 3454, 3444, 3455, + 3444, 3445, 3455, 3455, 3445, 3456, + 3445, 3446, 3456, 3456, 3446, 3457, + 3446, 3447, 3457, 3457, 3447, 3458, + 3447, 3448, 3458, 3458, 3448, 3459, + 3448, 3449, 3459, 3459, 3449, 3460, + 3449, 3450, 3460, 3460, 3450, 3461, + 3450, 3451, 3461, 3461, 3451, 3462, + 3451, 3452, 3462, 3462, 3452, 3463, + 3452, 3453, 3463, 3463, 3453, 3464, + 3454, 3455, 3465, 3465, 3455, 3466, + 3455, 3456, 3466, 3466, 3456, 3467, + 3456, 3457, 3467, 3467, 3457, 3468, + 3457, 3458, 3468, 3468, 3458, 3469, + 3458, 3459, 3469, 3469, 3459, 3470, + 3459, 3460, 3470, 3470, 3460, 3471, + 3460, 3461, 3471, 3471, 3461, 3472, + 3461, 3462, 3472, 3472, 3462, 3473, + 3462, 3463, 3473, 3473, 3463, 3474, + 3463, 3464, 3474, 3474, 3464, 3475, + 3465, 3466, 3476, 3476, 3466, 3477, + 3466, 3467, 3477, 3477, 3467, 3478, + 3467, 3468, 3478, 3478, 3468, 3479, + 3468, 3469, 3479, 3479, 3469, 3480, + 3469, 3470, 3480, 3480, 3470, 3481, + 3470, 3471, 3481, 3481, 3471, 3482, + 3471, 3472, 3482, 3482, 3472, 3483, + 3472, 3473, 3483, 3483, 3473, 3484, + 3473, 3474, 3484, 3484, 3474, 3485, + 3474, 3475, 3485, 3485, 3475, 3486, + 3476, 3477, 3487, 3487, 3477, 3488, + 3477, 3478, 3488, 3488, 3478, 3489, + 3478, 3479, 3489, 3489, 3479, 3490, + 3479, 3480, 3490, 3490, 3480, 3491, + 3480, 3481, 3491, 3491, 3481, 3492, + 3481, 3482, 3492, 3492, 3482, 3493, + 3482, 3483, 3493, 3493, 3483, 3494, + 3483, 3484, 3494, 3494, 3484, 3495, + 3484, 3485, 3495, 3495, 3485, 3496, + 3485, 3486, 3496, 3496, 3486, 3497, + 3487, 3488, 3498, 3498, 3488, 3499, + 3488, 3489, 3499, 3499, 3489, 3500, + 3489, 3490, 3500, 3500, 3490, 3501, + 3490, 3491, 3501, 3501, 3491, 3502, + 3491, 3492, 3502, 3502, 3492, 3503, + 3492, 3493, 3503, 3503, 3493, 3504, + 3493, 3494, 3504, 3504, 3494, 3505, + 3494, 3495, 3505, 3505, 3495, 3506, + 3495, 3496, 3506, 3506, 3496, 3507, + 3496, 3497, 3507, 3507, 3497, 3508, + 3509, 3510, 3520, 3520, 3510, 3521, + 3510, 3511, 3521, 3521, 3511, 3522, + 3511, 3512, 3522, 3522, 3512, 3523, + 3512, 3513, 3523, 3523, 3513, 3524, + 3513, 3514, 3524, 3524, 3514, 3525, + 3514, 3515, 3525, 3525, 3515, 3526, + 3515, 3516, 3526, 3526, 3516, 3527, + 3516, 3517, 3527, 3527, 3517, 3528, + 3517, 3518, 3528, 3528, 3518, 3529, + 3518, 3519, 3529, 3529, 3519, 3530, + 3520, 3521, 3531, 3531, 3521, 3532, + 3521, 3522, 3532, 3532, 3522, 3533, + 3522, 3523, 3533, 3533, 3523, 3534, + 3523, 3524, 3534, 3534, 3524, 3535, + 3524, 3525, 3535, 3535, 3525, 3536, + 3525, 3526, 3536, 3536, 3526, 3537, + 3526, 3527, 3537, 3537, 3527, 3538, + 3527, 3528, 3538, 3538, 3528, 3539, + 3528, 3529, 3539, 3539, 3529, 3540, + 3529, 3530, 3540, 3540, 3530, 3541, + 3531, 3532, 3542, 3542, 3532, 3543, + 3532, 3533, 3543, 3543, 3533, 3544, + 3533, 3534, 3544, 3544, 3534, 3545, + 3534, 3535, 3545, 3545, 3535, 3546, + 3535, 3536, 3546, 3546, 3536, 3547, + 3536, 3537, 3547, 3547, 3537, 3548, + 3537, 3538, 3548, 3548, 3538, 3549, + 3538, 3539, 3549, 3549, 3539, 3550, + 3539, 3540, 3550, 3550, 3540, 3551, + 3540, 3541, 3551, 3551, 3541, 3552, + 3542, 3543, 3553, 3553, 3543, 3554, + 3543, 3544, 3554, 3554, 3544, 3555, + 3544, 3545, 3555, 3555, 3545, 3556, + 3545, 3546, 3556, 3556, 3546, 3557, + 3546, 3547, 3557, 3557, 3547, 3558, + 3547, 3548, 3558, 3558, 3548, 3559, + 3548, 3549, 3559, 3559, 3549, 3560, + 3549, 3550, 3560, 3560, 3550, 3561, + 3550, 3551, 3561, 3561, 3551, 3562, + 3551, 3552, 3562, 3562, 3552, 3563, + 3553, 3554, 3564, 3564, 3554, 3565, + 3554, 3555, 3565, 3565, 3555, 3566, + 3555, 3556, 3566, 3566, 3556, 3567, + 3556, 3557, 3567, 3567, 3557, 3568, + 3557, 3558, 3568, 3568, 3558, 3569, + 3558, 3559, 3569, 3569, 3559, 3570, + 3559, 3560, 3570, 3570, 3560, 3571, + 3560, 3561, 3571, 3571, 3561, 3572, + 3561, 3562, 3572, 3572, 3562, 3573, + 3562, 3563, 3573, 3573, 3563, 3574, + 3564, 3565, 3575, 3575, 3565, 3576, + 3565, 3566, 3576, 3576, 3566, 3577, + 3566, 3567, 3577, 3577, 3567, 3578, + 3567, 3568, 3578, 3578, 3568, 3579, + 3568, 3569, 3579, 3579, 3569, 3580, + 3569, 3570, 3580, 3580, 3570, 3581, + 3570, 3571, 3581, 3581, 3571, 3582, + 3571, 3572, 3582, 3582, 3572, 3583, + 3572, 3573, 3583, 3583, 3573, 3584, + 3573, 3574, 3584, 3584, 3574, 3585, + 3575, 3576, 3586, 3586, 3576, 3587, + 3576, 3577, 3587, 3587, 3577, 3588, + 3577, 3578, 3588, 3588, 3578, 3589, + 3578, 3579, 3589, 3589, 3579, 3590, + 3579, 3580, 3590, 3590, 3580, 3591, + 3580, 3581, 3591, 3591, 3581, 3592, + 3581, 3582, 3592, 3592, 3582, 3593, + 3582, 3583, 3593, 3593, 3583, 3594, + 3583, 3584, 3594, 3594, 3584, 3595, + 3584, 3585, 3595, 3595, 3585, 3596, + 3586, 3587, 3597, 3597, 3587, 3598, + 3587, 3588, 3598, 3598, 3588, 3599, + 3588, 3589, 3599, 3599, 3589, 3600, + 3589, 3590, 3600, 3600, 3590, 3601, + 3590, 3591, 3601, 3601, 3591, 3602, + 3591, 3592, 3602, 3602, 3592, 3603, + 3592, 3593, 3603, 3603, 3593, 3604, + 3593, 3594, 3604, 3604, 3594, 3605, + 3594, 3595, 3605, 3605, 3595, 3606, + 3595, 3596, 3606, 3606, 3596, 3607, + 3597, 3598, 3608, 3608, 3598, 3609, + 3598, 3599, 3609, 3609, 3599, 3610, + 3599, 3600, 3610, 3610, 3600, 3611, + 3600, 3601, 3611, 3611, 3601, 3612, + 3601, 3602, 3612, 3612, 3602, 3613, + 3602, 3603, 3613, 3613, 3603, 3614, + 3603, 3604, 3614, 3614, 3604, 3615, + 3604, 3605, 3615, 3615, 3605, 3616, + 3605, 3606, 3616, 3616, 3606, 3617, + 3606, 3607, 3617, 3617, 3607, 3618, + 3608, 3609, 3619, 3619, 3609, 3620, + 3609, 3610, 3620, 3620, 3610, 3621, + 3610, 3611, 3621, 3621, 3611, 3622, + 3611, 3612, 3622, 3622, 3612, 3623, + 3612, 3613, 3623, 3623, 3613, 3624, + 3613, 3614, 3624, 3624, 3614, 3625, + 3614, 3615, 3625, 3625, 3615, 3626, + 3615, 3616, 3626, 3626, 3616, 3627, + 3616, 3617, 3627, 3627, 3617, 3628, + 3617, 3618, 3628, 3628, 3618, 3629, + 3630, 3631, 3641, 3641, 3631, 3642, + 3631, 3632, 3642, 3642, 3632, 3643, + 3632, 3633, 3643, 3643, 3633, 3644, + 3633, 3634, 3644, 3644, 3634, 3645, + 3634, 3635, 3645, 3645, 3635, 3646, + 3635, 3636, 3646, 3646, 3636, 3647, + 3636, 3637, 3647, 3647, 3637, 3648, + 3637, 3638, 3648, 3648, 3638, 3649, + 3638, 3639, 3649, 3649, 3639, 3650, + 3639, 3640, 3650, 3650, 3640, 3651, + 3641, 3642, 3652, 3652, 3642, 3653, + 3642, 3643, 3653, 3653, 3643, 3654, + 3643, 3644, 3654, 3654, 3644, 3655, + 3644, 3645, 3655, 3655, 3645, 3656, + 3645, 3646, 3656, 3656, 3646, 3657, + 3646, 3647, 3657, 3657, 3647, 3658, + 3647, 3648, 3658, 3658, 3648, 3659, + 3648, 3649, 3659, 3659, 3649, 3660, + 3649, 3650, 3660, 3660, 3650, 3661, + 3650, 3651, 3661, 3661, 3651, 3662, + 3652, 3653, 3663, 3663, 3653, 3664, + 3653, 3654, 3664, 3664, 3654, 3665, + 3654, 3655, 3665, 3665, 3655, 3666, + 3655, 3656, 3666, 3666, 3656, 3667, + 3656, 3657, 3667, 3667, 3657, 3668, + 3657, 3658, 3668, 3668, 3658, 3669, + 3658, 3659, 3669, 3669, 3659, 3670, + 3659, 3660, 3670, 3670, 3660, 3671, + 3660, 3661, 3671, 3671, 3661, 3672, + 3661, 3662, 3672, 3672, 3662, 3673, + 3663, 3664, 3674, 3674, 3664, 3675, + 3664, 3665, 3675, 3675, 3665, 3676, + 3665, 3666, 3676, 3676, 3666, 3677, + 3666, 3667, 3677, 3677, 3667, 3678, + 3667, 3668, 3678, 3678, 3668, 3679, + 3668, 3669, 3679, 3679, 3669, 3680, + 3669, 3670, 3680, 3680, 3670, 3681, + 3670, 3671, 3681, 3681, 3671, 3682, + 3671, 3672, 3682, 3682, 3672, 3683, + 3672, 3673, 3683, 3683, 3673, 3684, + 3674, 3675, 3685, 3685, 3675, 3686, + 3675, 3676, 3686, 3686, 3676, 3687, + 3676, 3677, 3687, 3687, 3677, 3688, + 3677, 3678, 3688, 3688, 3678, 3689, + 3678, 3679, 3689, 3689, 3679, 3690, + 3679, 3680, 3690, 3690, 3680, 3691, + 3680, 3681, 3691, 3691, 3681, 3692, + 3681, 3682, 3692, 3692, 3682, 3693, + 3682, 3683, 3693, 3693, 3683, 3694, + 3683, 3684, 3694, 3694, 3684, 3695, + 3685, 3686, 3696, 3696, 3686, 3697, + 3686, 3687, 3697, 3697, 3687, 3698, + 3687, 3688, 3698, 3698, 3688, 3699, + 3688, 3689, 3699, 3699, 3689, 3700, + 3689, 3690, 3700, 3700, 3690, 3701, + 3690, 3691, 3701, 3701, 3691, 3702, + 3691, 3692, 3702, 3702, 3692, 3703, + 3692, 3693, 3703, 3703, 3693, 3704, + 3693, 3694, 3704, 3704, 3694, 3705, + 3694, 3695, 3705, 3705, 3695, 3706, + 3696, 3697, 3707, 3707, 3697, 3708, + 3697, 3698, 3708, 3708, 3698, 3709, + 3698, 3699, 3709, 3709, 3699, 3710, + 3699, 3700, 3710, 3710, 3700, 3711, + 3700, 3701, 3711, 3711, 3701, 3712, + 3701, 3702, 3712, 3712, 3702, 3713, + 3702, 3703, 3713, 3713, 3703, 3714, + 3703, 3704, 3714, 3714, 3704, 3715, + 3704, 3705, 3715, 3715, 3705, 3716, + 3705, 3706, 3716, 3716, 3706, 3717, + 3707, 3708, 3718, 3718, 3708, 3719, + 3708, 3709, 3719, 3719, 3709, 3720, + 3709, 3710, 3720, 3720, 3710, 3721, + 3710, 3711, 3721, 3721, 3711, 3722, + 3711, 3712, 3722, 3722, 3712, 3723, + 3712, 3713, 3723, 3723, 3713, 3724, + 3713, 3714, 3724, 3724, 3714, 3725, + 3714, 3715, 3725, 3725, 3715, 3726, + 3715, 3716, 3726, 3726, 3716, 3727, + 3716, 3717, 3727, 3727, 3717, 3728, + 3718, 3719, 3729, 3729, 3719, 3730, + 3719, 3720, 3730, 3730, 3720, 3731, + 3720, 3721, 3731, 3731, 3721, 3732, + 3721, 3722, 3732, 3732, 3722, 3733, + 3722, 3723, 3733, 3733, 3723, 3734, + 3723, 3724, 3734, 3734, 3724, 3735, + 3724, 3725, 3735, 3735, 3725, 3736, + 3725, 3726, 3736, 3736, 3726, 3737, + 3726, 3727, 3737, 3737, 3727, 3738, + 3727, 3728, 3738, 3738, 3728, 3739, + 3729, 3730, 3740, 3740, 3730, 3741, + 3730, 3731, 3741, 3741, 3731, 3742, + 3731, 3732, 3742, 3742, 3732, 3743, + 3732, 3733, 3743, 3743, 3733, 3744, + 3733, 3734, 3744, 3744, 3734, 3745, + 3734, 3735, 3745, 3745, 3735, 3746, + 3735, 3736, 3746, 3746, 3736, 3747, + 3736, 3737, 3747, 3747, 3737, 3748, + 3737, 3738, 3748, 3748, 3738, 3749, + 3738, 3739, 3749, 3749, 3739, 3750, + 3751, 3752, 3762, 3762, 3752, 3763, + 3752, 3753, 3763, 3763, 3753, 3764, + 3753, 3754, 3764, 3764, 3754, 3765, + 3754, 3755, 3765, 3765, 3755, 3766, + 3755, 3756, 3766, 3766, 3756, 3767, + 3756, 3757, 3767, 3767, 3757, 3768, + 3757, 3758, 3768, 3768, 3758, 3769, + 3758, 3759, 3769, 3769, 3759, 3770, + 3759, 3760, 3770, 3770, 3760, 3771, + 3760, 3761, 3771, 3771, 3761, 3772, + 3762, 3763, 3773, 3773, 3763, 3774, + 3763, 3764, 3774, 3774, 3764, 3775, + 3764, 3765, 3775, 3775, 3765, 3776, + 3765, 3766, 3776, 3776, 3766, 3777, + 3766, 3767, 3777, 3777, 3767, 3778, + 3767, 3768, 3778, 3778, 3768, 3779, + 3768, 3769, 3779, 3779, 3769, 3780, + 3769, 3770, 3780, 3780, 3770, 3781, + 3770, 3771, 3781, 3781, 3771, 3782, + 3771, 3772, 3782, 3782, 3772, 3783, + 3773, 3774, 3784, 3784, 3774, 3785, + 3774, 3775, 3785, 3785, 3775, 3786, + 3775, 3776, 3786, 3786, 3776, 3787, + 3776, 3777, 3787, 3787, 3777, 3788, + 3777, 3778, 3788, 3788, 3778, 3789, + 3778, 3779, 3789, 3789, 3779, 3790, + 3779, 3780, 3790, 3790, 3780, 3791, + 3780, 3781, 3791, 3791, 3781, 3792, + 3781, 3782, 3792, 3792, 3782, 3793, + 3782, 3783, 3793, 3793, 3783, 3794, + 3784, 3785, 3795, 3795, 3785, 3796, + 3785, 3786, 3796, 3796, 3786, 3797, + 3786, 3787, 3797, 3797, 3787, 3798, + 3787, 3788, 3798, 3798, 3788, 3799, + 3788, 3789, 3799, 3799, 3789, 3800, + 3789, 3790, 3800, 3800, 3790, 3801, + 3790, 3791, 3801, 3801, 3791, 3802, + 3791, 3792, 3802, 3802, 3792, 3803, + 3792, 3793, 3803, 3803, 3793, 3804, + 3793, 3794, 3804, 3804, 3794, 3805, + 3795, 3796, 3806, 3806, 3796, 3807, + 3796, 3797, 3807, 3807, 3797, 3808, + 3797, 3798, 3808, 3808, 3798, 3809, + 3798, 3799, 3809, 3809, 3799, 3810, + 3799, 3800, 3810, 3810, 3800, 3811, + 3800, 3801, 3811, 3811, 3801, 3812, + 3801, 3802, 3812, 3812, 3802, 3813, + 3802, 3803, 3813, 3813, 3803, 3814, + 3803, 3804, 3814, 3814, 3804, 3815, + 3804, 3805, 3815, 3815, 3805, 3816, + 3806, 3807, 3817, 3817, 3807, 3818, + 3807, 3808, 3818, 3818, 3808, 3819, + 3808, 3809, 3819, 3819, 3809, 3820, + 3809, 3810, 3820, 3820, 3810, 3821, + 3810, 3811, 3821, 3821, 3811, 3822, + 3811, 3812, 3822, 3822, 3812, 3823, + 3812, 3813, 3823, 3823, 3813, 3824, + 3813, 3814, 3824, 3824, 3814, 3825, + 3814, 3815, 3825, 3825, 3815, 3826, + 3815, 3816, 3826, 3826, 3816, 3827, + 3817, 3818, 3828, 3828, 3818, 3829, + 3818, 3819, 3829, 3829, 3819, 3830, + 3819, 3820, 3830, 3830, 3820, 3831, + 3820, 3821, 3831, 3831, 3821, 3832, + 3821, 3822, 3832, 3832, 3822, 3833, + 3822, 3823, 3833, 3833, 3823, 3834, + 3823, 3824, 3834, 3834, 3824, 3835, + 3824, 3825, 3835, 3835, 3825, 3836, + 3825, 3826, 3836, 3836, 3826, 3837, + 3826, 3827, 3837, 3837, 3827, 3838, + 3828, 3829, 3839, 3839, 3829, 3840, + 3829, 3830, 3840, 3840, 3830, 3841, + 3830, 3831, 3841, 3841, 3831, 3842, + 3831, 3832, 3842, 3842, 3832, 3843, + 3832, 3833, 3843, 3843, 3833, 3844, + 3833, 3834, 3844, 3844, 3834, 3845, + 3834, 3835, 3845, 3845, 3835, 3846, + 3835, 3836, 3846, 3846, 3836, 3847, + 3836, 3837, 3847, 3847, 3837, 3848, + 3837, 3838, 3848, 3848, 3838, 3849, + 3839, 3840, 3850, 3850, 3840, 3851, + 3840, 3841, 3851, 3851, 3841, 3852, + 3841, 3842, 3852, 3852, 3842, 3853, + 3842, 3843, 3853, 3853, 3843, 3854, + 3843, 3844, 3854, 3854, 3844, 3855, + 3844, 3845, 3855, 3855, 3845, 3856, + 3845, 3846, 3856, 3856, 3846, 3857, + 3846, 3847, 3857, 3857, 3847, 3858, + 3847, 3848, 3858, 3858, 3848, 3859, + 3848, 3849, 3859, 3859, 3849, 3860, + 3850, 3851, 3861, 3861, 3851, 3862, + 3851, 3852, 3862, 3862, 3852, 3863, + 3852, 3853, 3863, 3863, 3853, 3864, + 3853, 3854, 3864, 3864, 3854, 3865, + 3854, 3855, 3865, 3865, 3855, 3866, + 3855, 3856, 3866, 3866, 3856, 3867, + 3856, 3857, 3867, 3867, 3857, 3868, + 3857, 3858, 3868, 3868, 3858, 3869, + 3858, 3859, 3869, 3869, 3859, 3870, + 3859, 3860, 3870, 3870, 3860, 3871, + }; + +}; diff --git a/projects/saf_r/.gitignore b/projects/saf_r/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ff3dff30031efafa24269a9ac0ef93f64f63ded1 --- /dev/null +++ b/projects/saf_r/.gitignore @@ -0,0 +1 @@ +saf_r \ No newline at end of file diff --git a/projects/saf_r/CMakeLists.txt b/projects/saf_r/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..61ede8ae5a5cedac78ff5781aec20973854a3df7 --- /dev/null +++ b/projects/saf_r/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.16) +project(saf_r) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(saf_r + src/main.cpp + "src/safrScene.hpp" + ) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(saf_r PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(saf_r PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(saf_r PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(saf_r SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(saf_r vkcv vkcv_testing vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_shader_compiler) diff --git a/projects/saf_r/shaders/raytracing.comp b/projects/saf_r/shaders/raytracing.comp new file mode 100644 index 0000000000000000000000000000000000000000..a7c6b92a646e5c2f753946f74fe7ab78aea44fe6 --- /dev/null +++ b/projects/saf_r/shaders/raytracing.comp @@ -0,0 +1,292 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +// defines constants +const float pi = 3.1415926535897932384626433832795; +const float hitBias = 0.01; // used to offset hits to avoid self intersection + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +//structs of materials, lights, spheres and intersection for use in compute shader +struct Material { + vec3 albedo; + vec3 diffuseColor; + float specularExponent; + float refractiveIndex; +}; + +struct Light{ + vec3 position; + float intensity; +}; + +struct Sphere{ + vec3 center; + float radius; + Material material; +}; + +struct Intersection{ + bool hit; + vec3 pos; + vec3 N; + Material material; +}; + + +//incoming light data +layout(std430, binding = 0) coherent buffer lights{ + Light inLights[]; +}; + +// incoming sphere data +layout(std430, binding = 1) coherent buffer spheres{ + Sphere inSpheres[]; +}; + +// output store image as swapchain input +layout(set=0, binding = 2, rgba8) uniform image2D outImage; + +// incoming constants, because size of dynamic arrays cannot be computed on gpu +layout( push_constant ) uniform constants{ + mat4 viewToWorld; + int lightCount; + int sphereCount; +}; + +/* +* safrReflect computes the new reflected or refracted ray depending on the material +* @param vec3: raydirection vector +* @param vec3: normalvector on which should be reflected or refracted +* @param float: degree of refraction. In case of simple reflection it is 1.0 +* @return vec3: new ray that is the result of the reflection or refraction +*/ +vec3 safrReflect(vec3 V, vec3 N, float refractIndex){ + if(refractIndex != 1.0){ + // Snell's law + float cosi = - max(-1.f, min(1.f, dot(V,N))); + float etai = 1; + float etat = refractIndex; + vec3 n = N; + float swap; + if(cosi < 0){ + cosi = -cosi; + n = -N; + swap = etai; + etai = etat; + etat = swap; + } + float eta = etai / etat; + float k = 1 - eta * eta * (1 - cosi * cosi); + if(k < 0){ + return vec3(0,0,0); + } else { + return V * eta + n * (eta * cosi - sqrt(k)); + } + }else{ + return reflect(V, N); + } +} + +/* +* the rayIntersect function checks, if a ray from the raytracer passes through the sphere, hits the sphere or passes by the the sphere +* @param vec3: origin of ray +* @param vec3: direction of ray +* @param float: distance of the ray to the sphere (out because there are no references in shaders) +* @return bool: if ray interesects sphere or not (out because there are no references in shaders) +*/ + +bool rayIntersect(const vec3 origin, const vec3 dir, out float t0, const int id){ + vec3 L = inSpheres[id].center - origin; + float tca = dot(L, dir); + float d2 = dot(L, L) - tca * tca; + if (d2 > inSpheres[id].radius * inSpheres[id].radius){ + return false; + } + float thc = float(sqrt(inSpheres[id].radius * inSpheres[id].radius - d2)); + t0 = tca - thc; + float t1 = tca + thc; + if (t0 < 0) { + t0 = t1; + } + if (t0 < 0){ + return false; + } + return true; +} + +/* +* sceneIntersect iterates over whole scene (over every single object) to check for intersections +* @param vec3: Origin of the ray +* @param vec3: direction of the ray +* @return: Intersection struct with hit(bool) position, normal and material of sphere +*/ + +Intersection sceneIntersect(const vec3 rayOrigin, const vec3 rayDirection) { + //distance if spheres will be rendered + float min_d = 1.0 / 0.0; // lets start with something big + + Intersection intersection; + intersection.hit = false; + + //go over every sphere, check if sphere is hit by ray, save if hit is near enough into intersection struct + for (int i = 0; i < sphereCount; i++) { + float d; + if (rayIntersect(rayOrigin, rayDirection, d, i)) { + + intersection.hit = true; + + if(d < min_d){ + min_d = d; + intersection.pos = rayOrigin + rayDirection * d; + intersection.N = normalize(intersection.pos - inSpheres[i].center); + intersection.material = inSpheres[i].material; + } + } + } + + float checkerboard_dist = min_d; + if (abs(rayDirection.y)>1e-3) { + float d = -(rayOrigin.y + 4) / rayDirection.y; // the checkerboard plane has equation y = -4 + vec3 pt = rayOrigin + rayDirection * d; + if (d > 0 && abs(pt.x) < 10 && pt.z<-10 && pt.z>-30 && d < min_d) { + checkerboard_dist = d; + intersection.hit = true; + intersection.pos = pt; + intersection.N = vec3(0, 1, 0); + intersection.material = inSpheres[0].material; + } + } + return intersection; +} + +/* +* biasHitPosition computes the new hitposition with respect to the raydirection and a bias +* @param vec3: Hit Position +* @param vec3: direction of ray +* @param vec3: N(ormal) +* @return vec3: new Hit position depending on hitBias (used to offset hits to avoid self intersection) +*/ +vec3 biasHitPosition(vec3 hitPos, vec3 rayDirection, vec3 N){ + return hitPos + sign(dot(rayDirection, N)) * N * hitBias; +} + +/* +* computeHitLighting iterates over all lights to compute the color for every ray +* @param Intersection: struct with all the data of the intersection +* @param vec3: Raydirection +* @param float: material albedo of the intersection +* @return colour/shadows of sphere with illumination +*/ +vec3 computeHitLighting(Intersection intersection, vec3 V, out float outReflectionThroughput){ + + float lightIntensityDiffuse = 0; + float lightIntensitySpecular = 0; + + //iterate over every light source to compute sphere colours/shadows + for (int i = 0; i < lightCount; i++) { + + //compute normal + distance between light and intersection + vec3 L = normalize(inLights[i].position - intersection.pos); + float d = distance(inLights[i].position, intersection.pos); + + //compute shadows + vec3 shadowOrigin = biasHitPosition(intersection.pos, L, intersection.N); + Intersection shadowIntersection = sceneIntersect(shadowOrigin, L); + bool isShadowed = false; + if(shadowIntersection.hit){ + isShadowed = distance(shadowIntersection.pos, shadowOrigin) < d; + } + if(isShadowed){ + continue; + } + + lightIntensityDiffuse += inLights[i].intensity * max(0.f, dot(L, intersection.N)); + lightIntensitySpecular += pow(max(0.f, dot(safrReflect(V, intersection.N, intersection.material.refractiveIndex), L)), intersection.material.specularExponent) * inLights[i].intensity; + } + + outReflectionThroughput = intersection.material.albedo[2]; + return intersection.material.diffuseColor * lightIntensityDiffuse * intersection.material.albedo[0] + lightIntensitySpecular * intersection.material.albedo[1]; +} + +/* +* castRay throws a ray out of the initial origin with respect to the initial direction checks for intersection and refelction +* @param vec3: initial origin of ray +* @param vec3: initial direction of ray +* @param int: max depth o ray reflection +* @return s +*/ + +vec3 castRay(const vec3 initialOrigin, const vec3 initialDirection, int max_depth) { + + vec3 skyColor = vec3(0.2, 0.7, 0.8); + vec3 rayOrigin = initialOrigin; + vec3 rayDirection = initialDirection; + + float reflectionThroughput = 1; + vec3 color = vec3(0); + + //iterate to max depth of reflections + for(int i = 0; i < max_depth; i++){ + + Intersection intersection = sceneIntersect(rayOrigin, rayDirection); + + vec3 hitColor; + float hitReflectionThroughput; + + if(intersection.hit){ + hitColor = computeHitLighting(intersection, rayDirection, hitReflectionThroughput); + }else{ + hitColor = skyColor; + } + + color += hitColor * reflectionThroughput; + reflectionThroughput *= hitReflectionThroughput; + + //if there is no intersection of a ray with a sphere, break out of the loop + if(!intersection.hit){ + break; + } + + //compute new direction and origin of the reflected ray + rayDirection = normalize(safrReflect(rayDirection, intersection.N, intersection.material.refractiveIndex)); + rayOrigin = biasHitPosition(intersection.pos, rayDirection, intersection.N); + } + + return color; +} + +/* +* computeDirection transforms the pixel coords to worldspace coords +* @param ivec2: pixel coordinates +* @return vec3: world coordinates +*/ +vec3 computeDirection(ivec2 coord){ + + ivec2 outImageRes = imageSize(outImage); + float fovDegree = 45; + float fov = fovDegree * pi / 180; + + vec2 uv = coord / vec2(outImageRes); + vec2 ndc = 2 * uv - 1; + + float tanFovHalf = tan(fov / 2.f); + float aspectRatio = outImageRes.x / float(outImageRes.y); + float x = ndc.x * tanFovHalf * aspectRatio; + float y = -ndc.y * tanFovHalf; + + vec3 directionViewSpace = normalize(vec3(x, y, 1)); + vec3 directionWorldSpace = mat3(viewToWorld) * directionViewSpace; + return directionWorldSpace; +} + +// the main function +void main(){ + ivec2 coord = ivec2(gl_GlobalInvocationID.xy); + int max_depth = 4; + vec3 direction = computeDirection(coord); + vec3 cameraPos = viewToWorld[3].xyz; + vec3 color = castRay(cameraPos, direction, max_depth); + + imageStore(outImage, coord, vec4(color, 0.f)); +} \ No newline at end of file diff --git a/projects/saf_r/shaders/shader.frag b/projects/saf_r/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..64b45eb26b9831f6504e69882018e46120615615 --- /dev/null +++ b/projects/saf_r/shaders/shader.frag @@ -0,0 +1,13 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 texCoord; + +layout(location = 0) out vec3 outColor; + +layout(set=0, binding=1) uniform sampler textureSampler; + +void main() { + outColor = fragColor; +} \ No newline at end of file diff --git a/projects/saf_r/shaders/shader.vert b/projects/saf_r/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..b6419f5e348ddeca66d1c8b0eb0a4cf32e2e80c4 --- /dev/null +++ b/projects/saf_r/shaders/shader.vert @@ -0,0 +1,32 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 texCoord; + +layout( push_constant ) uniform constants{ + mat4 mvp; + mat4 proj; +}; + +void main() { + vec3 positions[3] = { + vec3(-1, -1, -1), + vec3( 3, -1, -1), + vec3(-1, 3, -1) + }; + + vec3 colors[3] = { + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1) + }; + + vec4 position = mvp * vec4(positions[gl_VertexIndex], 1.0); + gl_Position = position; + + texCoord.x = ((proj * vec4(positions[gl_VertexIndex], 1.0)).x + 1.0) * 0.5; + texCoord.y = ((proj * vec4(positions[gl_VertexIndex], 1.0)).y + 1.0) * 0.5; + + fragColor = colors[gl_VertexIndex]; +} \ No newline at end of file diff --git a/projects/saf_r/src/main.cpp b/projects/saf_r/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3fef073a00f8263cc08ce17f033170d0f4031dc4 --- /dev/null +++ b/projects/saf_r/src/main.cpp @@ -0,0 +1,297 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> +#include <chrono> +#include <limits> +#include <cmath> +#include <vector> +#include <string.h> // memcpy(3) +#include "safrScene.hpp" + + +void createQuadraticLightCluster(std::vector<safrScene::Light>& lights, int countPerDimension, float dimension, float height, float intensity) { + float distance = dimension/countPerDimension; + + for(int x = 0; x <= countPerDimension; x++) { + for (int z = 0; z <= countPerDimension; z++) { + lights.push_back(safrScene::Light(glm::vec3(x * distance, height, z * distance), + float (intensity/countPerDimension) / 10.f) // Divide by 10, because intensity is busting O.o + ); + } + } + +} + +int main(int argc, const char** argv) { + const char* applicationName = "SAF_R"; + + //window creation + const int windowWidth = 800; + const int windowHeight = 600; + + vkcv::Core core = vkcv::Core::create( + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, + { "VK_KHR_swapchain" } + ); + + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + + //configuring the compute Shader + vkcv::PassConfig computePassDefinition({}); + vkcv::PassHandle computePass = core.createPass(computePassDefinition); + + if (!computePass) + { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + std::string shaderPathCompute = "shaders/raytracing.comp"; + + //creating the shader programs + vkcv::ShaderProgram safrShaderProgram; + vkcv::shader::GLSLCompiler compiler; + vkcv::ShaderProgram computeShaderProgram{}; + + compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("shaders/shader.vert"), + [&safrShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + safrShaderProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("shaders/shader.frag"), + [&safrShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + safrShaderProgram.addShader(shaderStage, path); + }); + + compiler.compile(vkcv::ShaderStage::COMPUTE, shaderPathCompute, [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + computeShaderProgram.addShader(shaderStage, path); + }); + + //create DescriptorSets (...) for every Shader + const vkcv::DescriptorBindings& descriptorBindings = safrShaderProgram.getReflectedDescriptors().at(0); + vkcv::DescriptorSetLayoutHandle descriptorSetLayout = core.createDescriptorSetLayout(descriptorBindings); + vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorSetLayout); + vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + const vkcv::DescriptorBindings& computeDescriptorBindings = computeShaderProgram.getReflectedDescriptors().at(0); + + vkcv::DescriptorSetLayoutHandle computeDescriptorSetLayout = core.createDescriptorSetLayout(computeDescriptorBindings); + vkcv::DescriptorSetHandle computeDescriptorSet = core.createDescriptorSet(computeDescriptorSetLayout); + + const std::vector<vkcv::VertexAttachment> computeVertexAttachments = computeShaderProgram.getVertexAttachments(); + + std::vector<vkcv::VertexBinding> computeBindings; + for (size_t i = 0; i < computeVertexAttachments.size(); i++) { + computeBindings.push_back(vkcv::VertexBinding(i, { computeVertexAttachments[i] })); + } + const vkcv::VertexLayout computeLayout(computeBindings); + + /* + * create the scene + */ + + //materials for the spheres + std::vector<safrScene::Material> materials; + safrScene::Material ivory(glm::vec4(0.6, 0.3, 0.1, 0.0), glm::vec3(0.4, 0.4, 0.3), 50., 1.0); + safrScene::Material red_rubber(glm::vec4(0.9, 0.1, 0.0, 0.0), glm::vec3(0.3, 0.1, 0.1), 10., 1.0); + safrScene::Material mirror( glm::vec4(0.0, 10.0, 0.8, 0.0), glm::vec3(1.0, 1.0, 1.0), 1425., 1.0); + safrScene::Material glass( glm::vec4(0.0, 10.0, 0.8, 0.0), glm::vec3(1.0, 1.0, 1.0), 1425., 1.5); + + materials.push_back(ivory); + materials.push_back(red_rubber); + materials.push_back(mirror); + + //spheres for the scene + std::vector<safrScene::Sphere> spheres; + spheres.push_back(safrScene::Sphere(glm::vec3(-3, 0, -16), 2, ivory)); + // spheres.push_back(safrScene::Sphere(glm::vec3(-1.0, -1.5, 12), 2, mirror)); + spheres.push_back(safrScene::Sphere(glm::vec3(-1.0, -1.5, -12), 2, glass)); + spheres.push_back(safrScene::Sphere(glm::vec3( 1.5, -0.5, -18), 3, red_rubber)); + spheres.push_back(safrScene::Sphere(glm::vec3( 7, 5, -18), 4, mirror)); + + //lights for the scene + std::vector<safrScene::Light> lights; + /* + lights.push_back(safrScene::Light(glm::vec3(-20, 20, 20), 1.5)); + lights.push_back(safrScene::Light(glm::vec3(30, 50, -25), 1.8)); + lights.push_back(safrScene::Light(glm::vec3(30, 20, 30), 1.7)); + */ + createQuadraticLightCluster(lights, 10, 2.5f, 20, 1.5f); + + + vkcv::SamplerHandle sampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + + + //create Buffer for compute shader + vkcv::Buffer<safrScene::Light> lightsBuffer = core.createBuffer<safrScene::Light>( + vkcv::BufferType::STORAGE, + lights.size() + ); + lightsBuffer.fill(lights); + + vkcv::Buffer<safrScene::Sphere> sphereBuffer = core.createBuffer<safrScene::Sphere>( + vkcv::BufferType::STORAGE, + spheres.size() + ); + sphereBuffer.fill(spheres); + + vkcv::DescriptorWrites computeWrites; + computeWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0,lightsBuffer.getHandle()), + vkcv::BufferDescriptorWrite(1,sphereBuffer.getHandle())}; + core.writeDescriptorSet(computeDescriptorSet, computeWrites); + + + const auto& context = core.getContext(); + + auto safrIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, vkcv::BufferMemoryType::DEVICE_LOCAL); + uint16_t indices[3] = { 0, 1, 2 }; + safrIndexBuffer.fill(&indices[0], sizeof(indices)); + + // an example attachment for passes that output to the window + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchain(windowHandle).getFormat()); + + vkcv::PassConfig safrPassDefinition({ present_color_attachment }); + vkcv::PassHandle safrPass = core.createPass(safrPassDefinition); + + if (!safrPass) + { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + //create the render pipeline + compute pipeline + const vkcv::GraphicsPipelineConfig safrPipelineDefinition{ + safrShaderProgram, + (uint32_t)windowWidth, + (uint32_t)windowHeight, + safrPass, + {}, + { core.getDescriptorSetLayout(descriptorSetLayout).vulkanHandle }, + false + }; + + vkcv::GraphicsPipelineHandle safrPipeline = core.createGraphicsPipeline(safrPipelineDefinition); + + const vkcv::ComputePipelineConfig computePipelineConfig{ + computeShaderProgram, + {core.getDescriptorSetLayout(computeDescriptorSetLayout).vulkanHandle} + }; + + vkcv::ComputePipelineHandle computePipeline = core.createComputePipeline(computePipelineConfig); + + if (!safrPipeline || !computePipeline) + { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + auto start = std::chrono::system_clock::now(); + + const vkcv::Mesh renderMesh({}, safrIndexBuffer.getVulkanHandle(), 3); + vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle); + vkcv::DrawcallInfo drawcall(renderMesh, { descriptorUsage }, 1); + + //create the camera + vkcv::camera::CameraManager cameraManager(core.getWindow(windowHandle)); + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, 2)); + cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, 0.0f)); + cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, -1.0f)); + + float time = 0; + + while (vkcv::Window::hasOpenWindow()) + { + vkcv::Window::pollEvents(); + + uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem + if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { + continue; + } + + //configure timer + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + start = end; + + time += 0.000001f * static_cast<float>(deltatime.count()); + + //adjust light position + /* + 639a53157e7d3936caf7c3e40379159cbcf4c89e + lights[0].position.x += std::cos(time * 3.0f) * 2.5f; + lights[1].position.z += std::cos(time * 2.5f) * 3.0f; + lights[2].position.y += std::cos(time * 1.5f) * 4.0f; + lightsBuffer.fill(lights); + */ + + spheres[0].center.y += std::cos(time * 0.5f * 3.141f) * 0.25f; + spheres[1].center.x += std::cos(time * 2.f) * 0.25f; + spheres[1].center.z += std::cos(time * 2.f + 0.5f * 3.141f) * 0.25f; + sphereBuffer.fill(spheres); + + //update camera + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + glm::mat4 mvp = cameraManager.getActiveCamera().getMVP(); + glm::mat4 proj = cameraManager.getActiveCamera().getProjection(); + + //create pushconstants for render + vkcv::PushConstants pushConstants(sizeof(glm::mat4) * 2); + pushConstants.appendDrawcall(std::array<glm::mat4, 2>{ mvp, proj }); + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + //configure the outImage for compute shader (render into the swapchain image) + computeWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapchainInput)}; + core.writeDescriptorSet(computeDescriptorSet, computeWrites); + core.prepareImageForStorage (cmdStream, swapchainInput); + + //fill pushconstants for compute shader + struct RaytracingPushConstantData { + glm::mat4 viewToWorld; + int32_t lightCount; + int32_t sphereCount; + }; + + RaytracingPushConstantData raytracingPushData; + raytracingPushData.lightCount = lights.size(); + raytracingPushData.sphereCount = spheres.size(); + raytracingPushData.viewToWorld = glm::inverse(cameraManager.getActiveCamera().getView()); + + vkcv::PushConstants pushConstantsCompute(sizeof(RaytracingPushConstantData)); + pushConstantsCompute.appendDrawcall(raytracingPushData); + + //dispatch compute shader + uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil( swapchainWidth/16.f)), + static_cast<uint32_t> (std::ceil(swapchainHeight/16.f)), + 1 }; // Anzahl workgroups + core.recordComputeDispatchToCmdStream(cmdStream, + computePipeline, + computeDispatchCount, + { vkcv::DescriptorSetUsage(0,core.getDescriptorSet(computeDescriptorSet).vulkanHandle) }, + pushConstantsCompute); + + core.recordBufferMemoryBarrier(cmdStream, lightsBuffer.getHandle()); + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + core.endFrame(windowHandle); + } + return 0; +} diff --git a/projects/saf_r/src/safrScene.hpp b/projects/saf_r/src/safrScene.hpp new file mode 100644 index 0000000000000000000000000000000000000000..33a298f82121971021d1912e6c1205e9c48a49f0 --- /dev/null +++ b/projects/saf_r/src/safrScene.hpp @@ -0,0 +1,51 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> +#include <chrono> +#include <limits> +#include <cmath> +#include <vector> +#include <string.h> // memcpy(3) + +class safrScene { + +public: + + /* + * Light struct with a position and intensity of the light source + */ + struct Light { + Light(const glm::vec3& p, const float& i) : position(p), intensity(i) {} + glm::vec3 position; + float intensity; + }; + + /* + * Material struct with defuse color, albedo and specular component + */ + struct Material { + Material(const glm::vec4& a, const glm::vec3& color, const float& spec, const float& r) : albedo(a), diffuse_color(color), specular_exponent(spec), refractive_index(r) {} + Material() : refractive_index(1), albedo(1, 0, 0, 0), diffuse_color(), specular_exponent() {} + glm::vec4 albedo; + alignas(16) glm::vec3 diffuse_color; + float specular_exponent; + float refractive_index; + }; + + /* + * the sphere is defined by it's center, the radius and the material + */ + struct Sphere { + glm::vec3 center; + float radius; + Material material; + + Sphere(const glm::vec3& c, const float& r, const Material& m) : center(c), radius(r), material(m) {} + + }; + + +}; \ No newline at end of file diff --git a/projects/sph/.gitignore b/projects/sph/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..3968dc30067c92efde65779bc5eebecf167dfc75 --- /dev/null +++ b/projects/sph/.gitignore @@ -0,0 +1 @@ +sph \ No newline at end of file diff --git a/projects/sph/CMakeLists.txt b/projects/sph/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..592aa4409ae3e01f4054f430bab7c424d25219d0 --- /dev/null +++ b/projects/sph/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.16) +project(sph) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(sph + src/main.cpp + src/Particle.hpp + src/Particle.cpp + src/BloomAndFlares.hpp + src/BloomAndFlares.cpp + src/PipelineInit.hpp + src/PipelineInit.cpp) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(sph PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(sph PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(sph PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(sph SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(sph vkcv vkcv_testing vkcv_camera vkcv_shader_compiler) diff --git a/projects/sph/shaders/bloom/composite.comp b/projects/sph/shaders/bloom/composite.comp new file mode 100644 index 0000000000000000000000000000000000000000..87b5ddb975106232d1cd3b6e5b8dc7e623dd0b59 --- /dev/null +++ b/projects/sph/shaders/bloom/composite.comp @@ -0,0 +1,38 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D blurImage; +layout(set=0, binding=1) uniform texture2D lensImage; +layout(set=0, binding=2) uniform sampler linearSampler; +layout(set=0, binding=3, r11f_g11f_b10f) uniform image2D colorBuffer; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(colorBuffer)))){ + return; + } + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / textureSize(sampler2D(blurImage, linearSampler), 0); + vec2 UV = pixel_coord.xy * pixel_size; + + vec4 composite_color = vec4(0.0f); + + vec3 blur_color = texture(sampler2D(blurImage, linearSampler), UV).rgb; + vec3 lens_color = texture(sampler2D(lensImage, linearSampler), UV).rgb; + vec3 main_color = imageLoad(colorBuffer, pixel_coord).rgb; + + // composite blur and lens features + float bloom_weight = 0.01f; + float lens_weight = 0.f; + float main_weight = 1 - (bloom_weight + lens_weight); + + composite_color.rgb = blur_color * bloom_weight + + lens_color * lens_weight + + main_color * main_weight; + + imageStore(colorBuffer, pixel_coord, composite_color); +} \ No newline at end of file diff --git a/projects/sph/shaders/bloom/downsample.comp b/projects/sph/shaders/bloom/downsample.comp new file mode 100644 index 0000000000000000000000000000000000000000..2ab00c7c92798769153634f3479c5b7f3fb61d94 --- /dev/null +++ b/projects/sph/shaders/bloom/downsample.comp @@ -0,0 +1,76 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D inBlurImage; +layout(set=0, binding=1) uniform sampler inImageSampler; +layout(set=0, binding=2, r11f_g11f_b10f) uniform writeonly image2D outBlurImage; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outBlurImage)))){ + return; + } + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / imageSize(outBlurImage); + vec2 UV = pixel_coord.xy * pixel_size; + vec2 UV_offset = UV + 0.5f * pixel_size; + + vec2 color_fetches[13] = { + // center neighbourhood (RED) + vec2(-1, 1), // LT + vec2(-1, -1), // LB + vec2( 1, -1), // RB + vec2( 1, 1), // RT + + vec2(-2, 2), // LT + vec2( 0, 2), // CT + vec2( 2, 2), // RT + + vec2(0 ,-2), // LC + vec2(0 , 0), // CC + vec2(2, 0), // CR + + vec2(-2, -2), // LB + vec2(0 , -2), // CB + vec2(2 , -2) // RB + }; + + float color_weights[13] = { + // 0.5f + 1.f/8.f, + 1.f/8.f, + 1.f/8.f, + 1.f/8.f, + + // 0.125f + 1.f/32.f, + 1.f/16.f, + 1.f/32.f, + + // 0.25f + 1.f/16.f, + 1.f/8.f, + 1.f/16.f, + + // 0.125f + 1.f/32.f, + 1.f/16.f, + 1.f/32.f + }; + + vec3 sampled_color = vec3(0.0f); + + for(uint i = 0; i < 13; i++) + { + vec2 color_fetch = UV_offset + color_fetches[i] * pixel_size; + vec3 color = texture(sampler2D(inBlurImage, inImageSampler), color_fetch).rgb; + color *= color_weights[i]; + sampled_color += color; + } + + imageStore(outBlurImage, pixel_coord, vec4(sampled_color, 1.f)); +} \ No newline at end of file diff --git a/projects/sph/shaders/bloom/lensFlares.comp b/projects/sph/shaders/bloom/lensFlares.comp new file mode 100644 index 0000000000000000000000000000000000000000..ce27d8850b709f61332d467914ddc944dc63109f --- /dev/null +++ b/projects/sph/shaders/bloom/lensFlares.comp @@ -0,0 +1,109 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D blurBuffer; +layout(set=0, binding=1) uniform sampler linearSampler; +layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D lensBuffer; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +vec3 sampleColorChromaticAberration(vec2 _uv) +{ + vec2 toCenter = (vec2(0.5) - _uv); + + vec3 colorScales = vec3(-1, 0, 1); + float aberrationScale = 0.1; + vec3 scaleFactors = colorScales * aberrationScale; + + float r = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.r).r; + float g = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.g).g; + float b = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.b).b; + return vec3(r, g, b); +} + +// _uv assumed to be flipped UV coordinates! +vec3 ghost_vectors(vec2 _uv) +{ + vec2 ghost_vec = (vec2(0.5f) - _uv); + + const uint c_ghost_count = 64; + const float c_ghost_spacing = length(ghost_vec) / c_ghost_count; + + ghost_vec *= c_ghost_spacing; + + vec3 ret_color = vec3(0.0f); + + for (uint i = 0; i < c_ghost_count; ++i) + { + // sample scene color + vec2 s_uv = fract(_uv + ghost_vec * vec2(i)); + vec3 s = sampleColorChromaticAberration(s_uv); + + // tint/weight + float d = distance(s_uv, vec2(0.5)); + float weight = 1.0f - smoothstep(0.0f, 0.75f, d); + s *= weight; + + ret_color += s; + } + + ret_color /= c_ghost_count; + return ret_color; +} + +vec3 halo(vec2 _uv) +{ + const float c_aspect_ratio = float(imageSize(lensBuffer).x) / float(imageSize(lensBuffer).y); + const float c_radius = 0.6f; + const float c_halo_thickness = 0.1f; + + vec2 halo_vec = vec2(0.5) - _uv; + //halo_vec.x /= c_aspect_ratio; + halo_vec = normalize(halo_vec); + //halo_vec.x *= c_aspect_ratio; + + + //vec2 w_uv = (_uv - vec2(0.5, 0.0)) * vec2(c_aspect_ratio, 1.0) + vec2(0.5, 0.0); + vec2 w_uv = _uv; + float d = distance(w_uv, vec2(0.5)); // distance to center + + float distance_to_halo = abs(d - c_radius); + + float halo_weight = 0.0f; + if(abs(d - c_radius) <= c_halo_thickness) + { + float distance_to_border = c_halo_thickness - distance_to_halo; + halo_weight = distance_to_border / c_halo_thickness; + + //halo_weight = clamp((halo_weight / 0.4f), 0.0f, 1.0f); + halo_weight = pow(halo_weight, 2.0f); + + + //halo_weight = 1.0f; + } + + return sampleColorChromaticAberration(_uv + halo_vec) * halo_weight; +} + + + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(lensBuffer)))){ + return; + } + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / imageSize(lensBuffer); + vec2 UV = pixel_coord.xy * pixel_size; + + vec2 flipped_UV = vec2(1.0f) - UV; + + vec3 color = vec3(0.0f); + + color += ghost_vectors(flipped_UV); + color += halo(UV); + color *= 0.5f; + + imageStore(lensBuffer, pixel_coord, vec4(color, 0.0f)); +} \ No newline at end of file diff --git a/projects/sph/shaders/bloom/upsample.comp b/projects/sph/shaders/bloom/upsample.comp new file mode 100644 index 0000000000000000000000000000000000000000..0ddeedb5b5af9e476dc19012fed6430544006c0e --- /dev/null +++ b/projects/sph/shaders/bloom/upsample.comp @@ -0,0 +1,45 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D inUpsampleImage; +layout(set=0, binding=1) uniform sampler inImageSampler; +layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D outUpsampleImage; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outUpsampleImage)))){ + return; + } + + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / imageSize(outUpsampleImage); + vec2 UV = pixel_coord.xy * pixel_size; + + const float gauss_kernel[3] = {1.f, 2.f, 1.f}; + const float gauss_weight = 16.f; + + vec3 sampled_color = vec3(0.f); + + for(int i = -1; i <= 1; i++) + { + for(int j = -1; j <= 1; j++) + { + vec2 sample_location = UV + vec2(j, i) * pixel_size; + vec3 color = texture(sampler2D(inUpsampleImage, inImageSampler), sample_location).rgb; + color *= gauss_kernel[j+1]; + color *= gauss_kernel[i+1]; + color /= gauss_weight; + + sampled_color += color; + } + } + + //vec3 prev_color = imageLoad(outUpsampleImage, pixel_coord).rgb; + //float bloomRimStrength = 0.75f; // adjust this to change strength of bloom + //sampled_color = mix(prev_color, sampled_color, bloomRimStrength); + + imageStore(outUpsampleImage, pixel_coord, vec4(sampled_color, 1.f)); +} \ No newline at end of file diff --git a/projects/sph/shaders/flip.comp b/projects/sph/shaders/flip.comp new file mode 100644 index 0000000000000000000000000000000000000000..f5cd7bf3ea5ed8d04de970c816989230421c0b52 --- /dev/null +++ b/projects/sph/shaders/flip.comp @@ -0,0 +1,53 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +layout(local_size_x = 256) in; + +struct Particle +{ + vec3 position; + float padding; + vec3 velocity; + float density; + vec3 force; + float pressure; +}; + +layout(std430, binding = 1) readonly buffer buffer_inParticle +{ + Particle inParticle[]; +}; + +layout(std430, binding = 0) writeonly buffer buffer_outParticle +{ + Particle outParticle[]; +}; + +layout( push_constant ) uniform constants{ + float h; + float mass; + float gasConstant; + float offset; + float gravity; + float viscosity; + float ABSORBTION; + float dt; + vec3 gravityDir; + float particleCount; +}; + +void main() { + uint id = gl_GlobalInvocationID.x; + + if(id >= int(particleCount)) + { + return; + } + + outParticle[id].force = inParticle[id].force; + outParticle[id].density = inParticle[id].density; + outParticle[id].pressure = inParticle[id].pressure; + outParticle[id].position = inParticle[id].position; + outParticle[id].velocity = inParticle[id].velocity; +} diff --git a/projects/sph/shaders/force.comp b/projects/sph/shaders/force.comp new file mode 100644 index 0000000000000000000000000000000000000000..ea9b378b48a23fd0208ab18d884dbccda5ab21f4 --- /dev/null +++ b/projects/sph/shaders/force.comp @@ -0,0 +1,95 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +const float PI = 3.1415926535897932384626433832795; + +layout(local_size_x = 256) in; + +struct Particle +{ + vec3 position; + float padding; + vec3 velocity; + float density; + vec3 force; + float pressure; + +}; + +layout(std430, binding = 1) readonly buffer buffer_inParticle +{ + Particle inParticle[]; +}; + +layout(std430, binding = 0) writeonly buffer buffer_outParticle +{ + Particle outParticle[]; +}; + +layout( push_constant ) uniform constants{ + float h; + float mass; + float gasConstant; + float offset; + float gravity; + float viscosity; + float ABSORBTION; + float dt; + vec3 gravityDir; + float particleCount; +}; + +float spiky(float r) +{ + return (15.f / (PI * pow(h, 6)) * pow((h-r), 3)) * int(0<=r && r<=h); +} + +float grad_spiky(float r) +{ + return -45.f / (PI * pow(h, 6)) * pow((h-r), 2) * int(0<=r && r<=h); +} + + + +float laplacian(float r) +{ + return (45.f / (PI * pow(h,6)) * (h - r)) * int(0<=r && r<=h); +} + +vec3 pressureForce = vec3(0, 0, 0); +vec3 viscosityForce = vec3(0, 0, 0); +vec3 externalForce = vec3(0, 0, 0); + +void main() { + + uint id = gl_GlobalInvocationID.x; + + if(id >= int(particleCount)) + { + return; + } + + externalForce = inParticle[id].density * gravity * vec3(-gravityDir.x,gravityDir.y,gravityDir.z); + + for(uint i = 0; i < int(particleCount); i++) + { + if (id != i) + { + vec3 dir = inParticle[id].position - inParticle[i].position; + float dist = length(dir); + if(dist != 0) + { + pressureForce += mass * -(inParticle[id].pressure + inParticle[i].pressure)/(2.f * inParticle[i].density) * grad_spiky(dist) * normalize(dir); + viscosityForce += mass * (inParticle[i].velocity - inParticle[id].velocity)/inParticle[i].density * laplacian(dist); + } + } + } + viscosityForce *= viscosity; + + outParticle[id].force = externalForce + pressureForce + viscosityForce; + outParticle[id].density = inParticle[id].density; + outParticle[id].pressure = inParticle[id].pressure; + outParticle[id].position = inParticle[id].position; + outParticle[id].velocity = inParticle[id].velocity; +} diff --git a/projects/sph/shaders/particleShading.inc b/projects/sph/shaders/particleShading.inc new file mode 100644 index 0000000000000000000000000000000000000000..b2d1832b9ccd6ba05a585b59bdfdedd4729e80f8 --- /dev/null +++ b/projects/sph/shaders/particleShading.inc @@ -0,0 +1,6 @@ +float circleFactor(vec2 triangleCoordinates){ + // percentage of distance from center to circle edge + float p = clamp((0.4 - length(triangleCoordinates)) / 0.4, 0, 1); + // remapping for nice falloff + return sqrt(p); +} \ No newline at end of file diff --git a/projects/sph/shaders/particle_params.inc b/projects/sph/shaders/particle_params.inc new file mode 100644 index 0000000000000000000000000000000000000000..e35cce13be1bc84f045da276fe46666d0b852984 --- /dev/null +++ b/projects/sph/shaders/particle_params.inc @@ -0,0 +1,8 @@ +#define h 0.4 +#define mass 0.15 +#define gasConstant 3000 +#define offset 1800 +#define gravity -1000 +#define viscosity 1500 +#define ABSORBTION 0.9 +#define dt 0.0005 diff --git a/projects/sph/shaders/pressure.comp b/projects/sph/shaders/pressure.comp new file mode 100644 index 0000000000000000000000000000000000000000..05b3af3afb490b427cc1297f21a82a779d4c8ecb --- /dev/null +++ b/projects/sph/shaders/pressure.comp @@ -0,0 +1,72 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +const float PI = 3.1415926535897932384626433832795; + +layout(local_size_x = 256) in; + +struct Particle +{ + vec3 position; + float padding; + vec3 velocity; + float density; + vec3 force; + float pressure; + +}; + +layout(std430, binding = 0) readonly buffer buffer_inParticle +{ + Particle inParticle[]; +}; + +layout(std430, binding = 1) writeonly buffer buffer_outParticle +{ + Particle outParticle[]; +}; + +layout( push_constant ) uniform constants{ + float h; + float mass; + float gasConstant; + float offset; + float gravity; + float viscosity; + float ABSORBTION; + float dt; + vec3 gravityDir; + float particleCount; +}; + +float poly6(float r) +{ + return (315.f * pow((pow(h,2)-pow(r,2)), 3)/(64.f*PI*pow(h, 9))) * int(0<=r && r<=h); +} + +float densitySum = 0.f; + +void main() { + + uint id = gl_GlobalInvocationID.x; + + if(id >= int(particleCount)) + { + return; + } + + for(uint i = 0; i < int(particleCount); i++) + { + if (id != i) + { + float dist = distance(inParticle[id].position, inParticle[i].position); + densitySum += mass * poly6(dist); + } + } + outParticle[id].density = max(densitySum,0.0000001f); + outParticle[id].pressure = max((densitySum - offset), 0.0000001f) * gasConstant; + outParticle[id].position = inParticle[id].position; + outParticle[id].velocity = inParticle[id].velocity; + outParticle[id].force = inParticle[id].force; +} diff --git a/projects/sph/shaders/shader.vert b/projects/sph/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..f5531ffa4f26d3652e8e35971c16af6dda2e3b45 --- /dev/null +++ b/projects/sph/shaders/shader.vert @@ -0,0 +1,49 @@ +#version 460 core +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 particle; + +struct Particle +{ + vec3 position; + float padding; + vec3 velocity; + float density; + vec3 force; + float pressure; +}; + +layout(std430, binding = 2) readonly buffer buffer_inParticle1 +{ + Particle inParticle1[]; +}; + +layout(std430, binding = 3) readonly buffer buffer_inParticle2 +{ + Particle inParticle2[]; +}; + +layout( push_constant ) uniform constants{ + mat4 view; + mat4 projection; +}; + +layout(location = 0) out vec2 passTriangleCoordinates; +layout(location = 1) out vec3 passVelocity; + +void main() +{ + int id = gl_InstanceIndex; + passVelocity = inParticle1[id].velocity; + + // particle position in view space + vec4 positionView = view * vec4(inParticle1[id].position, 1); + // by adding the triangle position in view space the mesh is always camera facing + positionView.xyz += particle; + // multiply with projection matrix for final position + gl_Position = projection * positionView; + + // 0.01 corresponds to vertex position size in main + float normalizationDivider = 0.012; + passTriangleCoordinates = particle.xy / normalizationDivider; +} \ No newline at end of file diff --git a/projects/sph/shaders/shader_water.frag b/projects/sph/shaders/shader_water.frag new file mode 100644 index 0000000000000000000000000000000000000000..2aee4ec692a2ada060a77389099b2c279e9c338c --- /dev/null +++ b/projects/sph/shaders/shader_water.frag @@ -0,0 +1,28 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +#include "particleShading.inc" + +layout(location = 0) in vec2 passTriangleCoordinates; +layout(location = 1) in vec3 passVelocity; + +layout(location = 0) out vec3 outColor; + +layout(set=0, binding=0) uniform uColor { + vec4 color; +} Color; + +layout(set=0,binding=1) uniform uPosition{ + vec2 position; +} Position; + +void main() +{ + float p = length(passVelocity)/100.f; + outColor = vec3(0.f+p/3.f, 0.05f+p/2.f, 0.4f+p); + + // make the triangle look like a circle + outColor *= circleFactor(passTriangleCoordinates); + +} diff --git a/projects/sph/shaders/tonemapping.comp b/projects/sph/shaders/tonemapping.comp new file mode 100644 index 0000000000000000000000000000000000000000..26f0232d66e3475afdd1266c0cc6288b47ed1c38 --- /dev/null +++ b/projects/sph/shaders/tonemapping.comp @@ -0,0 +1,19 @@ +#version 440 + +layout(set=0, binding=0, rgba16f) uniform image2D inImage; +layout(set=0, binding=1, rgba8) uniform image2D outImage; + + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main(){ + + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(inImage)))){ + return; + } + ivec2 uv = ivec2(gl_GlobalInvocationID.xy); + vec3 linearColor = imageLoad(inImage, uv).rgb; + vec3 tonemapped = linearColor / (dot(linearColor, vec3(0.21, 0.71, 0.08)) + 1); // reinhard tonemapping + vec3 gammaCorrected = pow(tonemapped, vec3(1.f / 2.2f)); + imageStore(outImage, uv, vec4(gammaCorrected, 0.f)); +} \ No newline at end of file diff --git a/projects/sph/shaders/updateData.comp b/projects/sph/shaders/updateData.comp new file mode 100644 index 0000000000000000000000000000000000000000..3c935b232aff11388cc3b371e5524fa30486b36f --- /dev/null +++ b/projects/sph/shaders/updateData.comp @@ -0,0 +1,109 @@ +#version 450 core +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +layout(local_size_x = 256) in; + +struct Particle +{ + vec3 position; + float padding; + vec3 velocity; + float density; + vec3 force; + float pressure; + +}; + +layout(std430, binding = 0) readonly buffer buffer_inParticle +{ + Particle inParticle[]; +}; + +layout(std430, binding = 1) writeonly buffer buffer_outParticle +{ + Particle outParticle[]; +}; + +layout( push_constant ) uniform constants{ + float h; + float mass; + float gasConstant; + float offset; + float gravity; + float viscosity; + float ABSORBTION; + float dt; + vec3 gravityDir; + float particleCount; +}; + +void main() { + + uint id = gl_GlobalInvocationID.x; + + if(id >= int(particleCount)) + { + return; + } + + vec3 accel = inParticle[id].force / inParticle[id].density; + vec3 vel_new = inParticle[id].velocity + (dt * accel); + + vec3 out_force = inParticle[id].force; + float out_density = inParticle[id].density; + float out_pressure = inParticle[id].pressure; + + if (length(vel_new) > 100.f) + { + vel_new = normalize(vel_new)*50; + out_density = 0.01f; + out_pressure = 0.01f; + out_force = gravity * vec3(-gravityDir.x,gravityDir.y,gravityDir.z); + } + + vec3 pos_new = inParticle[id].position + (dt * vel_new); + + // Überprüfe Randbedingungen x + if (inParticle[id].position.x < -1.0) + { + vel_new = reflect(vel_new.xyz, vec3(1.f,0.f,0.f)) * ABSORBTION; + pos_new.x = -1.0 + 0.01f; + } + else if (inParticle[id].position.x > 1.0) + { + vel_new = reflect(vel_new,vec3(1.f,0.f,0.f)) * ABSORBTION; + pos_new.x = 1.0 - 0.01f; + } + + // Überprüfe Randbedingungen y + if (inParticle[id].position.y < -1.0) + { + vel_new = reflect(vel_new,vec3(0.f,1.f,0.f)) * ABSORBTION; + pos_new.y = -1.0 + 0.01f; + + } + else if (inParticle[id].position.y > 1.0) + { + vel_new = reflect(vel_new,vec3(0.f,1.f,0.f)) * ABSORBTION; + pos_new.y = 1.0 - 0.01f; + } + + // Überprüfe Randbedingungen z + if (inParticle[id].position.z < -1.0 ) + { + vel_new = reflect(vel_new,vec3(0.f,0.f,1.f)) * ABSORBTION; + pos_new.z = -1.0 + 0.01f; + } + else if (inParticle[id].position.z > 1.0 ) + { + vel_new = reflect(vel_new,vec3(0.f,0.f,1.f)) * ABSORBTION; + pos_new.z = 1.0 - 0.01f; + } + + outParticle[id].force = out_force; + outParticle[id].density = out_density; + outParticle[id].pressure = out_pressure; + outParticle[id].position = pos_new; + outParticle[id].velocity = vel_new; +} diff --git a/projects/sph/src/BloomAndFlares.cpp b/projects/sph/src/BloomAndFlares.cpp new file mode 100644 index 0000000000000000000000000000000000000000..09534815afcd8ab238b79da5c6bbceb6672b043a --- /dev/null +++ b/projects/sph/src/BloomAndFlares.cpp @@ -0,0 +1,285 @@ +#include "BloomAndFlares.hpp" +#include <vkcv/shader/GLSLCompiler.hpp> + +BloomAndFlares::BloomAndFlares( + vkcv::Core *p_Core, + vk::Format colorBufferFormat, + uint32_t width, + uint32_t height) : + + p_Core(p_Core), + m_ColorBufferFormat(colorBufferFormat), + m_Width(width), + m_Height(height), + m_LinearSampler(p_Core->createSampler(vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE)), + m_Blur(p_Core->createImage(colorBufferFormat, width, height, 1, true, true, false)), + m_LensFeatures(p_Core->createImage(colorBufferFormat, width, height, 1, false, true, false)) +{ + vkcv::shader::GLSLCompiler compiler; + + // DOWNSAMPLE + vkcv::ShaderProgram dsProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "shaders/bloom/downsample.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + dsProg.addShader(shaderStage, path); + }); + for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) + { + m_DownsampleDescSetLayouts.push_back( + p_Core->createDescriptorSetLayout(dsProg.getReflectedDescriptors().at(0))); + + m_DownsampleDescSets.push_back( + p_Core->createDescriptorSet(m_DownsampleDescSetLayouts.back())); + } + m_DownsamplePipe = p_Core->createComputePipeline({ + dsProg, { p_Core->getDescriptorSetLayout(m_DownsampleDescSetLayouts[0]).vulkanHandle } }); + + // UPSAMPLE + vkcv::ShaderProgram usProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "shaders/bloom/upsample.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + usProg.addShader(shaderStage, path); + }); + for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) + { + m_UpsampleDescSetLayouts.push_back( + p_Core->createDescriptorSetLayout(usProg.getReflectedDescriptors().at(0))); + m_UpsampleDescSets.push_back( + p_Core->createDescriptorSet(m_UpsampleDescSetLayouts.back())); + } + m_UpsamplePipe = p_Core->createComputePipeline({ + usProg, { p_Core->getDescriptorSetLayout(m_UpsampleDescSetLayouts[0]).vulkanHandle } }); + + // LENS FEATURES + vkcv::ShaderProgram lensProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "shaders/bloom/lensFlares.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + lensProg.addShader(shaderStage, path); + }); + m_LensFlareDescSetLayout = p_Core->createDescriptorSetLayout(lensProg.getReflectedDescriptors().at(0)); + m_LensFlareDescSet = p_Core->createDescriptorSet(m_LensFlareDescSetLayout); + m_LensFlarePipe = p_Core->createComputePipeline({ + lensProg, { p_Core->getDescriptorSetLayout(m_LensFlareDescSetLayout).vulkanHandle } }); + + // COMPOSITE + vkcv::ShaderProgram compProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "shaders/bloom/composite.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + compProg.addShader(shaderStage, path); + }); + m_CompositeDescSetLayout = p_Core->createDescriptorSetLayout(compProg.getReflectedDescriptors().at(0)); + m_CompositeDescSet = p_Core->createDescriptorSet(m_CompositeDescSetLayout); + m_CompositePipe = p_Core->createComputePipeline({ + compProg, { p_Core->getDescriptorSetLayout(m_CompositeDescSetLayout).vulkanHandle } }); +} + +void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, + const vkcv::ImageHandle &colorAttachment) +{ + auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; + auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; + // blur dispatch + uint32_t initialDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(dispatchCountX)), + static_cast<uint32_t>(glm::ceil(dispatchCountY)), + 1 + }; + + // downsample dispatch of original color attachment + p_Core->prepareImageForSampling(cmdStream, colorAttachment); + p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); + + vkcv::DescriptorWrites initialDownsampleWrites; + initialDownsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, colorAttachment)}; + initialDownsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + initialDownsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), 0) }; + p_Core->writeDescriptorSet(m_DownsampleDescSets[0], initialDownsampleWrites); + + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_DownsamplePipe, + initialDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[0]).vulkanHandle)}, + vkcv::PushConstants(0)); + + // downsample dispatches of blur buffer's mip maps + float mipDispatchCountX = dispatchCountX; + float mipDispatchCountY = dispatchCountY; + for(uint32_t mipLevel = 1; mipLevel < std::min((uint32_t)m_DownsampleDescSets.size(), m_Blur.getMipCount()); mipLevel++) + { + // mip descriptor writes + vkcv::DescriptorWrites mipDescriptorWrites; + mipDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel - 1, true)}; + mipDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + mipDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel) }; + p_Core->writeDescriptorSet(m_DownsampleDescSets[mipLevel], mipDescriptorWrites); + + // mip dispatch calculation + mipDispatchCountX /= 2.0f; + mipDispatchCountY /= 2.0f; + + uint32_t mipDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(mipDispatchCountX)), + static_cast<uint32_t>(glm::ceil(mipDispatchCountY)), + 1 + }; + + if(mipDispatchCount[0] == 0) + mipDispatchCount[0] = 1; + if(mipDispatchCount[1] == 0) + mipDispatchCount[1] = 1; + + // mip blur dispatch + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_DownsamplePipe, + mipDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[mipLevel]).vulkanHandle)}, + vkcv::PushConstants(0)); + + // image barrier between mips + p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); + } +} + +void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream) +{ + // upsample dispatch + p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); + + const uint32_t upsampleMipLevels = std::min( + static_cast<uint32_t>(m_UpsampleDescSets.size() - 1), + static_cast<uint32_t>(3) + ); + + // upsample dispatch for each mip map + for(uint32_t mipLevel = upsampleMipLevels; mipLevel > 0; mipLevel--) + { + // mip descriptor writes + vkcv::DescriptorWrites mipUpsampleWrites; + mipUpsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel, true)}; + mipUpsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + mipUpsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel - 1) }; + p_Core->writeDescriptorSet(m_UpsampleDescSets[mipLevel], mipUpsampleWrites); + + auto mipDivisor = glm::pow(2.0f, static_cast<float>(mipLevel) - 1.0f); + + auto upsampleDispatchX = static_cast<float>(m_Width) / mipDivisor; + auto upsampleDispatchY = static_cast<float>(m_Height) / mipDivisor; + upsampleDispatchX /= 8.0f; + upsampleDispatchY /= 8.0f; + + const uint32_t upsampleDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(upsampleDispatchX)), + static_cast<uint32_t>(glm::ceil(upsampleDispatchY)), + 1 + }; + + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_UpsamplePipe, + upsampleDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleDescSets[mipLevel]).vulkanHandle)}, + vkcv::PushConstants(0) + ); + // image barrier between mips + p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); + } +} + +void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream) +{ + // lens feature generation descriptor writes + p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); + p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); + + vkcv::DescriptorWrites lensFeatureWrites; + lensFeatureWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), 0)}; + lensFeatureWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + lensFeatureWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_LensFeatures.getHandle(), 0)}; + p_Core->writeDescriptorSet(m_LensFlareDescSet, lensFeatureWrites); + + auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; + auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; + // lens feature generation dispatch + uint32_t lensFeatureDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(dispatchCountX)), + static_cast<uint32_t>(glm::ceil(dispatchCountY)), + 1 + }; + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_LensFlarePipe, + lensFeatureDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_LensFlareDescSet).vulkanHandle)}, + vkcv::PushConstants(0)); +} + +void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, + const vkcv::ImageHandle &colorAttachment) +{ + p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); + p_Core->prepareImageForSampling(cmdStream, m_LensFeatures.getHandle()); + p_Core->prepareImageForStorage(cmdStream, colorAttachment); + + // bloom composite descriptor write + vkcv::DescriptorWrites compositeWrites; + compositeWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle()), + vkcv::SampledImageDescriptorWrite(1, m_LensFeatures.getHandle())}; + compositeWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(2, m_LinearSampler)}; + compositeWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(3, colorAttachment)}; + p_Core->writeDescriptorSet(m_CompositeDescSet, compositeWrites); + + float dispatchCountX = static_cast<float>(m_Width) / 8.0f; + float dispatchCountY = static_cast<float>(m_Height) / 8.0f; + + uint32_t compositeDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(dispatchCountX)), + static_cast<uint32_t>(glm::ceil(dispatchCountY)), + 1 + }; + + // bloom composite dispatch + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_CompositePipe, + compositeDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)}, + vkcv::PushConstants(0)); +} + +void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, + const vkcv::ImageHandle &colorAttachment) +{ + execDownsamplePipe(cmdStream, colorAttachment); + execUpsamplePipe(cmdStream); + execLensFeaturePipe(cmdStream); + execCompositePipe(cmdStream, colorAttachment); +} + +void BloomAndFlares::updateImageDimensions(uint32_t width, uint32_t height) +{ + if ((width == m_Width) && (height == m_Height)) { + return; + } + + m_Width = width; + m_Height = height; + + p_Core->getContext().getDevice().waitIdle(); + m_Blur = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, true, true, false); + m_LensFeatures = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, false, true, false); +} + + diff --git a/projects/sph/src/BloomAndFlares.hpp b/projects/sph/src/BloomAndFlares.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1644d38e9c98c7a0bf74d48b173f0e627214f1e1 --- /dev/null +++ b/projects/sph/src/BloomAndFlares.hpp @@ -0,0 +1,51 @@ +#pragma once +#include <vkcv/Core.hpp> +#include <glm/glm.hpp> + +class BloomAndFlares{ +public: + BloomAndFlares(vkcv::Core *p_Core, + vk::Format colorBufferFormat, + uint32_t width, + uint32_t height); + + void execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); + + void updateImageDimensions(uint32_t width, uint32_t height); + +private: + vkcv::Core *p_Core; + + vk::Format m_ColorBufferFormat; + uint32_t m_Width; + uint32_t m_Height; + + vkcv::SamplerHandle m_LinearSampler; + vkcv::Image m_Blur; + vkcv::Image m_LensFeatures; + + + vkcv::ComputePipelineHandle m_DownsamplePipe; + std::vector<vkcv::DescriptorSetLayoutHandle> m_DownsampleDescSetLayouts; + std::vector<vkcv::DescriptorSetHandle> m_DownsampleDescSets; // per mip desc set + + vkcv::ComputePipelineHandle m_UpsamplePipe; + std::vector<vkcv::DescriptorSetLayoutHandle> m_UpsampleDescSetLayouts; + std::vector<vkcv::DescriptorSetHandle> m_UpsampleDescSets; // per mip desc set + + vkcv::ComputePipelineHandle m_LensFlarePipe; + vkcv::DescriptorSetLayoutHandle m_LensFlareDescSetLayout; + vkcv::DescriptorSetHandle m_LensFlareDescSet; + + vkcv::ComputePipelineHandle m_CompositePipe; + vkcv::DescriptorSetLayoutHandle m_CompositeDescSetLayout; + vkcv::DescriptorSetHandle m_CompositeDescSet; + + void execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); + void execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream); + void execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream); + void execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); +}; + + + diff --git a/projects/sph/src/Particle.cpp b/projects/sph/src/Particle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..329236989b7cab502e7a4e1bb5aa27869bed53cb --- /dev/null +++ b/projects/sph/src/Particle.cpp @@ -0,0 +1,39 @@ + +#include "Particle.hpp" + +Particle::Particle(glm::vec3 position, glm::vec3 velocity) +: m_position(position), + m_velocity(velocity) +{ + m_density = 0.f; + m_force = glm::vec3(0.f); + m_pressure = 0.f; +} + +const glm::vec3& Particle::getPosition()const{ + return m_position; +} + +void Particle::setPosition( const glm::vec3 pos ){ + m_position = pos; +} + +const glm::vec3& Particle::getVelocity()const{ + return m_velocity; +} + +void Particle::setVelocity( const glm::vec3 vel ){ + m_velocity = vel; +} + +const float& Particle::getDensity()const { + return m_density; +} + +const glm::vec3& Particle::getForce()const { + return m_force; +} + +const float& Particle::getPressure()const { + return m_pressure; +} \ No newline at end of file diff --git a/projects/sph/src/Particle.hpp b/projects/sph/src/Particle.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6c4ab50b74cc4544976318c23e36f4b91989ee66 --- /dev/null +++ b/projects/sph/src/Particle.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <glm/glm.hpp> + +class Particle { + +public: + Particle(glm::vec3 position, glm::vec3 velocity); + + const glm::vec3& getPosition()const; + + void setPosition( const glm::vec3 pos ); + + const glm::vec3& getVelocity()const; + + void setVelocity( const glm::vec3 vel ); + + const float& getDensity()const; + + const glm::vec3& getForce()const; + + const float& getPressure()const; + + + +private: + // all properties of the Particle + glm::vec3 m_position; + float m_padding1; + glm::vec3 m_velocity; + float m_density; + glm::vec3 m_force; + float m_pressure; +}; diff --git a/projects/sph/src/PipelineInit.cpp b/projects/sph/src/PipelineInit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6cf941fa0d8f8716b7d05daf9b6fb618b0fa7d85 --- /dev/null +++ b/projects/sph/src/PipelineInit.cpp @@ -0,0 +1,27 @@ +#include "PipelineInit.hpp" + +vkcv::DescriptorSetHandle PipelineInit::ComputePipelineInit(vkcv::Core *pCore, vkcv::ShaderStage shaderStage, std::filesystem::path includePath, + vkcv::ComputePipelineHandle &pipeline) { + vkcv::ShaderProgram shaderProgram; + vkcv::shader::GLSLCompiler compiler; + compiler.compile(shaderStage, includePath, + [&](vkcv::ShaderStage shaderStage1, const std::filesystem::path& path1) {shaderProgram.addShader(shaderStage1, path1); + }); + vkcv::DescriptorSetLayoutHandle descriptorSetLayout = pCore->createDescriptorSetLayout( + shaderProgram.getReflectedDescriptors().at(0)); + vkcv::DescriptorSetHandle descriptorSet = pCore->createDescriptorSet(descriptorSetLayout); + + const std::vector<vkcv::VertexAttachment> vertexAttachments = shaderProgram.getVertexAttachments(); + + std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + } + const vkcv::VertexLayout layout(bindings); + + pipeline = pCore->createComputePipeline({ + shaderProgram, + { pCore->getDescriptorSetLayout(descriptorSetLayout).vulkanHandle } }); + + return descriptorSet; +} \ No newline at end of file diff --git a/projects/sph/src/PipelineInit.hpp b/projects/sph/src/PipelineInit.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e628af0eef9c0558719b405790246946d8720d47 --- /dev/null +++ b/projects/sph/src/PipelineInit.hpp @@ -0,0 +1,12 @@ +#pragma once +#include <vkcv/Core.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> +#include <fstream> + +class PipelineInit{ +public: + static vkcv::DescriptorSetHandle ComputePipelineInit(vkcv::Core *pCore, + vkcv::ShaderStage shaderStage, + std::filesystem::path includePath, + vkcv::ComputePipelineHandle& pipeline); +}; diff --git a/projects/sph/src/main.cpp b/projects/sph/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..255fb0e73f068ff9e5e8ce892897a1325631b6e1 --- /dev/null +++ b/projects/sph/src/main.cpp @@ -0,0 +1,409 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> +#include <random> +#include <glm/glm.hpp> +#include <glm/gtc/matrix_access.hpp> +#include <glm/gtc/matrix_transform.hpp> +#include <time.h> +#include <vkcv/shader/GLSLCompiler.hpp> +#include "BloomAndFlares.hpp" +#include "PipelineInit.hpp" +#include "Particle.hpp" + +int main(int argc, const char **argv) { + const char *applicationName = "SPH"; + + vkcv::Core core = vkcv::Core::create( + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, + { VK_KHR_SWAPCHAIN_EXTENSION_NAME } + ); + + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 1920, 1080, false); + vkcv::Window& window = core.getWindow(windowHandle); + + vkcv::camera::CameraManager cameraManager(window); + + auto particleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, + vkcv::BufferMemoryType::DEVICE_LOCAL); + uint16_t indices[3] = {0, 1, 2}; + particleIndexBuffer.fill(&indices[0], sizeof(indices)); + + vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat; + // an example attachment for passes that output to the window + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + colorFormat); + + + vkcv::PassConfig particlePassDefinition({present_color_attachment}); + vkcv::PassHandle particlePass = core.createPass(particlePassDefinition); + + vkcv::PassConfig computePassDefinition({}); + vkcv::PassHandle computePass = core.createPass(computePassDefinition); + + //rotation + float rotationx = 0; + float rotationy = 0; + + // params + float param_h = 0.20; + float param_mass = 0.03; + float param_gasConstant = 3500; + float param_offset = 200; + float param_gravity = -5000; + float param_viscosity = 10; + float param_ABSORBTION = 0.5; + float param_dt = 0.0005; + + if (!particlePass || !computePass) + { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + vkcv::shader::GLSLCompiler compiler; + +// comp shader 1 + vkcv::ComputePipelineHandle computePipeline1; + vkcv::DescriptorSetHandle computeDescriptorSet1 = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, + "shaders/pressure.comp", computePipeline1); +// comp shader 2 + vkcv::ComputePipelineHandle computePipeline2; + vkcv::DescriptorSetHandle computeDescriptorSet2 = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, + "shaders/force.comp", computePipeline2); + +//comp shader 3 + vkcv::ComputePipelineHandle computePipeline3; + vkcv::DescriptorSetHandle computeDescriptorSet3 = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, + "shaders/updateData.comp", computePipeline3); + +//comp shader 4 + vkcv::ComputePipelineHandle computePipeline4; + vkcv::DescriptorSetHandle computeDescriptorSet4 = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, + "shaders/flip.comp", computePipeline4); + +// shader + vkcv::ShaderProgram particleShaderProgram{}; + compiler.compile(vkcv::ShaderStage::VERTEX, "shaders/shader.vert", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + particleShaderProgram.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::FRAGMENT, "shaders/shader_water.frag", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + particleShaderProgram.addShader(shaderStage, path); + }); + + vkcv::DescriptorSetLayoutHandle descriptorSetLayout = core.createDescriptorSetLayout( + particleShaderProgram.getReflectedDescriptors().at(0)); + vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorSetLayout); + + vkcv::Buffer<glm::vec3> vertexBuffer = core.createBuffer<glm::vec3>( + vkcv::BufferType::VERTEX, + 3 + ); + const std::vector<vkcv::VertexAttachment> vertexAttachments = particleShaderProgram.getVertexAttachments(); + + const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { + vkcv::VertexBufferBinding(0, vertexBuffer.getVulkanHandle())}; + + std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + bindings.push_back(vkcv::VertexBinding(i, {vertexAttachments[i]})); + } + + const vkcv::VertexLayout particleLayout(bindings); + + vkcv::GraphicsPipelineConfig particlePipelineDefinition{ + particleShaderProgram, + UINT32_MAX, + UINT32_MAX, + particlePass, + {particleLayout}, + {core.getDescriptorSetLayout(descriptorSetLayout).vulkanHandle}, + true}; + particlePipelineDefinition.m_blendMode = vkcv::BlendMode::Additive; + + const std::vector<glm::vec3> vertices = {glm::vec3(-0.012, 0.012, 0), + glm::vec3(0.012, 0.012, 0), + glm::vec3(0, -0.012, 0)}; + + vertexBuffer.fill(vertices); + + vkcv::GraphicsPipelineHandle particlePipeline = core.createGraphicsPipeline(particlePipelineDefinition); + + vkcv::Buffer<glm::vec4> color = core.createBuffer<glm::vec4>( + vkcv::BufferType::UNIFORM, + 1 + ); + + vkcv::Buffer<glm::vec2> position = core.createBuffer<glm::vec2>( + vkcv::BufferType::UNIFORM, + 1 + ); + + int numberParticles = 20000; + std::vector<Particle> particles; + for (int i = 0; i < numberParticles; i++) { + const float lo = 0.6; + const float hi = 0.9; + const float vlo = 0; + const float vhi = 70; + float x = lo + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(hi-lo))); + float y = lo + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(hi-lo))); + float z = lo + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(hi-lo))); + float vx = vlo + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(vhi-vlo))); + float vy = vlo + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(vhi-vlo))); + float vz = vlo + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(vhi-vlo))); + glm::vec3 pos = glm::vec3(x,y,z); + glm::vec3 vel = glm::vec3(vx,vy,vz); + //glm::vec3 vel = glm::vec3(0.0,0.0,0.0); + particles.push_back(Particle(pos, vel)); + } + + vkcv::Buffer<Particle> particleBuffer1 = core.createBuffer<Particle>( + vkcv::BufferType::STORAGE, + numberParticles * sizeof(glm::vec4) * 3 + + ); + + vkcv::Buffer<Particle> particleBuffer2 = core.createBuffer<Particle>( + vkcv::BufferType::STORAGE, + numberParticles * sizeof(glm::vec4) * 3 + ); + + particleBuffer1.fill(particles); + particleBuffer2.fill(particles); + + vkcv::DescriptorWrites setWrites; + setWrites.uniformBufferWrites = {vkcv::BufferDescriptorWrite(0,color.getHandle()), + vkcv::BufferDescriptorWrite(1,position.getHandle())}; + setWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(2,particleBuffer1.getHandle()), + vkcv::BufferDescriptorWrite(3,particleBuffer2.getHandle())}; + core.writeDescriptorSet(descriptorSet, setWrites); + + vkcv::DescriptorWrites computeWrites; + computeWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0,particleBuffer1.getHandle()), + vkcv::BufferDescriptorWrite(1,particleBuffer2.getHandle())}; + + core.writeDescriptorSet(computeDescriptorSet1, computeWrites); + core.writeDescriptorSet(computeDescriptorSet2, computeWrites); + core.writeDescriptorSet(computeDescriptorSet3, computeWrites); + core.writeDescriptorSet(computeDescriptorSet4, computeWrites); + + if (!particlePipeline || !computePipeline1 || !computePipeline2 || !computePipeline3 || !computePipeline4) + { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + const vkcv::Mesh renderMesh({vertexBufferBindings}, particleIndexBuffer.getVulkanHandle(), + particleIndexBuffer.getCount()); + vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle); + + auto pos = glm::vec2(0.f); + auto spawnPosition = glm::vec3(0.f); + + std::vector<vkcv::DrawcallInfo> drawcalls; + drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage}, numberParticles)); + + auto start = std::chrono::system_clock::now(); + + glm::vec4 colorData = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex0).setNearFar(0.1, 30); + cameraManager.getCamera(camIndex1).setNearFar(0.1, 30); + + cameraManager.setActiveCamera(1); + + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -2.5)); + cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, -2.5f)); + cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, 0.0f)); + + auto swapchainExtent = core.getSwapchain(window.getSwapchainHandle()).getExtent(); + + vkcv::ImageHandle colorBuffer = core.createImage( + colorFormat, + swapchainExtent.width, + swapchainExtent.height, + 1, false, true, true + ).getHandle(); + BloomAndFlares bloomAndFlares(&core, colorFormat, swapchainExtent.width, swapchainExtent.height); + + //tone mapping shader & pipeline + vkcv::ComputePipelineHandle tonemappingPipe; + vkcv::DescriptorSetHandle tonemappingDescriptor = PipelineInit::ComputePipelineInit(&core, vkcv::ShaderStage::COMPUTE, + "shaders/tonemapping.comp", tonemappingPipe); + + + while (vkcv::Window::hasOpenWindow()) { + vkcv::Window::pollEvents(); + + uint32_t swapchainWidth, swapchainHeight; + if (!core.beginFrame(swapchainWidth, swapchainHeight, windowHandle)) { + continue; + } + + color.fill(&colorData); + position.fill(&pos); + + auto end = std::chrono::system_clock::now(); + float deltatime = 0.000001 * static_cast<float>( std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() ); + start = end; + + cameraManager.update(deltatime); + + // split view and projection to allow for easy billboarding in shader + struct { + glm::mat4 view; + glm::mat4 projection; + } renderingMatrices; + + glm::vec3 gravityDir = glm::rotate(glm::mat4(1.0), glm::radians(rotationx), glm::vec3(0.f,0.f,1.f)) * glm::vec4(0.f,1.f,0.f,0.f); + gravityDir = glm::rotate(glm::mat4(1.0), glm::radians(rotationy), glm::vec3(0.f,1.f,0.f)) * glm::vec4(gravityDir,0.f); + + renderingMatrices.view = cameraManager.getActiveCamera().getView(); + renderingMatrices.view = glm::rotate(renderingMatrices.view, glm::radians(rotationx), glm::vec3(0.f, 0.f, 1.f)); + renderingMatrices.view = glm::rotate(renderingMatrices.view, glm::radians(rotationy), glm::vec3(0.f, 1.f, 0.f)); + renderingMatrices.projection = cameraManager.getActiveCamera().getProjection(); + + // keybindings rotation + if (glfwGetKey(window.getWindow(), GLFW_KEY_LEFT) == GLFW_PRESS) + rotationx += deltatime * 50; + if (glfwGetKey(window.getWindow(), GLFW_KEY_RIGHT) == GLFW_PRESS) + rotationx -= deltatime * 50; + + if (glfwGetKey(window.getWindow(), GLFW_KEY_UP) == GLFW_PRESS) + rotationy += deltatime * 50; + if (glfwGetKey(window.getWindow(), GLFW_KEY_DOWN) == GLFW_PRESS) + rotationy -= deltatime * 50; + + // keybindings params + if (glfwGetKey(window.getWindow(), GLFW_KEY_T) == GLFW_PRESS) + param_h += deltatime * 0.2; + if (glfwGetKey(window.getWindow(), GLFW_KEY_G) == GLFW_PRESS) + param_h -= deltatime * 0.2; + + if (glfwGetKey(window.getWindow(), GLFW_KEY_Y) == GLFW_PRESS) + param_mass += deltatime * 0.2; + if (glfwGetKey(window.getWindow(), GLFW_KEY_H) == GLFW_PRESS) + param_mass -= deltatime * 0.2; + + if (glfwGetKey(window.getWindow(), GLFW_KEY_U) == GLFW_PRESS) + param_gasConstant += deltatime * 1500.0; + if (glfwGetKey(window.getWindow(), GLFW_KEY_J) == GLFW_PRESS) + param_gasConstant -= deltatime * 1500.0; + + if (glfwGetKey(window.getWindow(), GLFW_KEY_I) == GLFW_PRESS) + param_offset += deltatime * 400.0; + if (glfwGetKey(window.getWindow(), GLFW_KEY_K) == GLFW_PRESS) + param_offset -= deltatime * 400.0; + + if (glfwGetKey(window.getWindow(), GLFW_KEY_O) == GLFW_PRESS) + param_viscosity = 50; + if (glfwGetKey(window.getWindow(), GLFW_KEY_L) == GLFW_PRESS) + param_viscosity = 1200; + + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + glm::vec4 pushData[3] = { + glm::vec4(param_h,param_mass,param_gasConstant,param_offset), + glm::vec4(param_gravity,param_viscosity,param_ABSORBTION,param_dt), + glm::vec4(gravityDir.x,gravityDir.y,gravityDir.z,(float)numberParticles) + }; + + std::cout << "h: " << param_h << " | mass: " << param_mass << " | gasConstant: " << param_gasConstant << " | offset: " << param_offset << " | viscosity: " << param_viscosity << std::endl; + + vkcv::PushConstants pushConstantsCompute (sizeof(pushData)); + pushConstantsCompute.appendDrawcall(pushData); + + uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(numberParticles/256.f)),1,1}; + + core.recordComputeDispatchToCmdStream(cmdStream, + computePipeline1, + computeDispatchCount, + {vkcv::DescriptorSetUsage(0,core.getDescriptorSet(computeDescriptorSet1).vulkanHandle)}, + pushConstantsCompute); + + core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); + core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); + + core.recordComputeDispatchToCmdStream(cmdStream, + computePipeline2, + computeDispatchCount, + {vkcv::DescriptorSetUsage(0,core.getDescriptorSet(computeDescriptorSet2).vulkanHandle)}, + pushConstantsCompute); + + core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); + core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); + + core.recordComputeDispatchToCmdStream(cmdStream, + computePipeline3, + computeDispatchCount, + { vkcv::DescriptorSetUsage(0,core.getDescriptorSet(computeDescriptorSet3).vulkanHandle) }, + pushConstantsCompute); + + core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); + core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); + + core.recordComputeDispatchToCmdStream(cmdStream, + computePipeline4, + computeDispatchCount, + { vkcv::DescriptorSetUsage(0,core.getDescriptorSet(computeDescriptorSet4).vulkanHandle) }, + pushConstantsCompute); + + core.recordBufferMemoryBarrier(cmdStream, particleBuffer1.getHandle()); + core.recordBufferMemoryBarrier(cmdStream, particleBuffer2.getHandle()); + + + // bloomAndFlares & tonemapping + vkcv::PushConstants pushConstantsDraw (sizeof(renderingMatrices)); + pushConstantsDraw.appendDrawcall(renderingMatrices); + + core.recordDrawcallsToCmdStream( + cmdStream, + particlePass, + particlePipeline, + pushConstantsDraw, + {drawcalls}, + { colorBuffer }, + windowHandle); + + bloomAndFlares.execWholePipeline(cmdStream, colorBuffer); + + core.prepareImageForStorage(cmdStream, colorBuffer); + core.prepareImageForStorage(cmdStream, swapchainInput); + + vkcv::DescriptorWrites tonemappingDescriptorWrites; + tonemappingDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(0, colorBuffer), + vkcv::StorageImageDescriptorWrite(1, swapchainInput) + }; + core.writeDescriptorSet(tonemappingDescriptor, tonemappingDescriptorWrites); + + uint32_t tonemappingDispatchCount[3]; + tonemappingDispatchCount[0] = std::ceil(swapchainExtent.width / 8.f); + tonemappingDispatchCount[1] = std::ceil(swapchainExtent.height / 8.f); + tonemappingDispatchCount[2] = 1; + + core.recordComputeDispatchToCmdStream( + cmdStream, + tonemappingPipe, + tonemappingDispatchCount, + {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptor).vulkanHandle) }, + vkcv::PushConstants(0)); + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + core.endFrame(windowHandle); + } + + return 0; +} diff --git a/projects/voxelization/assets/shaders/depthToMoments.comp b/projects/voxelization/assets/shaders/depthToMoments.comp index 5a78d0cb9b748187d12057708fcd0de7658a61ed..79e47cdef02143ed97d53e533f47e822db8c0f6f 100644 --- a/projects/voxelization/assets/shaders/depthToMoments.comp +++ b/projects/voxelization/assets/shaders/depthToMoments.comp @@ -28,9 +28,11 @@ void main(){ z += texelFetch(sampler2DMS(srcTexture, depthSampler), uv, i).r; } z /= msaaCount; - + z = 2 * z - 1; // algorithm expects depth in range [-1:1] + float z2 = z*z; vec4 moments = vec4(z, z2, z2*z, z2*z2); vec4 momentsQuantized = quantizeMoments(moments); + imageStore(outImage, uv, momentsQuantized); } \ No newline at end of file diff --git a/projects/voxelization/assets/shaders/shadowBlur.inc b/projects/voxelization/assets/shaders/shadowBlur.inc index 06147415f118dca9badd15813b431a68682ce0b0..ed4994ed1ace34afdafff15920d18a2433a3c0a4 100644 --- a/projects/voxelization/assets/shaders/shadowBlur.inc +++ b/projects/voxelization/assets/shaders/shadowBlur.inc @@ -3,7 +3,7 @@ vec4 blurMomentShadowMap1D(ivec2 coord, ivec2 blurDirection, texture2D srcTexture, sampler depthSampler){ - int blurRadius = 9; + int blurRadius = 7; int minOffset = -(blurRadius-1) / 2; int maxOffset = -minOffset; diff --git a/projects/voxelization/assets/shaders/shadowBlurX.comp b/projects/voxelization/assets/shaders/shadowBlurX.comp index 45b91aad71673347dbf607fecef92463ef1c3c88..41d127fdf5ce46dec883d49af4f284b5787d5d38 100644 --- a/projects/voxelization/assets/shaders/shadowBlurX.comp +++ b/projects/voxelization/assets/shaders/shadowBlurX.comp @@ -18,6 +18,6 @@ void main(){ } ivec2 coord = ivec2(gl_GlobalInvocationID.xy); vec4 moments = blurMomentShadowMap1D(coord, ivec2(1, 0), srcTexture, depthSampler); - + // moments = texelFetch(sampler2D(srcTexture, depthSampler), coord, 0); imageStore(outImage, coord, moments); } \ No newline at end of file diff --git a/projects/voxelization/assets/shaders/shadowBlurY.comp b/projects/voxelization/assets/shaders/shadowBlurY.comp index 51d4df054b0d99e54149863a5967143518f61dd2..c1710d7d6c75ef0093fecfe708272f56f9541eaf 100644 --- a/projects/voxelization/assets/shaders/shadowBlurY.comp +++ b/projects/voxelization/assets/shaders/shadowBlurY.comp @@ -16,10 +16,8 @@ void main(){ if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage)))){ return; } - ivec2 coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixelSize = vec2(1) / textureSize(sampler2D(srcTexture, depthSampler), 0); - + ivec2 coord = ivec2(gl_GlobalInvocationID.xy); vec4 moments = blurMomentShadowMap1D(coord, ivec2(0, 1), srcTexture, depthSampler); - + // moments = texelFetch(sampler2D(srcTexture, depthSampler), coord, 0); imageStore(outImage, coord, moments); } \ No newline at end of file diff --git a/projects/voxelization/assets/shaders/shadowMapping.inc b/projects/voxelization/assets/shaders/shadowMapping.inc index c56ae8985c5c5fcef780b622d8b888f1081af74c..9124a05c310c2cc16e6b02802f5adb36bde42804 100644 --- a/projects/voxelization/assets/shaders/shadowMapping.inc +++ b/projects/voxelization/assets/shaders/shadowMapping.inc @@ -6,7 +6,8 @@ // nice math blob from the moment shadow mapping presentation float ComputeMSMShadowIntensity(vec4 _4Moments, float FragmentDepth, float DepthBias, float MomentBias) { - vec4 b=mix(_4Moments, vec4(0.5),MomentBias); + vec4 b=mix(_4Moments, vec4(0, 0.63, 0, 0.63),MomentBias); + vec3 z; z[0]=FragmentDepth-DepthBias; float L32D22=fma(-b[0], b[1], b[2]); @@ -39,24 +40,23 @@ float ComputeMSMShadowIntensity(vec4 _4Moments, float FragmentDepth, float Depth } vec4 quantizeMoments(vec4 moments){ - mat4 T = mat4( - -2.07224649, 13.7948857237, 0.105877704, 9.7924062118, - 32.23703778, -59.4683975703, -1.9077466311, -33.7652110555, - -68.571074599, 82.0359750338, 9.3496555107, 47.9456096605, - 39.3703274134, -35.364903257, -6.6543490743, -23.9728048165); - vec4 quantized = T * moments; - quantized[0] += 0.0359558848; - return quantized; + vec4 quantized; + quantized.r = 1.5 * moments.r - 2 * moments.b + 0.5; + quantized.g = 4 * moments.g - 4 * moments.a; + quantized.b = sqrt(3)/2 * moments.r - sqrt(12)/9 * moments.b + 0.5; + quantized.a = 0.5 * moments.g + 0.5 * moments.a; + + return quantized; } vec4 unquantizeMoments(vec4 moments){ - moments[0] -= 0.0359558848; - mat4 T = mat4( - 0.2227744146, 0.1549679261, 0.1451988946, 0.163127443, - 0.0771972861, 0.1394629426, 0.2120202157, 0.2591432266, - 0.7926986636, 0.7963415838, 0.7258694464, 0.6539092497, - 0.0319417555, -0.1722823173, -0.2758014811, -0.3376131734); - return T * moments; + moments -= vec4(0.5, 0, 0.5, 0); + vec4 unquantized; + unquantized.r = -1.f / 3 * moments.r + sqrt(3) * moments.b; + unquantized.g = 0.125 * moments.g + moments.a; + unquantized.b = -0.75 * moments.r + 0.75 * sqrt(3) * moments.b; + unquantized.a = -0.125 * moments.g + moments.a; + return unquantized / 0.98; // division reduces light bleeding } float rescaleRange(float a, float b, float v) @@ -78,18 +78,20 @@ float shadowTest(vec3 worldPos, LightInfo lightInfo, texture2D shadowMap, sample if(any(lessThan(lightPos.xy, vec2(0))) || any(greaterThan(lightPos.xy, vec2(1)))){ return 1; } - + lightPos.z = clamp(lightPos.z, 0, 1); + lightPos.z = 2 * lightPos.z - 1; // algorithm expects depth in range [-1:1] vec4 shadowMapSample = texture(sampler2D(shadowMap, shadowMapSampler), lightPos.xy); shadowMapSample = unquantizeMoments(shadowMapSample); float depthBias = 0.f; - float momentBias = 0.0003; + float momentBias = 0.0006; float shadow = ComputeMSMShadowIntensity(shadowMapSample, lightPos.z, depthBias, momentBias); - return reduceLightBleeding(shadow, 0.1f); + return clamp(shadow, 0, 1); + // return reduceLightBleeding(shadow, 0.1f); } #endif // #ifndef SHADOW_MAPPING_INC \ No newline at end of file diff --git a/projects/voxelization/src/BloomAndFlares.cpp b/projects/voxelization/src/BloomAndFlares.cpp index d47f61d0dc7fea4e38508b7b1d6c040595e2944a..2014d7a0219141ec6363b38a5311cb924b6b6a45 100644 --- a/projects/voxelization/src/BloomAndFlares.cpp +++ b/projects/voxelization/src/BloomAndFlares.cpp @@ -127,6 +127,8 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre 1 }; + p_Core->recordBeginDebugLabel(cmdStream, "Bloom downsample", { 1, 1, 1, 1 }); + // downsample dispatch of original color attachment p_Core->prepareImageForSampling(cmdStream, colorAttachment); p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); @@ -182,10 +184,14 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre // image barrier between mips p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); } + + p_Core->recordEndDebugLabel(cmdStream); } void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream) { + p_Core->recordBeginDebugLabel(cmdStream, "Bloom upsample", { 1, 1, 1, 1 }); + // upsample dispatch p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); @@ -227,10 +233,14 @@ void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream // image barrier between mips p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); } + + p_Core->recordEndDebugLabel(cmdStream); } void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream) { + p_Core->recordBeginDebugLabel(cmdStream, "Lense flare generation", { 1, 1, 1, 1 }); + // lens feature generation descriptor writes p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); @@ -295,11 +305,15 @@ void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStr // image barrier between mips p_Core->recordImageMemoryBarrier(cmdStream, m_LensFeatures.getHandle()); } + + p_Core->recordEndDebugLabel(cmdStream); } void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle& colorAttachment, const uint32_t attachmentWidth, const uint32_t attachmentHeight, const glm::vec3& cameraForward) { + p_Core->recordBeginDebugLabel(cmdStream, "Bloom/lense flare composition", { 1, 1, 1, 1 }); + p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); p_Core->prepareImageForSampling(cmdStream, m_LensFeatures.getHandle()); p_Core->prepareImageForStorage(cmdStream, colorAttachment); @@ -329,11 +343,13 @@ void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStrea // bloom composite dispatch p_Core->recordComputeDispatchToCmdStream( - cmdStream, - m_CompositePipe, - compositeDispatchCount, - {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)}, - pushConstants); + cmdStream, + m_CompositePipe, + compositeDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)}, + pushConstants); + + p_Core->recordEndDebugLabel(cmdStream); } void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment, diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp index d8041c1e9935d148ded8fb1ca8f0e4d8b79fce71..ce4261ff2403139d10b9d677e7aa216a3e41178f 100644 --- a/projects/voxelization/src/ShadowMapping.cpp +++ b/projects/voxelization/src/ShadowMapping.cpp @@ -266,6 +266,7 @@ void ShadowMapping::recordShadowMapRendering( drawcalls.push_back(vkcv::DrawcallInfo(mesh, {})); } + m_corePtr->recordBeginDebugLabel(cmdStream, "Shadow map depth", {1, 1, 1, 1}); m_corePtr->recordDrawcallsToCmdStream( cmdStream, m_shadowMapPass, @@ -275,6 +276,7 @@ void ShadowMapping::recordShadowMapRendering( { m_shadowMapDepth.getHandle() }, windowHandle); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapDepth.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // depth to moments uint32_t dispatchCount[3]; @@ -287,6 +289,8 @@ void ShadowMapping::recordShadowMapRendering( vkcv::PushConstants msaaPushConstants (sizeof(msaaSampleCount)); msaaPushConstants.appendDrawcall(msaaSampleCount); + m_corePtr->recordBeginDebugLabel(cmdStream, "Depth to moments", { 1, 1, 1, 1 }); + m_corePtr->prepareImageForStorage(cmdStream, m_shadowMap.getHandle()); m_corePtr->recordComputeDispatchToCmdStream( cmdStream, @@ -295,6 +299,9 @@ void ShadowMapping::recordShadowMapRendering( { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_depthToMomentsDescriptorSet).vulkanHandle) }, msaaPushConstants); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); + + m_corePtr->recordBeginDebugLabel(cmdStream, "Moment shadow map blur", { 1, 1, 1, 1 }); // blur X m_corePtr->prepareImageForStorage(cmdStream, m_shadowMapIntermediate.getHandle()); @@ -316,6 +323,8 @@ void ShadowMapping::recordShadowMapRendering( vkcv::PushConstants(0)); m_shadowMap.recordMipChainGeneration(cmdStream); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle()); + + m_corePtr->recordEndDebugLabel(cmdStream); } vkcv::ImageHandle ShadowMapping::getShadowMap() { diff --git a/projects/voxelization/src/ShadowMapping.hpp b/projects/voxelization/src/ShadowMapping.hpp index 7de83b800ce073f5541a889b87a7f0cd763ffa69..3067307b444d4cee18caccaf58a94a13584dc774 100644 --- a/projects/voxelization/src/ShadowMapping.hpp +++ b/projects/voxelization/src/ShadowMapping.hpp @@ -3,6 +3,7 @@ #include <vkcv/camera/Camera.hpp> #include <glm/glm.hpp> +#define GLM_ENABLE_EXPERIMENTAL // use this before inclusion, else error! #include <glm/gtx/transform.hpp> struct LightInfo { diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp index 3cbff0df84757fb370a0372ddd45a9df401d4b60..c023af21c673651984e945ab03d16280c18f0768 100644 --- a/projects/voxelization/src/Voxelization.cpp +++ b/projects/voxelization/src/Voxelization.cpp @@ -251,6 +251,7 @@ void Voxelization::voxelizeMeshes( vkcv::PushConstants voxelCountPushConstants (sizeof(voxelCount)); voxelCountPushConstants.appendDrawcall(voxelCount); + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel reset", { 1, 1, 1, 1 }); m_corePtr->recordComputeDispatchToCmdStream( cmdStream, m_voxelResetPipe, @@ -258,6 +259,7 @@ void Voxelization::voxelizeMeshes( { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).vulkanHandle) }, voxelCountPushConstants); m_corePtr->recordBufferMemoryBarrier(cmdStream, m_voxelBuffer.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // voxelization std::vector<vkcv::DrawcallInfo> drawcalls; @@ -270,6 +272,7 @@ void Voxelization::voxelizeMeshes( },1)); } + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxelization", { 1, 1, 1, 1 }); m_corePtr->prepareImageForStorage(cmdStream, m_voxelImageIntermediate.getHandle()); m_corePtr->recordDrawcallsToCmdStream( cmdStream, @@ -279,6 +282,7 @@ void Voxelization::voxelizeMeshes( drawcalls, { m_dummyRenderTarget.getHandle() }, windowHandle); + m_corePtr->recordEndDebugLabel(cmdStream); // buffer to image const uint32_t bufferToImageGroupSize[3] = { 4, 4, 4 }; @@ -287,6 +291,7 @@ void Voxelization::voxelizeMeshes( bufferToImageDispatchCount[i] = glm::ceil(voxelResolution / float(bufferToImageGroupSize[i])); } + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel buffer to image", { 1, 1, 1, 1 }); m_corePtr->recordComputeDispatchToCmdStream( cmdStream, m_bufferToImagePipe, @@ -295,14 +300,17 @@ void Voxelization::voxelizeMeshes( vkcv::PushConstants(0)); m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImageIntermediate.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // intermediate image mipchain + m_corePtr->recordBeginDebugLabel(cmdStream, "Intermediate Voxel mipmap generation", { 1, 1, 1, 1 }); m_voxelImageIntermediate.recordMipChainGeneration(cmdStream); m_corePtr->prepareImageForSampling(cmdStream, m_voxelImageIntermediate.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // secondary bounce + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel secondary bounce", { 1, 1, 1, 1 }); m_corePtr->prepareImageForStorage(cmdStream, m_voxelImage.getHandle()); - m_corePtr->recordComputeDispatchToCmdStream( cmdStream, m_secondaryBouncePipe, @@ -310,12 +318,14 @@ void Voxelization::voxelizeMeshes( { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_secondaryBounceDescriptorSet).vulkanHandle) }, vkcv::PushConstants(0)); m_voxelImage.recordMipChainGeneration(cmdStream); - m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImage.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); // final image mipchain + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel mipmap generation", { 1, 1, 1, 1 }); m_voxelImage.recordMipChainGeneration(cmdStream); m_corePtr->prepareImageForSampling(cmdStream, m_voxelImage.getHandle()); + m_corePtr->recordEndDebugLabel(cmdStream); } void Voxelization::renderVoxelVisualisation( @@ -344,6 +354,7 @@ void Voxelization::renderVoxelVisualisation( vkcv::Mesh({}, nullptr, drawVoxelCount), { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_visualisationDescriptorSet).vulkanHandle) },1); + m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel visualisation", { 1, 1, 1, 1 }); m_corePtr->prepareImageForStorage(cmdStream, m_voxelImage.getHandle()); m_corePtr->recordDrawcallsToCmdStream( cmdStream, @@ -353,6 +364,7 @@ void Voxelization::renderVoxelVisualisation( { drawcall }, renderTargets, windowHandle); + m_corePtr->recordEndDebugLabel(cmdStream); } void Voxelization::updateVoxelOffset(const vkcv::camera::Camera& camera) { diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index a7798813a52429d31f207ae24af6a3effb90c17c..a4ffb668e74d0a0829bb3c436ed5b992695b6ecf 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -20,8 +20,19 @@ int main(int argc, const char** argv) { vkcv::Features features; features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); - features.requireExtension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); - features.requireExtension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME); + features.tryExtensionFeature<vk::PhysicalDevice16BitStorageFeatures>( + VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, + [](vk::PhysicalDevice16BitStorageFeatures& features) { + features.setStorageBuffer16BitAccess(true); + } + ); + + features.tryExtensionFeature<vk::PhysicalDeviceShaderFloat16Int8Features>( + VK_KHR_16BIT_STORAGE_EXTENSION_NAME, + [](vk::PhysicalDeviceShaderFloat16Int8Features& features) { + features.setShaderFloat16(true); + } + ); const uint32_t windowWidth = 1280; const uint32_t windowHeight = 720; @@ -765,6 +776,7 @@ int main(int argc, const char** argv) { const std::vector<vkcv::ImageHandle> prepassRenderTargets = { depthBuffer }; + core.recordBeginDebugLabel(cmdStream, "Depth prepass", { 1, 1, 1, 1 }); core.recordDrawcallsToCmdStream( cmdStream, prepassPass, @@ -775,6 +787,7 @@ int main(int argc, const char** argv) { windowHandle); core.recordImageMemoryBarrier(cmdStream, depthBuffer); + core.recordEndDebugLabel(cmdStream); vkcv::PushConstants pushConstants (2 * sizeof(glm::mat4)); @@ -791,6 +804,7 @@ int main(int argc, const char** argv) { const std::vector<vkcv::ImageHandle> renderTargets = { colorBuffer, depthBuffer }; + core.recordBeginDebugLabel(cmdStream, "Forward rendering", { 1, 1, 1, 1 }); core.recordDrawcallsToCmdStream( cmdStream, forwardPass, @@ -799,6 +813,7 @@ int main(int argc, const char** argv) { drawcalls, renderTargets, windowHandle); + core.recordEndDebugLabel(cmdStream); if (renderVoxelVis) { voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets, voxelVisualisationMip, windowHandle); @@ -808,6 +823,7 @@ int main(int argc, const char** argv) { skySettingsPushConstants.appendDrawcall(skySettings); // sky + core.recordBeginDebugLabel(cmdStream, "Sky", { 1, 1, 1, 1 }); core.recordDrawcallsToCmdStream( cmdStream, skyPass, @@ -816,6 +832,7 @@ int main(int argc, const char** argv) { { vkcv::DrawcallInfo(vkcv::Mesh({}, nullptr, 3), {}) }, renderTargets, windowHandle); + core.recordEndDebugLabel(cmdStream); const uint32_t fullscreenLocalGroupSize = 8; @@ -832,8 +849,8 @@ int main(int argc, const char** argv) { fulsscreenDispatchCount[2] = 1; if (usingMsaa) { + core.recordBeginDebugLabel(cmdStream, "MSAA resolve", { 1, 1, 1, 1 }); if (msaaCustomResolve) { - core.prepareImageForSampling(cmdStream, colorBuffer); core.prepareImageForStorage(cmdStream, resolvedColorBuffer); @@ -850,6 +867,7 @@ int main(int argc, const char** argv) { else { core.resolveMSAAImage(cmdStream, colorBuffer, resolvedColorBuffer); } + core.recordEndDebugLabel(cmdStream); } bloomFlares.execWholePipeline(cmdStream, resolvedColorBuffer, fsrWidth, fsrHeight, @@ -859,6 +877,7 @@ int main(int argc, const char** argv) { core.prepareImageForStorage(cmdStream, swapBuffer); core.prepareImageForSampling(cmdStream, resolvedColorBuffer); + core.recordBeginDebugLabel(cmdStream, "Tonemapping", { 1, 1, 1, 1 }); core.recordComputeDispatchToCmdStream( cmdStream, tonemappingPipeline, @@ -871,6 +890,7 @@ int main(int argc, const char** argv) { core.prepareImageForStorage(cmdStream, swapBuffer2); core.prepareImageForSampling(cmdStream, swapBuffer); + core.recordEndDebugLabel(cmdStream); if (bilinearUpscaling) { upscaling1.recordUpscaling(cmdStream, swapBuffer, swapBuffer2); @@ -895,6 +915,7 @@ int main(int argc, const char** argv) { glm::ceil(swapchainHeight / static_cast<float>(fullscreenLocalGroupSize)) ); + core.recordBeginDebugLabel(cmdStream, "Post Processing", { 1, 1, 1, 1 }); core.recordComputeDispatchToCmdStream( cmdStream, postEffectsPipeline, @@ -904,6 +925,7 @@ int main(int argc, const char** argv) { ).vulkanHandle) }, timePushConstants ); + core.recordEndDebugLabel(cmdStream); // present and end core.prepareSwapchainImageForPresent(cmdStream); diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index e866693bf203ebb9e45f9de09f26d4e3cb9f4d48..52915ff04800ef3b6cb1e6caefdb3f25f6568aac 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -89,7 +89,7 @@ namespace vkcv { if (type == BufferType::STAGING) { memoryUsage = vma::MemoryUsage::eCpuToGpu; } - + auto bufferAllocation = allocator.createBuffer( vk::BufferCreateInfo(createFlags, size, usageFlags), vma::AllocationCreateInfo( diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index b745914b7734f3e8c2ced4c511144884e12bede6..2f3453f3ff97bd778df8fcfd36d79cc901c867ba 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -272,7 +272,7 @@ namespace vkcv #ifdef __APPLE__ featureManager.useExtension("VK_KHR_portability_subset", true); #endif - + if (featureManager.useExtension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false)) { featureManager.useFeatures<vk::PhysicalDeviceShaderFloat16Int8Features>( [](vk::PhysicalDeviceShaderFloat16Int8Features& features) { @@ -337,7 +337,8 @@ namespace vkcv queuePairsCompute, queuePairsTransfer ); - + + vma::AllocatorCreateFlags vmaFlags; const vma::AllocatorCreateInfo allocatorCreateInfo ( vma::AllocatorCreateFlags(), physicalDevice, diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index a24ed15b1c427b1205f3523439fa27a0bcf757bf..99d27496ba134c75dc555dca18fc26410005ed23 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -52,7 +52,7 @@ namespace vkcv Core::Core(Context &&context, const CommandResources& commandResources, const SyncResources& syncResources) noexcept : m_Context(std::move(context)), m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)}, - m_PipelineManager{std::make_unique<GraphicsPipelineManager>(m_Context.m_Device)}, + m_PipelineManager{std::make_unique<GraphicsPipelineManager>(m_Context.m_Device, m_Context.m_PhysicalDevice)}, m_ComputePipelineManager{std::make_unique<ComputePipelineManager>(m_Context.m_Device)}, m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)), m_BufferManager{std::unique_ptr<BufferManager>(new BufferManager())}, @@ -502,6 +502,50 @@ namespace vkcv recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction); } + + void Core::recordRayGenerationToCmdStream( + CommandStreamHandle cmdStreamHandle, + vk::Pipeline rtxPipeline, + vk::PipelineLayout rtxPipelineLayout, + vk::StridedDeviceAddressRegionKHR rgenRegion, + vk::StridedDeviceAddressRegionKHR rmissRegion, + vk::StridedDeviceAddressRegionKHR rchitRegion, + vk::StridedDeviceAddressRegionKHR rcallRegion, + const std::vector<DescriptorSetUsage>& descriptorSetUsages, + const PushConstants& pushConstants, + const WindowHandle windowHandle) { + + auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eRayTracingKHR, rtxPipeline); + for (const auto& usage : descriptorSetUsages) { + cmdBuffer.bindDescriptorSets( + vk::PipelineBindPoint::eRayTracingKHR, + rtxPipelineLayout, + usage.setLocation, + { usage.vulkanHandle }, + usage.dynamicOffsets + ); + } + + if (pushConstants.getSizePerDrawcall() > 0) { + cmdBuffer.pushConstants( + rtxPipelineLayout, + (vk::ShaderStageFlagBits::eClosestHitKHR | vk::ShaderStageFlagBits::eMissKHR | vk::ShaderStageFlagBits::eRaygenKHR), // TODO: add Support for eAnyHitKHR, eCallableKHR, eIntersectionKHR + 0, + pushConstants.getSizePerDrawcall(), + pushConstants.getData()); + } + + auto m_rtxDispatcher = vk::DispatchLoaderDynamic((PFN_vkGetInstanceProcAddr)m_Context.getInstance().getProcAddr("vkGetInstanceProcAddr")); + m_rtxDispatcher.init(m_Context.getInstance()); + + cmdBuffer.traceRaysKHR(&rgenRegion,&rmissRegion,&rchitRegion,&rcallRegion, + getWindow(windowHandle).getWidth(), getWindow(windowHandle).getHeight(),1, m_rtxDispatcher); + + }; + recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr); + } + void Core::recordComputeDispatchToCmdStream( CommandStreamHandle cmdStreamHandle, ComputePipelineHandle computePipeline, @@ -540,7 +584,7 @@ namespace vkcv void Core::recordBeginDebugLabel(const CommandStreamHandle &cmdStream, const std::string& label, const std::array<float, 4>& color) { -#ifndef NDEBUG + #ifdef VULKAN_DEBUG_LABELS static PFN_vkCmdBeginDebugUtilsLabelEXT beginDebugLabel = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>( m_Context.getDevice().getProcAddr("vkCmdBeginDebugUtilsLabelEXT") ); @@ -559,11 +603,11 @@ namespace vkcv }; recordCommandsToStream(cmdStream, submitFunction, nullptr); -#endif + #endif } void Core::recordEndDebugLabel(const CommandStreamHandle &cmdStream) { -#ifndef NDEBUG + #ifdef VULKAN_DEBUG_LABELS static PFN_vkCmdEndDebugUtilsLabelEXT endDebugLabel = reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>( m_Context.getDevice().getProcAddr("vkCmdEndDebugUtilsLabelEXT") ); @@ -577,7 +621,7 @@ namespace vkcv }; recordCommandsToStream(cmdStream, submitFunction, nullptr); -#endif + #endif } void Core::recordComputeIndirectDispatchToCmdStream( @@ -961,7 +1005,7 @@ namespace vkcv static void setDebugObjectLabel(const vk::Device& device, const vk::ObjectType& type, uint64_t handle, const std::string& label) { -#ifndef NDEBUG +#ifndef VULKAN_DEBUG_LABELS static PFN_vkSetDebugUtilsObjectNameEXT setDebugLabel = reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>( device.getProcAddr("vkSetDebugUtilsObjectNameEXT") ); diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp index 6d73ad17e609c5c431d4398ffb46d3522659341e..6daf221b01d052ef02b5c1376412f7dbd7257861 100644 --- a/src/vkcv/DescriptorManager.cpp +++ b/src/vkcv/DescriptorManager.cpp @@ -15,7 +15,8 @@ namespace vkcv vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000), vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000), vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000), - vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000) + vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000), // for RTX + vk::DescriptorPoolSize(vk::DescriptorType::eAccelerationStructureKHR, 1000) // for RTX }; m_PoolInfo = vk::DescriptorPoolCreateInfo( @@ -92,9 +93,9 @@ namespace vkcv ); //create the descriptor set's layout from the binding data gathered above - vk::DescriptorSetLayout vulkanHandle = VK_NULL_HANDLE; + vk::DescriptorSetLayout vulkanHandle; vk::DescriptorSetLayoutCreateInfo layoutInfo(vk::DescriptorSetLayoutCreateFlags(), bindingsVector); - layoutInfo.setPNext(&bindingFlagsInfo); + layoutInfo.setPNext(&bindingFlagsInfo); auto result = m_Device.createDescriptorSetLayout(&layoutInfo, nullptr, &vulkanHandle); if (result != vk::Result::eSuccess) { @@ -111,7 +112,7 @@ namespace vkcv { //create and allocate the set based on the layout provided DescriptorSetLayout setLayout = m_DescriptorSetLayouts[setLayoutHandle.getId()]; - vk::DescriptorSet vulkanHandle = VK_NULL_HANDLE; + vk::DescriptorSet vulkanHandle; vk::DescriptorSetAllocateInfo allocInfo(m_Pools.back(), 1, &setLayout.vulkanHandle); uint32_t sumVariableDescriptorCounts = 0; diff --git a/src/vkcv/FeatureManager.cpp b/src/vkcv/FeatureManager.cpp index 5fcd129e0b661bf97d196e2a290121f6c5dd364f..c25745fcdd007df86316e0f72bc3d654377baa70 100644 --- a/src/vkcv/FeatureManager.cpp +++ b/src/vkcv/FeatureManager.cpp @@ -157,7 +157,7 @@ m_physicalDevice.getFeatures2(&query) vkcv_check_init_features2(vk::PhysicalDeviceHostQueryResetFeatures); vkcv_check_feature(hostQueryReset); - + return true; } @@ -259,7 +259,7 @@ m_physicalDevice.getFeatures2(&query) vkcv_check_init_features2(vk::PhysicalDeviceUniformBufferStandardLayoutFeatures); vkcv_check_feature(uniformBufferStandardLayout); - + return true; } @@ -292,8 +292,105 @@ m_physicalDevice.getFeatures2(&query) return true; } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceVulkan12Features &features, bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceVulkan12Features); + + vkcv_check_feature(samplerMirrorClampToEdge); + vkcv_check_feature(drawIndirectCount); + vkcv_check_feature(storageBuffer8BitAccess); + vkcv_check_feature(uniformAndStorageBuffer8BitAccess); + vkcv_check_feature(storagePushConstant8); + vkcv_check_feature(shaderBufferInt64Atomics); + vkcv_check_feature(shaderSharedInt64Atomics); + vkcv_check_feature(shaderFloat16); + vkcv_check_feature(shaderInt8); + vkcv_check_feature(descriptorIndexing); + vkcv_check_feature(shaderInputAttachmentArrayDynamicIndexing); + vkcv_check_feature(shaderUniformTexelBufferArrayDynamicIndexing); + vkcv_check_feature(shaderStorageTexelBufferArrayDynamicIndexing); + vkcv_check_feature(shaderUniformBufferArrayNonUniformIndexing); + vkcv_check_feature(shaderSampledImageArrayNonUniformIndexing); + vkcv_check_feature(shaderStorageBufferArrayNonUniformIndexing); + vkcv_check_feature(shaderStorageImageArrayNonUniformIndexing); + vkcv_check_feature(shaderInputAttachmentArrayNonUniformIndexing); + vkcv_check_feature(shaderUniformTexelBufferArrayNonUniformIndexing); + vkcv_check_feature(shaderStorageTexelBufferArrayNonUniformIndexing); + vkcv_check_feature(descriptorBindingUniformBufferUpdateAfterBind); + vkcv_check_feature(descriptorBindingSampledImageUpdateAfterBind); + vkcv_check_feature(descriptorBindingStorageImageUpdateAfterBind); + vkcv_check_feature(descriptorBindingStorageBufferUpdateAfterBind); + vkcv_check_feature(descriptorBindingUniformTexelBufferUpdateAfterBind); + vkcv_check_feature(descriptorBindingStorageTexelBufferUpdateAfterBind); + vkcv_check_feature(descriptorBindingUpdateUnusedWhilePending); + vkcv_check_feature(descriptorBindingPartiallyBound); + vkcv_check_feature(descriptorBindingVariableDescriptorCount); + vkcv_check_feature(runtimeDescriptorArray); + vkcv_check_feature(samplerFilterMinmax); + vkcv_check_feature(scalarBlockLayout); + vkcv_check_feature(imagelessFramebuffer); + vkcv_check_feature(uniformBufferStandardLayout); + vkcv_check_feature(shaderSubgroupExtendedTypes); + vkcv_check_feature(separateDepthStencilLayouts); + vkcv_check_feature(hostQueryReset); + vkcv_check_feature(timelineSemaphore); + vkcv_check_feature(bufferDeviceAddress); + vkcv_check_feature(bufferDeviceAddressCaptureReplay); + vkcv_check_feature(bufferDeviceAddressMultiDevice); + vkcv_check_feature(vulkanMemoryModel); + vkcv_check_feature(vulkanMemoryModelDeviceScope); + vkcv_check_feature(vulkanMemoryModelAvailabilityVisibilityChains); + vkcv_check_feature(shaderOutputViewportIndex); + vkcv_check_feature(shaderOutputLayer); + vkcv_check_feature(subgroupBroadcastDynamicId); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceVulkan11Features &features, bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceVulkan11Features); + + vkcv_check_feature(multiview); + vkcv_check_feature(multiviewGeometryShader); + vkcv_check_feature(multiviewTessellationShader); + vkcv_check_feature(protectedMemory); + vkcv_check_feature(samplerYcbcrConversion); + vkcv_check_feature(shaderDrawParameters); + vkcv_check_feature(storageBuffer16BitAccess); + vkcv_check_feature(storageInputOutput16); + vkcv_check_feature(storagePushConstant16); + vkcv_check_feature(uniformAndStorageBuffer16BitAccess); + vkcv_check_feature(variablePointers); + vkcv_check_feature(variablePointersStorageBuffer); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceAccelerationStructureFeaturesKHR &features, bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceAccelerationStructureFeaturesKHR); + + vkcv_check_feature(accelerationStructure); + vkcv_check_feature(accelerationStructureCaptureReplay); + vkcv_check_feature(accelerationStructureIndirectBuild); + vkcv_check_feature(accelerationStructureHostCommands); + vkcv_check_feature(descriptorBindingAccelerationStructureUpdateAfterBind); + + return true; + } + + bool FeatureManager::checkSupport(const vk::PhysicalDeviceRayTracingPipelineFeaturesKHR &features, bool required) const { + vkcv_check_init_features2(vk::PhysicalDeviceRayTracingPipelineFeaturesKHR); + + vkcv_check_feature(rayTracingPipeline); + vkcv_check_feature(rayTracingPipelineShaderGroupHandleCaptureReplay); + vkcv_check_feature(rayTracingPipelineShaderGroupHandleCaptureReplayMixed); + vkcv_check_feature(rayTracingPipelineTraceRaysIndirect); + vkcv_check_feature(rayTraversalPrimitiveCulling); - vk::BaseOutStructure* FeatureManager::findFeatureStructure(vk::StructureType type) const { + return true; + } + + vk::BaseOutStructure* FeatureManager::findFeatureStructure(vk::StructureType type) const { for (auto& base : m_featuresExtensions) { if (base->sType == type) { return base; diff --git a/src/vkcv/GraphicsPipelineManager.cpp b/src/vkcv/GraphicsPipelineManager.cpp index cb7dd31dddd3a5c0742f95e8429175724aa26454..870220f45b52c022f7c2d445a40e99ab4a6a4a2f 100644 --- a/src/vkcv/GraphicsPipelineManager.cpp +++ b/src/vkcv/GraphicsPipelineManager.cpp @@ -5,8 +5,9 @@ namespace vkcv { - GraphicsPipelineManager::GraphicsPipelineManager(vk::Device device) noexcept : - m_Device{device}, + GraphicsPipelineManager::GraphicsPipelineManager(vk::Device device, vk::PhysicalDevice physicalDevice) noexcept : + m_Device(device), + m_physicalDevice(physicalDevice), m_Pipelines{} {} @@ -237,7 +238,9 @@ namespace vkcv * @param config sets Depth Clamping and Culling Mode * @return Pipeline Rasterization State Create Info Struct */ - vk::PipelineRasterizationStateCreateInfo createPipelineRasterizationStateCreateInfo(const GraphicsPipelineConfig &config) { + vk::PipelineRasterizationStateCreateInfo createPipelineRasterizationStateCreateInfo( + const GraphicsPipelineConfig &config, + const vk::PhysicalDeviceConservativeRasterizationPropertiesEXT& conservativeRasterProperties) { vk::CullModeFlags cullMode; switch (config.m_culling) { case CullMode::None: @@ -267,14 +270,14 @@ namespace vkcv 0.f, 1.f ); - + static vk::PipelineRasterizationConservativeStateCreateInfoEXT conservativeRasterization; if (config.m_UseConservativeRasterization) { conservativeRasterization = vk::PipelineRasterizationConservativeStateCreateInfoEXT( {}, vk::ConservativeRasterizationModeEXT::eOverestimate, - 0.f + std::max(1 - conservativeRasterProperties.primitiveOverestimationSize, 0.f) ); pipelineRasterizationStateCreateInfo.pNext = &conservativeRasterization; @@ -544,8 +547,13 @@ namespace vkcv createPipelineViewportStateCreateInfo(config); // rasterization state + vk::PhysicalDeviceConservativeRasterizationPropertiesEXT conservativeRasterProperties; + vk::PhysicalDeviceProperties deviceProperties; + vk::PhysicalDeviceProperties2 deviceProperties2(deviceProperties); + deviceProperties2.pNext = &conservativeRasterProperties; + m_physicalDevice.getProperties2(&deviceProperties2); vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo = - createPipelineRasterizationStateCreateInfo(config); + createPipelineRasterizationStateCreateInfo(config, conservativeRasterProperties); // multisample state vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = diff --git a/src/vkcv/GraphicsPipelineManager.hpp b/src/vkcv/GraphicsPipelineManager.hpp index a08e64939dc967511095f22862c52de05148d7e9..782603ab0e1ffa9bde05fda96c5d2d259eff1953 100644 --- a/src/vkcv/GraphicsPipelineManager.hpp +++ b/src/vkcv/GraphicsPipelineManager.hpp @@ -20,7 +20,7 @@ namespace vkcv { public: GraphicsPipelineManager() = delete; // no default ctor - explicit GraphicsPipelineManager(vk::Device device) noexcept; // ctor + explicit GraphicsPipelineManager(vk::Device device, vk::PhysicalDevice physicalDevice) noexcept; // ctor ~GraphicsPipelineManager() noexcept; // dtor GraphicsPipelineManager(const GraphicsPipelineManager &other) = delete; // copy-ctor @@ -71,8 +71,9 @@ namespace vkcv GraphicsPipelineConfig m_config; }; - vk::Device m_Device; - std::vector<GraphicsPipeline> m_Pipelines; + vk::Device m_Device; + vk::PhysicalDevice m_physicalDevice; // needed to get infos to configure conservative rasterization + std::vector<GraphicsPipeline> m_Pipelines; void destroyPipelineById(uint64_t id); diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp index f99bd3c609005957469c1f2856b489f7f3e2fd47..504d8fcdbd84935db339370b15c31ccefe26e02b 100644 --- a/src/vkcv/ShaderProgram.cpp +++ b/src/vkcv/ShaderProgram.cpp @@ -315,6 +315,31 @@ namespace vkcv { } } + // Used to reflect acceleration structure bindings for RTX. + for (uint32_t i = 0; i < resources.acceleration_structures.size(); i++) { + auto& u = resources.acceleration_structures[i]; + const spirv_cross::SPIRType& base_type = comp.get_type(u.base_type_id); + + uint32_t setID = comp.get_decoration(u.id, spv::DecorationDescriptorSet); + uint32_t bindingID = comp.get_decoration(u.id, spv::DecorationBinding); + auto binding = DescriptorBinding { + bindingID, + DescriptorType::ACCELERATION_STRUCTURE_KHR, + base_type.vecsize, + shaderStage, + false + }; + + auto insertionResult = m_DescriptorSets[setID].insert(std::make_pair(bindingID, binding)); + if (!insertionResult.second) + { + vkcv_log(LogLevel::WARNING, + "Attempting to overwrite already existing binding %u at set ID %u.", + bindingID, + setID); + } + } + //reflect push constants for (const auto &pushConstantBuffer : resources.push_constant_buffers) {