├── .gitignore ├── .gitmodules ├── AddApplicationProject.cmake ├── AddLibraryProject.cmake ├── CMakeLists.txt ├── GenerateVS2017Solution.bat ├── LICENSE ├── README.md ├── shader ├── Random.hlsl ├── RandomUnitVectorPS.hlsl ├── Screen.h ├── ScreenVS.hlsl ├── Util.hlsl ├── atmosphere │ ├── AddScatteringPS.hlsl │ ├── Atmosphere.h │ ├── AtmosphereConstants.h │ ├── AtmosphericScattering.hlsl.h │ ├── AtmosphericScatteringPS.hlsl │ ├── GatherInscatterPS.hlsl │ ├── MultipleScatteringPS.hlsl │ ├── OpticalDepthPS.hlsl │ ├── PackInscatterPS.hlsl │ ├── SingleScatteringPS.hlsl │ └── TotalInscatterPS.hlsl ├── helloworld │ ├── HelloWorld.h │ ├── OffScreen2dPS.hlsl │ ├── OffScreen3dPS.hlsl │ └── ScreenPS.hlsl └── noise │ ├── TilableNoise2dPS.hlsl │ └── TilableNoise3dPS.hlsl └── src ├── app ├── PrecomputedAtmosphericScattering │ ├── CMakeLists.txt │ ├── Camera.h │ ├── InputEvent.h │ └── main.cpp ├── PureLatticeGaugeModel │ ├── CMakeLists.txt │ └── main.cpp └── helloworld │ ├── CMakeLists.txt │ ├── InputEvent.h │ └── main.cpp ├── lib ├── etc │ ├── CMakeLists.txt │ ├── EventHandler.hpp │ └── dummy.cpp ├── gpu │ ├── CMakeLists.txt │ ├── DirectXUtil.hpp │ ├── FullScreenTriangle.cpp │ ├── FullScreenTriangle.hpp │ ├── GPU.hpp │ ├── GPUExports.hpp │ ├── Render.cpp │ ├── Render.hpp │ ├── TextureIO.cpp │ └── TextureIO.hpp ├── math │ ├── CMakeLists.txt │ ├── Math.hpp │ ├── SO3.hpp │ └── dummy.cpp └── window │ ├── CMakeLists.txt │ ├── Log.cpp │ ├── Log.hpp │ ├── Window.cpp │ ├── Window.hpp │ └── WindowExport.hpp ├── test └── lib │ └── math │ ├── CMakeLists.txt │ └── main.cpp └── thirdparty └── imgui └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Temporary directories 2 | _build/ 3 | renderdoc/ 4 | 5 | # Configuration files 6 | *.ini 7 | 8 | # Prerequisites 9 | *.d 10 | 11 | # Compiled Object files 12 | *.slo 13 | *.lo 14 | *.o 15 | *.obj 16 | 17 | # Precompiled Headers 18 | *.gch 19 | *.pch 20 | 21 | # Compiled Dynamic libraries 22 | *.so 23 | *.dylib 24 | *.dll 25 | 26 | # Fortran module files 27 | *.mod 28 | *.smod 29 | 30 | # Compiled Static libraries 31 | *.lai 32 | *.la 33 | *.a 34 | *.lib 35 | 36 | # Executables 37 | *.exe 38 | *.out 39 | *.app 40 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/thirdparty/imgui"] 2 | path = src/thirdparty/imgui 3 | url = https://github.com/ocornut/imgui.git 4 | [submodule "src/thirdparty/imgui/imgui"] 5 | path = src/thirdparty/imgui/imgui 6 | url = https://github.com/ocornut/imgui.git 7 | -------------------------------------------------------------------------------- /AddApplicationProject.cmake: -------------------------------------------------------------------------------- 1 | function(AddApplicationProject inProjectName) 2 | # Collect sources 3 | file (GLOB sources "*.h" "*.cpp") 4 | 5 | source_group("" FILES ${sources}) 6 | 7 | # Properties->C/C++->General->Additional Include Directories 8 | include_directories ("${PROJECT_SOURCE_DIR}") 9 | 10 | # Set Properties->General->Configuration Type 11 | add_executable (${inProjectName} ${sources}) 12 | 13 | # Creates a folder "app" and adds target project (${inProjectName}.vcproj) under it 14 | set_property(TARGET ${inProjectName} PROPERTY FOLDER "app") 15 | 16 | # Properties->General->Output Directory 17 | set_target_properties(${inProjectName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) 18 | 19 | # Properties -> Debugging -> Working Directorty 20 | set_target_properties(${inProjectName} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") 21 | 22 | # Adds logic to INSTALL.vcproj to copy node.exe to destination directory 23 | install (TARGETS ${inProjectName} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/_install) 24 | endfunction() 25 | -------------------------------------------------------------------------------- /AddLibraryProject.cmake: -------------------------------------------------------------------------------- 1 | function(AddLibraryProject inProjectName) 2 | # Collect sources 3 | file (GLOB sources "*.cpp" "*.hpp") 4 | 5 | source_group("" FILES ${sources}) 6 | 7 | # Properties->C/C++->General->Additional Include Directories 8 | include_directories (.) 9 | 10 | # Properties->General->Configuration Type 11 | if (build_shared_libs) 12 | add_definitions(-DBUILD_SHARED_LIBS) 13 | add_library(${inProjectName} SHARED ${sources}) 14 | else (build_shared_libs) 15 | add_library(${inProjectName} STATIC ${sources}) 16 | endif (build_shared_libs) 17 | 18 | # Creates a folder "lib" and adds target project under it 19 | set_property(TARGET ${inProjectName} PROPERTY FOLDER "lib") 20 | 21 | # Properties->General->Output Directory 22 | set_target_properties(${inProjectName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) 23 | 24 | if (build_shared_libs) 25 | # Adds logic to INSTALL.vcproj to copy ${inProjectName}.dll to the destination directory 26 | install (TARGETS ${inProjectName} 27 | RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/_install 28 | LIBRARY DESTINATION ${PROJECT_SOURCE_DIR}/_install) 29 | endif (build_shared_libs) 30 | endfunction() 31 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # References 2 | # * The Ultimate Guide to Modern CMake, https://rix0r.nl/blog/2015/08/13/cmake-guide/ 3 | # * CMAKE AND VISUAL STUDIO, https://cognitivewaves.wordpress.com/cmake-and-visual-studio/ 4 | cmake_minimum_required (VERSION 3.9) 5 | 6 | # test 7 | include(./AddApplicationProject.cmake) 8 | include(./AddLibraryProject.cmake) 9 | 10 | set(CMAKE_CXX_STANDARD 17) 11 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 12 | if(MSVC) 13 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17") 14 | endif(MSVC) 15 | 16 | # Select if dynamic or static libraries are built 17 | option (build_shared_libs "Build Shared Libraries" OFF) 18 | 19 | # Maps to a solution file (ToyModels.sln) 20 | project (ToyModels) 21 | 22 | # Turn on the ability to create folders to organize projects (.vcproj) 23 | # It creates "CMakePredefinedTargets" folder by default and adds CMake defined projects like INSTALL.vcproj and ZERO_CHECK.vcproj 24 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 25 | 26 | # Set compiler flags and options. 27 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") 28 | 29 | # Command to output information to the console. Useful for displaying errors, warnings, and debugging 30 | message ("cxx Flags: " ${CMAKE_CXX_FLAGS}) 31 | 32 | # Sub-directories where more CMakeLists.txt exist 33 | add_subdirectory(src/app/helloworld) 34 | add_subdirectory(src/app/PrecomputedAtmosphericScattering) 35 | add_subdirectory(src/app/PureLatticeGaugeModel) 36 | add_subdirectory(src/lib/etc) 37 | add_subdirectory(src/lib/math) 38 | add_subdirectory(src/lib/window) 39 | add_subdirectory(src/lib/gpu) 40 | add_subdirectory(src/thirdparty/imgui) 41 | 42 | if(MSVC) 43 | # Set the startup project 44 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT helloworld) 45 | endif() 46 | 47 | # Turn on CMake testing capabilities 48 | enable_testing() 49 | add_subdirectory(src/test/lib/math) 50 | -------------------------------------------------------------------------------- /GenerateVS2017Solution.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | cd %~dp0 4 | 5 | set target_dir=_build 6 | 7 | if exist "%target_dir%" ( 8 | rmdir /s /q %target_dir% 9 | ) 10 | 11 | mkdir %target_dir% 12 | cd %target_dir% 13 | cmake .. -G "Visual Studio 15 2017" 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 k-ishiyama 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Toymodels 2 | ------------ 3 | A personal repository for physics simulation. 4 | 5 | ``` 6 | src/ 7 | app/ 8 | helloworld/ 9 | PrecomputedAtmosphericScattering/ 10 | PureLatticeGaugeModel/ 11 | lib/ 12 | etc/ 13 | gpu/ 14 | math/ 15 | window/ 16 | test/ 17 | .. 18 | thirdparty/ 19 | imgui/ 20 | shader/ 21 | .. 22 | ``` 23 | 24 | How to generate the build projects 25 | ------------ 26 | #### Windows, Visual Studio 2017 27 | mkdir _build 28 | cd _build 29 | cmake .. -G "Visual Studio 15 2017" 30 | 31 | 45 | -------------------------------------------------------------------------------- /shader/Random.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef RANDOM_HLSL 2 | #define RANDOM_HLSL 3 | 4 | // https://www.shadertoy.com/view/4dlcR4 5 | #define W uint2(0x3504f335u, 0x8fc1ecd5u) 6 | #define M 741103597u 7 | uint hash(uint2 x) 8 | { 9 | x *= W; // x' = Fx(x), y' = Fy(y) 10 | x.x ^= x.y; // combine 11 | x.x *= M; // MLCG constant 12 | return x.x; 13 | } 14 | 15 | float Hash31(float3 n) 16 | { 17 | return frac(sin(dot(n, float3(12.9898, 4.1414, 2.23620679))) * 43758.5453); 18 | } 19 | 20 | // https://www.shadertoy.com/view/4djSRW 21 | #define HASHSCALE3 float3(.1031, .1030, .0973) 22 | float2 Hash22(float2 p) 23 | { 24 | float3 p3 = frac(p.xyx * HASHSCALE3); 25 | p3 += dot(p3, p3.yzx+19.19); 26 | return frac((p3.xx+p3.yz)*p3.zy); 27 | } 28 | 29 | float2 Hash21(float p) 30 | { 31 | float3 p3 = frac(float3(p, p, p) * HASHSCALE3); 32 | p3 += dot(p3, p3.yzx + 19.19); 33 | return frac((p3.xx+p3.yz)*p3.zy); 34 | 35 | } 36 | 37 | float3 RandomUnitVector(float2 p) 38 | { 39 | float2 random = Hash22(p); 40 | float z = random.x * 2.0 - 1.0; 41 | float t = random.y * 3.14159265; 42 | float r = sqrt(1.0 - z * z); 43 | float x = r * cos(t); 44 | float y = r * sin(t); 45 | return float3(x, y, z); 46 | } 47 | 48 | #endif // RANDOM_HLSL 49 | -------------------------------------------------------------------------------- /shader/RandomUnitVectorPS.hlsl: -------------------------------------------------------------------------------- 1 | // Ref: https://www.shadertoy.com/view/4djSRW 2 | #define HASHSCALE3 float3(443.897, 441.423, 437.195) 3 | float2 hash21(float p) 4 | { 5 | float3 p3 = frac(float3(p,p,p) * HASHSCALE3); 6 | p3 += dot(p3, p3.yzx + 19.19); 7 | return frac((p3.xx+p3.yz)*p3.zy); 8 | } 9 | 10 | //=============================================== 11 | 12 | float4 Entry(float4 Pos : SV_POSITION, float2 uv : TexCoord) : SV_Target 13 | { 14 | float4 outColor = float4(0.0, 0.0, 0.0, 1.0); 15 | float2 random = hash21(uv.x); 16 | 17 | float z = random.x * 2.0 - 1.0; 18 | float t = random.y * 3.14159265; 19 | float r = sqrt(1.0 - z * z); 20 | float x = r * cos(t); 21 | float y = r * sin(t); 22 | 23 | outColor.xyz = float3(x, y, z); 24 | return outColor; 25 | } 26 | -------------------------------------------------------------------------------- /shader/Screen.h: -------------------------------------------------------------------------------- 1 | #ifndef SCREEN_H 2 | #define SCREEN_H 3 | 4 | #define M_PI 3.14159265 5 | 6 | //-------------------------------------------------- 7 | 8 | struct ConstantBufferParam 9 | { 10 | float4 mFloat4[16]; 11 | }; 12 | 13 | cbuffer cbConstantBufferParam : register(b0) 14 | { 15 | ConstantBufferParam gCBParam; 16 | } 17 | 18 | float4 GetParam(const int index) { return gCBParam.mFloat4[index]; } 19 | 20 | // following functions will be deprecated 21 | float GetElapsedTime() { return GetParam(0).x; } 22 | float2 GetScreenResolution() { return GetParam(0).yz; } 23 | 24 | //-------------------------------------------------- 25 | 26 | struct Tex3DShaderParams 27 | { 28 | float2 mWQ; 29 | uint mDepthSlice; 30 | float mPadding; 31 | }; 32 | 33 | cbuffer cbConstantBufferParam : register(b1) 34 | { 35 | Tex3DShaderParams gTex3dParam; 36 | } 37 | 38 | float2 GetWQ() { return gTex3dParam.mWQ; } 39 | float GetCurrentDepth() { return GetWQ().x; } 40 | uint GetDepthSlice() { return gTex3dParam.mDepthSlice; } 41 | 42 | //-------------------------------------------------- 43 | 44 | SamplerState SamplerLinearClamp : register(s0) 45 | { 46 | Filter = MIN_MAG_MIP_LINEAR; 47 | AddressU = Clamp; 48 | AddressV = Clamp; 49 | }; 50 | 51 | SamplerState SamplerLinearWrap : register(s1) 52 | { 53 | Filter = MIN_MAG_MIP_LINEAR; 54 | AddressU = Wrap; 55 | AddressV = Wrap; 56 | }; 57 | 58 | //-------------------------------------------------- 59 | 60 | #endif // SCREEN_H 61 | -------------------------------------------------------------------------------- /shader/ScreenVS.hlsl: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // Vertex Shader 3 | // http://altdevblog.com/2011/08/08/an-interesting-vertex-shader-trick/ 4 | //-------------------------------------------------------------------------------------- 5 | struct VSQuadOut 6 | { 7 | float4 position : SV_Position; 8 | float2 texcoord: TexCoord; 9 | }; 10 | 11 | VSQuadOut Entry(uint id: SV_VertexID) 12 | { 13 | VSQuadOut Out; 14 | // full screen quad with texture coords 15 | Out.texcoord = float2((id << 1) & 2, id & 2); 16 | Out.position = float4(Out.texcoord * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f); 17 | return Out; 18 | } 19 | -------------------------------------------------------------------------------- /shader/Util.hlsl: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_HLSL 2 | #define UTIL_HLSL 3 | 4 | //------------------------------------------------------------------------- 5 | float3 UVToDirection(float2 inUV) 6 | { 7 | float2 st = (inUV * 2.0 - float2(1.0, 1.0)) * float2(3.14159265, 0.5 * 3.14159265); 8 | return float3(cos(st.y) * cos(st.x), sin(st.y), cos(st.y) * sin(st.x)); 9 | } 10 | 11 | float2 DirectionToUV(float3 inDir) 12 | { 13 | return float2(atan2(inDir.z, inDir.x) / (2.0 * 3.14159265) + 0.5, 1.0 - acos(inDir.y) / 3.14159265); 14 | } 15 | 16 | //--------------------------------------------------------------------------------- 17 | 18 | float3 UVToOmniDirection( 19 | float2 inClipPos // ([-1, 1], [-1, 1]) 20 | ) 21 | { 22 | float3 outViewDir = float3(0.0, 0.0, 1.0); 23 | float z2 = inClipPos.x * inClipPos.x + inClipPos.y * inClipPos.y; 24 | if (z2 <= 1.0) 25 | { 26 | float t = acos(1.0 - z2); 27 | float s = atan2(inClipPos.y, inClipPos.x); 28 | outViewDir = -float3( sin(t) * cos(s), cos(t), sin(t) * sin(s)); 29 | } 30 | return outViewDir; 31 | } 32 | 33 | float3 UVToViewDirection( 34 | float2 inClipPos, 35 | float3x3 inCameraMatrix 36 | ) 37 | { 38 | float3 dir = normalize(float3(inClipPos, 2.0)); 39 | return mul(inCameraMatrix, dir); 40 | } 41 | 42 | #if 0 43 | float3 UVToViewDirection( 44 | float2 inClipPos, // [-1,1] 45 | float3x3 inSO3, 46 | float inFoV // [rad] 47 | ) 48 | { 49 | float3 dir = normalize(float3(inClipPos, tan(inFoV))); 50 | return mul(inSO3, dir); 51 | } 52 | #endif 53 | 54 | //-------------------------------------------------------------------------------- 55 | 56 | void DebugDrawTexture2D(inout float4 ioColor, Texture2D inTexture, SamplerState inSampler, float2 inUV, float2 inPos, float2 inSize) 57 | { 58 | float right = inPos.x + inSize.x; 59 | float bottom = inPos.y + inSize.y; 60 | if (inUV.x >= inPos.x && inUV.x < right && inUV.y >= inPos.y && inUV.y < bottom) 61 | { 62 | float2 tex_uv = (inUV - inPos) / inSize; 63 | ioColor = inTexture.SampleLevel(inSampler, tex_uv, 0); 64 | } 65 | } 66 | 67 | void DebugDrawTexture3D(inout float4 ioColor, Texture3D inTexture, SamplerState inSampler, float2 inUV, float2 inPos, float2 inSize) 68 | { 69 | float right = inPos.x + inSize.x; 70 | float bottom = inPos.y + inSize.y; 71 | if (inUV.x >= inPos.x && inUV.x < right && inUV.y >= inPos.y && inUV.y < bottom) 72 | { 73 | float3 size; 74 | inTexture.GetDimensions(size.x, size.y, size.z); 75 | 76 | float2 tex_uv = (inUV - inPos) / inSize; 77 | float3 tex_uvw = float3(frac(tex_uv.x * size.z), tex_uv.y, floor(tex_uv.x * size.z) / size.z); 78 | ioColor = inTexture.SampleLevel(inSampler, tex_uvw, 0); 79 | } 80 | } 81 | 82 | #endif // UTIL_HLSL 83 | -------------------------------------------------------------------------------- /shader/atmosphere/AddScatteringPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "Atmosphere.h" 2 | #include "AtmosphereConstants.h" 3 | #include "AtmosphericScattering.hlsl.h" 4 | #include "../Random.hlsl" 5 | 6 | Texture3D gTexture3Da : register(t4); 7 | Texture3D gTexture3Db : register(t5); 8 | 9 | struct PSOutput 10 | { 11 | float4 outColor0 : SV_Target0; 12 | float4 outColor1 : SV_Target1; 13 | }; 14 | 15 | PSOutput Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 16 | { 17 | PSOutput o; 18 | const uint slice = GetDepthSlice(); 19 | o.outColor0 = gTexture3Da.Load(uint4(inPosition.xy, slice, 0)); 20 | o.outColor1 = gTexture3Db.Load(uint4(inPosition.xy, slice, 0)); 21 | return o; 22 | } 23 | -------------------------------------------------------------------------------- /shader/atmosphere/Atmosphere.h: -------------------------------------------------------------------------------- 1 | #ifndef ATMOSPHERE_H 2 | #define ATMOSPHERE_H 3 | 4 | #include "../Screen.h" 5 | 6 | #endif // ATMOSPHERE_H 7 | -------------------------------------------------------------------------------- /shader/atmosphere/AtmosphereConstants.h: -------------------------------------------------------------------------------- 1 | #ifndef ATMOSPHERE_CONSTANTS_H 2 | #define ATMOSPHERE_CONSTANTS_H 3 | 4 | #ifdef __cplusplus 5 | #include 6 | using float2 = math::Vector2; 7 | using float3 = math::Vector3; 8 | using float4 = math::Vector4; 9 | #endif // __cplusplus 10 | 11 | #define EARTH_RADIUS 6360.f // [km] 12 | #define ATM_TOP_HEIGHT 260.f // [km] 13 | #define ATM_TOP_RADIUS (EARTH_RADIUS + ATM_TOP_HEIGHT) 14 | #define INSCATTER_INTEGRAL_STEPS 512 15 | #define EARTH_CENTER float3(0,-EARTH_RADIUS,0) 16 | #define LUT_HEIGHT_MARGIN 0.004 // [km] 17 | 18 | #if 0 19 | // Low quality 20 | #define TEX4D_U 4 21 | #define TEX4D_V 64 22 | #define TEX4D_W 8 23 | #else 24 | // High quality 25 | #define TEX4D_U 12 // height 26 | #define TEX4D_V 96 // view zenith 27 | #define TEX4D_W 24 // sun zenith 28 | #endif 29 | 30 | struct PrecomputedSctrParams 31 | { 32 | float3 mRayleighSctrCoeff; // [nm^{-1}] 33 | float mRayleighScaleHeight; // [km] 34 | 35 | float3 mMieSctrCoeff; // [nm^{-1}] 36 | float mMieScaleHeight; // [km] 37 | 38 | float mMieAbsorption; // [-] 39 | float3 mPadding; 40 | 41 | #ifdef __cplusplus 42 | PrecomputedSctrParams() 43 | : mRayleighSctrCoeff(5.78f, 13.6f, 33.1f) 44 | , mRayleighScaleHeight(7.997f) 45 | , mMieSctrCoeff(20.0f, 20.0f, 20.0f) 46 | , mMieScaleHeight(3.0f) 47 | , mMieAbsorption(1.11f) 48 | {} 49 | #endif // __cplusplus 50 | }; 51 | #ifdef __cplusplus 52 | static_assert(sizeof(PrecomputedSctrParams) % 16 == 0, "sizeof(""PrecomputedSctrParams"") is not multiple of 16"); 53 | #else 54 | cbuffer cbPrecomputedSctrParams : register(b1) 55 | { 56 | PrecomputedSctrParams gCBPrecomputedSctrParams; 57 | } 58 | #endif 59 | 60 | 61 | struct RuntimeSctrParams 62 | { 63 | float mMieAsymmetry; // [-] 64 | float3 mPadding; 65 | 66 | #ifdef __cplusplus 67 | RuntimeSctrParams() 68 | : mMieAsymmetry(0.76f) 69 | {} 70 | #endif // __cplusplus 71 | }; 72 | #ifdef __cplusplus 73 | static_assert(sizeof(RuntimeSctrParams) % 16 == 0, "sizeof(""RuntimeSctrParams"") is not multiple of 16"); 74 | #else 75 | cbuffer cbRuntimeSctrParams : register(b2) 76 | { 77 | RuntimeSctrParams gCBRuntimeSctrParams; 78 | } 79 | #endif 80 | 81 | #endif // ATMOSPHERE_CONSTANTS_H 82 | -------------------------------------------------------------------------------- /shader/atmosphere/AtmosphericScattering.hlsl.h: -------------------------------------------------------------------------------- 1 | #ifndef ATMOSPHERIC_SCATTERING_H 2 | #define ATMOSPHERIC_SCATTERING_H 3 | 4 | //------------------------------------------------------ 5 | // Precomputed atmospheric scattering 6 | // 7 | // References 8 | // [Bruneton08] Bruneton, E., Neyret, F. "Precomputed atmospheric scattering", Proc. of EGSR'08, Vol 27, no 4, pp. 1079--1086 (2008) 9 | // [Elek09] Elek, O. "Rendering Parametrizable Planetary Atmosphere with Multiple Scattering in Real-Time", CESCG 2009. (2009) 10 | // [Yusov13] Yusov, E. "Outdoor Light Scattering Sample Update", https://software.intel.com/en-us/blogs/2013/09/19/otdoor-light-scattering-sample-update, (2013) 11 | // [Hillaire16] Hillaire, S. "Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite", SIGGRAPH 2016. (2016) 12 | //------------------------------------------------------ 13 | 14 | //------------------------------------------------------ 15 | // Intersection tests 16 | //------------------------------------------------------ 17 | float4 RayDoubleSphereIntersect( 18 | in float3 inRayOrigin, 19 | in float3 inRayDir, 20 | in float2 inSphereRadii // x = 1st sphere, y = 2nd sphere 21 | ) 22 | { 23 | float a = dot(inRayDir, inRayDir); 24 | float b = 2.0 * dot(inRayOrigin, inRayDir); 25 | float2 c = dot(inRayOrigin, inRayOrigin) - inSphereRadii * inSphereRadii; 26 | float2 d = b*b - 4.0 * a*c; 27 | // d < 0 .. Ray misses the sphere 28 | // d = 0 .. Ray intersects the sphere in one point 29 | // d > 0 .. Ray intersects the sphere in two points 30 | float2 real_root_mask = (d.xy >= 0.0); 31 | d = sqrt(max(d, 0.0)); 32 | float4 distance = float4(-b - d.x, -b + d.x, -b - d.y, -b + d.y) / (2.0 * a); 33 | distance = lerp(float4(-1.0, -1.0, -1.0, -1.0), distance, real_root_mask.xxyy); 34 | // distance.x = distance to the intersection point of the 1st sphere (near side) 35 | // distance.y = distance to the intersection point of the 1st sphere (far side) 36 | // distance.z = distance to the intersection point of the 2nd sphere (near side) 37 | // distance.w = distance to the intersection point of the 2nd sphere (far side) 38 | return distance; 39 | } 40 | 41 | //------------------------------------------------------ 42 | // [Bruneton09] 43 | //------------------------------------------------------ 44 | float3 UnpackMieInscatter(float4 inRayleighMie, float3 inRayleighScatteringCoeff) 45 | { 46 | return inRayleighMie.xyz * inRayleighMie.w / max(inRayleighMie.x, 1e-9) * (inRayleighScatteringCoeff.x / inRayleighScatteringCoeff); 47 | } 48 | 49 | float4 PackInscatter(float3 inRayleigh, float3 inMie) 50 | { 51 | return float4(inRayleigh.xyz, inMie.x); 52 | } 53 | 54 | //------------------------------------------------------ 55 | // 3d LookUpTable parametrization [Yusov13] 56 | //------------------------------------------------------ 57 | #define LUT_RESOLUTION float3(TEX4D_U, TEX4D_V, TEX4D_W) 58 | 59 | float3 ComputeViewDir(in float cosViewZenith) 60 | { 61 | return float3(sqrt(saturate(1.0 - cosViewZenith * cosViewZenith)), cosViewZenith, 0.0); 62 | } 63 | 64 | float3 ComputeLightDir(in float3 inViewDir, in float cosLightZenith) 65 | { 66 | float3 light_dir; 67 | light_dir.x = (inViewDir.x > 0) ? (1. - cosLightZenith * inViewDir.y) / inViewDir.x : 0; 68 | light_dir.y = cosLightZenith; 69 | light_dir.z = sqrt(saturate(1 - dot(light_dir.xy, light_dir.xy))); 70 | //light_dir = normalize(light_dir); // Do not normalize light_dir [Yusov13] 71 | return light_dir; 72 | } 73 | 74 | float GetCosHorizonAngle(float height) 75 | { 76 | // Due to numeric precision issues, height might sometimes be slightly negative [Yusov13] 77 | height = max(height, 0); 78 | return -sqrt(height * (2 * EARTH_RADIUS + height)) / (EARTH_RADIUS + height); 79 | } 80 | 81 | float ZenithAngle2TexCoord(float inCosZenith, float inHeight, in float inTextureResolution) 82 | { 83 | float prev_tex_coord = 1; 84 | float tex_coord; 85 | float cos_horizon = GetCosHorizonAngle(inHeight); 86 | // When performing look-ups into the scattering texture, it is very important that all the look-ups are consistent 87 | // wrt to the horizon. This means that if the first look-up is above (below) horizon, then the second look-up 88 | // should also be above (below) horizon. 89 | // We use previous texture coordinate, if it is provided, to find out if previous look-up was above or below 90 | // horizon. If texture coordinate is negative, then this is the first look-up 91 | float offset; 92 | if (inCosZenith > cos_horizon) 93 | { 94 | // Scale to [0,1] 95 | tex_coord = saturate((inCosZenith - cos_horizon) / (1.0 - cos_horizon)); 96 | tex_coord = sqrt(sqrt(tex_coord)); 97 | 98 | offset = 0.5; 99 | // Now remap texture coordinate to the upper half of the texture. 100 | // To avoid filtering across discontinuity at 0.5, we must map 101 | // the texture coordinate to [0.5 + 0.5/inTextureResolution, 1 - 0.5/inTextureResolution] 102 | // 103 | // 0.5 1.5 D/2+0.5 D-0.5 texture coordinate x dimension 104 | // | | | | 105 | // | X | X | .... | X || X | .... | X | 106 | // 0 1 D/2-1 D/2 D-1 texel index 107 | // 108 | tex_coord = offset + 0.5 / inTextureResolution + tex_coord * (inTextureResolution / 2.0 - 1.0) / inTextureResolution; 109 | } 110 | else 111 | { 112 | tex_coord = saturate((cos_horizon - inCosZenith) / (cos_horizon - (-1))); 113 | tex_coord = sqrt(sqrt(tex_coord)); 114 | 115 | offset = 0.0; 116 | // Now remap texture coordinate to the lower half of the texture. 117 | // To avoid filtering across discontinuity at 0.5, we must map 118 | // the texture coordinate to [0.5, 0.5 - 0.5/inTextureResolution] 119 | // 120 | // 0.5 1.5 D/2-0.5 texture coordinate x dimension 121 | // | | | 122 | // | X | X | .... | X || X | .... 123 | // 0 1 D/2-1 D/2 texel index 124 | // 125 | tex_coord = offset + 0.5 / inTextureResolution + tex_coord * (inTextureResolution / 2.0 - 1.0) / inTextureResolution; 126 | } 127 | 128 | return tex_coord; 129 | } 130 | 131 | float TexCoord2ZenithAngle(float inTexcoord, float inHeight, in float inTextureResolution) 132 | { 133 | float cos_zenith; 134 | float cos_horizon = GetCosHorizonAngle(inHeight); 135 | [flatten] if (inTexcoord > 0.5) 136 | { 137 | // Remap to [0,1] from the upper half of the texture [0.5 + 0.5/inTextureResolution, 1 - 0.5/inTextureResolution] 138 | inTexcoord = saturate((inTexcoord - (0.5 + 0.5 / inTextureResolution)) * inTextureResolution / (inTextureResolution / 2.0 - 1.0)); 139 | inTexcoord *= inTexcoord; 140 | inTexcoord *= inTexcoord; 141 | // Assure that the ray does NOT hit Earth 142 | cos_zenith = max((cos_horizon + inTexcoord * (1.0 - cos_horizon)), cos_horizon + 1e-4); 143 | } 144 | else 145 | { 146 | // Remap to [0,1] from the lower half of the texture [0.5, 0.5 - 0.5/inTextureResolution] 147 | inTexcoord = saturate((inTexcoord - 0.5 / inTextureResolution) * inTextureResolution / (inTextureResolution / 2.0 - 1.0)); 148 | inTexcoord *= inTexcoord; 149 | inTexcoord *= inTexcoord; 150 | // Assure that the ray DOES hit Earth 151 | cos_zenith = min((cos_horizon - inTexcoord * (1.0 + cos_horizon)), cos_horizon - 1e-4); 152 | } 153 | return cos_zenith; 154 | } 155 | 156 | float3 WorldCoordToLUTCoord( 157 | float inHeight, 158 | float inCosViewZenith, 159 | float inCosLightZenith 160 | ) 161 | { 162 | float3 uvw; 163 | float height = clamp(inHeight, LUT_HEIGHT_MARGIN, ATM_TOP_HEIGHT - LUT_HEIGHT_MARGIN); 164 | uvw.z = saturate((height - LUT_HEIGHT_MARGIN) / (ATM_TOP_HEIGHT - 2.0 * LUT_HEIGHT_MARGIN)); 165 | uvw.z = sqrt(uvw.z); 166 | uvw.y = ZenithAngle2TexCoord(inCosViewZenith, height, LUT_RESOLUTION.y); 167 | uvw.x = (atan(max(inCosLightZenith, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5; // Bruneton's formula [Bruneton09] 168 | uvw.xz = ((uvw * (LUT_RESOLUTION - 1.0) + 0.5) / LUT_RESOLUTION).xz; 169 | return uvw; 170 | } 171 | 172 | void LUTCoordToWorldCoord( 173 | in float3 inUVW, 174 | out float outHeight, 175 | out float outCosViewZenith, 176 | out float outCosLightZenith 177 | ) 178 | { 179 | // Rescale to exactly 0,1 range 180 | inUVW.xz = saturate((inUVW* LUT_RESOLUTION - 0.5) / (LUT_RESOLUTION - 1.0)).xz; 181 | inUVW.z = inUVW.z * inUVW.z; 182 | outHeight = inUVW.z * (ATM_TOP_HEIGHT - 2.0 * LUT_HEIGHT_MARGIN) + LUT_HEIGHT_MARGIN; 183 | outCosViewZenith = TexCoord2ZenithAngle(inUVW.y, outHeight, LUT_RESOLUTION.y); 184 | outCosLightZenith = tan((2.0 * inUVW.x - 1.0 + 0.26) * 1.1) / tan(1.26 * 1.1); // Bruneton's formula [Bruneton09] 185 | } 186 | 187 | float4 SamplePrecomputedTexture( 188 | float3 inStartPos, 189 | float3 inViewDir, 190 | float3 inLightDir, 191 | in Texture3D inTexture3d, 192 | in SamplerState inSampler) 193 | { 194 | float3 dir = inStartPos - EARTH_CENTER; 195 | float dist = length(dir); 196 | dir /= dist; 197 | float height = dist - EARTH_RADIUS; 198 | float cos_view_zenith = dot(dir, inViewDir); 199 | float cos_light_zenith = dot(dir, inLightDir); 200 | 201 | float3 uvw = WorldCoordToLUTCoord(height, cos_view_zenith, cos_light_zenith); 202 | return inTexture3d.SampleLevel(inSampler, uvw, 0); 203 | } 204 | 205 | void LookUpPrecomputedScatteringPacked( 206 | float3 inStartPos, 207 | float3 inViewDir, 208 | float3 inLightDir, 209 | float3 inBetaR, 210 | in Texture3D inPackedInscatterTexture, 211 | in SamplerState inSampler, 212 | out float3 outInscatterR, 213 | out float3 outInscatterM 214 | ) 215 | { 216 | float4 packed_inscatter = SamplePrecomputedTexture(inStartPos, inViewDir, inLightDir, inPackedInscatterTexture, inSampler); 217 | outInscatterR = packed_inscatter.xyz; 218 | outInscatterM = UnpackMieInscatter(packed_inscatter, inBetaR); 219 | } 220 | 221 | void LookUpPrecomputedScatteringSeparated( 222 | float3 inStartPos, 223 | float3 inViewDir, 224 | float3 inLightDir, 225 | in Texture3D inInscatterTextureR, 226 | in Texture3D inInscatterTextureM, 227 | in SamplerState inSampler, 228 | out float3 outInscatterR, 229 | out float3 outInscatterM 230 | ) 231 | { 232 | outInscatterR = SamplePrecomputedTexture(inStartPos, inViewDir, inLightDir, inInscatterTextureR, inSampler).xyz; 233 | outInscatterM = SamplePrecomputedTexture(inStartPos, inViewDir, inLightDir, inInscatterTextureM, inSampler).xyz; 234 | } 235 | 236 | //------------------------------------------------------ 237 | // 3d LookUpTable parametrization for sunlight and skylight 238 | //------------------------------------------------------ 239 | void SunlightLUTCoordToWorldCoord(float2 inUV, out float outHeight, out float outSunZenith) 240 | { 241 | // Rescale to exactly 0,1 range 242 | inUV.xy = saturate((inUV * LUT_RESOLUTION.xz - 0.5) / (LUT_RESOLUTION.xz - 1.0)); 243 | outHeight = inUV.x * inUV.x * (ATM_TOP_HEIGHT - 2.0 * LUT_HEIGHT_MARGIN) + LUT_HEIGHT_MARGIN; 244 | outSunZenith = tan((2.0 * inUV.y - 1.0 + 0.26) * 1.1) / tan(1.26 * 1.1); // Bruneton's formula [Bruneton09] 245 | } 246 | 247 | float2 WorldCoordToSunlightLUTCoord(float inHeight, float inSunZenith) 248 | { 249 | float2 outUV = float2(0, 0); 250 | float height = clamp(inHeight, LUT_HEIGHT_MARGIN, ATM_TOP_HEIGHT - LUT_HEIGHT_MARGIN); 251 | outUV.x = saturate((height - LUT_HEIGHT_MARGIN) / (ATM_TOP_HEIGHT - 2.0 * LUT_HEIGHT_MARGIN)); 252 | outUV.x = sqrt(outUV.x); 253 | outUV.y = (atan(max(inSunZenith, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5; // Bruneton's formula [Bruneton09] 254 | outUV = ((outUV * (LUT_RESOLUTION.xz - 1.0) + 0.5) / LUT_RESOLUTION.xz); 255 | return outUV; 256 | } 257 | 258 | float3 SampleLightTexture( 259 | float3 inStartPos, 260 | float3 inLightDir, 261 | in Texture2D inTexture2d, 262 | in SamplerState inSampler) 263 | { 264 | float3 dir = inStartPos - EARTH_CENTER; 265 | float dist = length(dir); 266 | dir /= dist; 267 | float height = dist - EARTH_RADIUS; 268 | float cos_light_zenith = dot(dir, inLightDir); 269 | float2 uv = WorldCoordToSunlightLUTCoord(height, cos_light_zenith); 270 | float3 light = inTexture2d.SampleLevel(inSampler, uv, 0).xyz; 271 | return light; 272 | } 273 | 274 | //------------------------------------------------------ 275 | // Phase functions 276 | //------------------------------------------------------ 277 | float RayleighPhase(float mu) 278 | { 279 | return 3.0 / 4.0 * 1.0 / (4.0 * M_PI)*(1.0 + mu*mu); 280 | } 281 | 282 | float HenyeyGreensteinPhaseFunc(float mu, float g) 283 | { 284 | return (1.0 - g*g) / ((4.0 * M_PI) * pow(1.0 + g*g - 2.0*g*mu, 1.5)); 285 | } 286 | 287 | float CornetteShanksPhaseFunc(float mu, float g) 288 | { 289 | return (3.0 / 2.0) / (4.0 * M_PI) * (1.0 - g*g) / (2.0 + g*g) * (1.0 + mu*mu)*pow(abs(1.0 + g*g - 2.0*g*mu), -1.5); 290 | } 291 | 292 | float MiePhase(float mu, float g) 293 | { 294 | return CornetteShanksPhaseFunc(mu, g); 295 | } 296 | 297 | //------------------------------------------------------ 298 | // Naive optical depth 299 | // - We call the optical depth considering only height-falloff as "naive optical depth" 300 | //------------------------------------------------------ 301 | float2 CalulateNaiveOpticalDepth( 302 | in float3 inStartPos, 303 | in float3 inEndPos, 304 | in float2 inScaleHeights, 305 | const int inNumSteps) 306 | { 307 | const float3 dr = (inEndPos - inStartPos) / inNumSteps; 308 | const float length_dr = length(dr); 309 | const float start_height= abs(length(inStartPos - EARTH_CENTER) - EARTH_RADIUS); 310 | 311 | float2 optical_depth = 0.0; 312 | for (int i = 0; i <= inNumSteps; ++i) 313 | { 314 | float3 curr_pos = inStartPos + dr * float(i); 315 | float height = abs(length(curr_pos - EARTH_CENTER) - EARTH_RADIUS); 316 | float2 integrand = exp(-height / inScaleHeights); 317 | optical_depth += integrand * length_dr; 318 | } 319 | return optical_depth; 320 | } 321 | 322 | float2 CalculateNaiveOpticalDepthAlongRay( 323 | in float3 inWorldPos, 324 | in float3 inRayDir, 325 | in float2 inScaleHeights, 326 | const int inNumSteps) 327 | { 328 | // Ray - {Earth, The top of atmosphere} intersection test 329 | float4 distances = RayDoubleSphereIntersect(inWorldPos - EARTH_CENTER, inRayDir, float2(EARTH_RADIUS, ATM_TOP_RADIUS)); 330 | 331 | float2 ray_distance_to_earth = distances.xy; 332 | if (ray_distance_to_earth.x > 0) 333 | return float2(1e20, 1e20); // huge optical depth 334 | 335 | float2 ray_distance_to_atm_top = distances.zw; 336 | float ray_length = ray_distance_to_atm_top.y; // far side 337 | float3 intersection_pos = inWorldPos + inRayDir * ray_length; 338 | return CalulateNaiveOpticalDepth(inWorldPos, intersection_pos, inScaleHeights, inNumSteps); 339 | } 340 | 341 | //------------------------------------------------------ 342 | // Single scattering 343 | //------------------------------------------------------ 344 | void SingleScattering( 345 | in float3 inStartPos, 346 | in float3 inEndPos, 347 | in float3 inLightDir, 348 | in PrecomputedSctrParams inParams, 349 | in Texture2D inOpticalDepthTexture, 350 | in SamplerState inOpticalDepthSampler, 351 | out float3 outInscatterR, 352 | out float3 outInscatterM, 353 | out float3 outTransmittance, 354 | const int inNumSteps) 355 | { 356 | outTransmittance = float3(0.0, 0.0, 0.0); 357 | outInscatterR = float3(0.0, 0.0, 0.0); 358 | outInscatterM = float3(0.0, 0.0, 0.0); 359 | 360 | float3 dr = (inEndPos - inStartPos) / float(inNumSteps); 361 | float length_dr = length(dr); 362 | 363 | float mie_g = 0.0; 364 | float3 betaR = inParams.mRayleighSctrCoeff.rgb; 365 | float3 betaM = inParams.mMieSctrCoeff.rgb * inParams.mMieAbsorption * (1.0 - mie_g); 366 | float2 scale_height = float2(inParams.mRayleighScaleHeight, inParams.mMieScaleHeight); 367 | 368 | float2 optdepth_from_cam = float2(0.0, 0.0); 369 | // Integrand: exp(-h(x)/H) * t(x->Pc) * t(x->s) 370 | for (int i = 0; i <= inNumSteps; i++) 371 | { 372 | float3 sample_pos = inStartPos + dr * float(i); 373 | float3 integrandR, integrandM; 374 | 375 | // optdepth_from_cam_integrand = ( exp(-h(x)/HR), exp(-h(x)/HM) ) 376 | // optdepth_to_top = \int^Pc_x exp(-h(x')/H) dx' 377 | float height = (length(sample_pos - EARTH_CENTER) - EARTH_RADIUS); 378 | float2 optdepth_from_cam_integrand = exp(-height / scale_height); 379 | 380 | // optdepth_to_top is precalculated in the texture 381 | float cos_light_zenith = dot(normalize(sample_pos - EARTH_CENTER), inLightDir); 382 | float2 optdepth_to_top = inOpticalDepthTexture.SampleLevel(inOpticalDepthSampler, float2(height / ATM_TOP_HEIGHT, cos_light_zenith*0.5 + 0.5), 0).xy; 383 | 384 | float3 trans_from_cam = exp(-betaR * optdepth_from_cam.x - betaM * optdepth_from_cam.y); 385 | float3 trans_to_top = exp(-betaR * optdepth_to_top.x - betaM * optdepth_to_top.y); 386 | 387 | // integrand: exp(-h(x)/H) * t(x->Pc) * t(x->s) 388 | integrandR = optdepth_from_cam_integrand.x * trans_from_cam * trans_to_top; 389 | integrandM = optdepth_from_cam_integrand.y * trans_from_cam * trans_to_top; 390 | 391 | outInscatterR += integrandR * length_dr; 392 | outInscatterM += integrandM * length_dr; 393 | optdepth_from_cam += optdepth_from_cam_integrand * length_dr; 394 | } 395 | 396 | float3 optical_depthR = inParams.mRayleighSctrCoeff.rgb * optdepth_from_cam.x; 397 | float3 optical_depthM = inParams.mMieSctrCoeff.rgb * inParams.mMieAbsorption * (1.0 - mie_g) * optdepth_from_cam.y; 398 | outTransmittance = exp(-(optical_depthR + optical_depthM)); 399 | outInscatterR *= inParams.mRayleighSctrCoeff.rgb; 400 | outInscatterM *= inParams.mMieSctrCoeff.rgb; 401 | } 402 | 403 | //------------------------------------------------------ 404 | // Multiple scattering 405 | //------------------------------------------------------ 406 | void MultipleScattering( 407 | in float3 inStartPos, 408 | in float3 inEndPos, 409 | in float3 inLightDir, 410 | in PrecomputedSctrParams inParams, 411 | in Texture3D inInscatterTextureR, 412 | in Texture3D inInscatterTextureM, 413 | in SamplerState inSamplerLinearClamp, 414 | out float3 outInscatterR, 415 | out float3 outInscatterM, 416 | out float3 outTransmittance, 417 | const int inNumSteps) 418 | { 419 | outTransmittance = float3(0.0, 0.0, 0.0); 420 | outInscatterR = float3(0.0, 0.0, 0.0); 421 | outInscatterM = float3(0.0, 0.0, 0.0); 422 | 423 | float3 dr = (inEndPos - inStartPos) / float(inNumSteps); 424 | float3 view_dir = normalize(inEndPos - inStartPos); 425 | float length_dr = length(dr); 426 | 427 | float mie_g = 0.0; 428 | float mu = dot(view_dir, inLightDir); 429 | float3 betaR = inParams.mRayleighSctrCoeff.rgb; 430 | float3 betaM = inParams.mMieSctrCoeff.rgb * inParams.mMieAbsorption * (1.0 - mie_g); 431 | float2 scale_height = float2(inParams.mRayleighScaleHeight, inParams.mMieScaleHeight); 432 | 433 | float2 optdepth_from_cam = float2(0.0, 0.0); 434 | // Integrand: exp(-h(x)/H) * t(x->Pc) * t(x->s) 435 | for (int i = 0; i <= inNumSteps; i++) 436 | { 437 | float3 sample_pos = inStartPos + dr * float(i); 438 | 439 | // optdepth_from_cam_integrand = ( exp(-h(x)/HR), exp(-h(x)/HM) ) 440 | float height = (length(sample_pos - EARTH_CENTER) - EARTH_RADIUS); 441 | float2 optdepth_from_cam_integrand = exp(-height / scale_height); 442 | float3 trans_from_cam = exp(-betaR * optdepth_from_cam.x - betaM * optdepth_from_cam.y); 443 | 444 | float3 inscatter_r; 445 | float3 inscatter_m; 446 | LookUpPrecomputedScatteringSeparated( 447 | sample_pos, view_dir, inLightDir, 448 | inInscatterTextureR, inInscatterTextureM, inSamplerLinearClamp, 449 | inscatter_r, inscatter_m); 450 | outInscatterR += inscatter_r * optdepth_from_cam_integrand.x * trans_from_cam * length_dr; 451 | outInscatterM += inscatter_m * optdepth_from_cam_integrand.y * trans_from_cam * length_dr; 452 | optdepth_from_cam += optdepth_from_cam_integrand * length_dr; 453 | } 454 | 455 | float3 optical_depthR = inParams.mRayleighSctrCoeff.rgb * optdepth_from_cam.x; 456 | float3 optical_depthM = inParams.mMieSctrCoeff.rgb * inParams.mMieAbsorption * (1.0 - mie_g) * optdepth_from_cam.y; 457 | outTransmittance = exp(-(optical_depthR + optical_depthM)); 458 | outInscatterR *= inParams.mRayleighSctrCoeff.xyz; 459 | outInscatterM *= inParams.mMieSctrCoeff.xyz; 460 | } 461 | 462 | #endif // ATMOSPHERIC_SCATTERING_H 463 | -------------------------------------------------------------------------------- /shader/atmosphere/AtmosphericScatteringPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "Atmosphere.h" 2 | #include "AtmosphereConstants.h" 3 | #include "AtmosphericScattering.hlsl.h" 4 | #include "../Util.hlsl" 5 | 6 | // #pragma pack_matrix(row_major) // Sets the matrix packing alignment to row major 7 | 8 | Texture2D gTexture2Da : register(t0); 9 | Texture2D gTexture2Db : register(t1); 10 | Texture2D gTexture2Dc : register(t2); 11 | Texture2D gTexture2Dd : register(t3); 12 | Texture3D gTexture3Da : register(t4); 13 | Texture3D gTexture3Db : register(t5); 14 | Texture3D gTexture3Dc : register(t6); 15 | Texture3D gTexture3Dd : register(t7); 16 | 17 | //------------------------------------------------------------------------- 18 | 19 | // https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ 20 | float3 ACESFilm(float3 x) 21 | { 22 | float a = 2.51f; 23 | float b = 0.03f; 24 | float c = 2.43f; 25 | float d = 0.59f; 26 | float e = 0.14f; 27 | return saturate((x*(a*x + b)) / (x*(c*x + d) + e)); 28 | } 29 | 30 | //------------------------------------------------------------------------- 31 | #define GND_TOP_HEIGHT 4.5 // [km] 32 | #define GND_TOP_RADIUS (EARTH_RADIUS + GND_TOP_HEIGHT) 33 | #define GND_BOTTOM_HEIGHT 0.0 34 | #define USE_PACKED_INSCATTER 1 35 | 36 | 37 | float3x3 CalculateCameraMatrix(float3 look_to, float3 up_dir) 38 | { 39 | float3 forward = look_to; 40 | float3 right = normalize( cross(look_to , up_dir ) ); 41 | float3 up = normalize( cross(right , look_to ) ); 42 | return float3x3(right, up, forward); 43 | } 44 | 45 | //-------------------------------------------------------- 46 | 47 | float4 Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 48 | { 49 | const float time = GetParam(0).x; 50 | const float2 resolution = GetParam(0).yz; 51 | const float2 clip_pos = (2.0 * float2(inUV.x, 1.0 - inUV.y) - 1.0) * resolution.xy / resolution.yy; 52 | const float3 extraterrestrial_sunlight = 1e5 * float3(1, 1, 1); 53 | 54 | float4 outColor = float4(0.0, 0.0, 0.0, 1.0); 55 | 56 | float fov = tan(M_PI/3.25); 57 | float3 light_dir = GetParam(5).xyz; 58 | float3 camera_pos = GetParam(4).xyz; 59 | float3x3 camera_matrix = float3x3(GetParam(1).xyz, GetParam(2).xyz, GetParam(3).xyz); 60 | float3 view_dir = UVToViewDirection(clip_pos * fov, camera_matrix); 61 | const int camera_mode = 0; 62 | if (camera_mode == 1) 63 | view_dir = UVToOmniDirection(clip_pos * fov); 64 | 65 | float ray_length = 1e4; 66 | float3 world_pos = camera_pos + ray_length * view_dir; 67 | float4 distances = RayDoubleSphereIntersect(camera_pos, view_dir, float2(EARTH_RADIUS, ATM_TOP_RADIUS)); 68 | float2 ray_distance_to_earth = distances.xy; 69 | float2 ray_distance_to_atm_top = distances.zw; 70 | bool is_ground = (ray_distance_to_earth.x > 0); 71 | bool is_atmosphere = (ray_distance_to_atm_top.y > 0); 72 | if(!is_atmosphere) 73 | return outColor; 74 | 75 | world_pos = camera_pos + ray_distance_to_earth.x * view_dir; 76 | 77 | if(ray_distance_to_atm_top.x > 0) 78 | camera_pos = camera_pos + ray_distance_to_atm_top.x * view_dir; 79 | 80 | const float3 atm_top_pos = camera_pos + ray_distance_to_atm_top.y * view_dir; 81 | const bool shadow_enabled = GetParam(4).w; 82 | const float mie_g = GetParam(6).y; 83 | 84 | PrecomputedSctrParams sctr_params; 85 | sctr_params.mRayleighSctrCoeff = GetParam(8).xyz; 86 | sctr_params.mRayleighScaleHeight = GetParam(8).w; 87 | sctr_params.mMieSctrCoeff = GetParam(9).xyz; 88 | sctr_params.mMieScaleHeight = GetParam(9).w; 89 | sctr_params.mMieAbsorption = GetParam(10).x; 90 | 91 | ray_length = ray_distance_to_atm_top.y; 92 | if(ray_distance_to_earth.x > 0.0) 93 | ray_length = min(ray_distance_to_earth.x, ray_distance_to_atm_top.y); 94 | 95 | world_pos = camera_pos + ray_length * view_dir; 96 | float3 inscatterR, inscatterM; 97 | #if USE_PACKED_INSCATTER 98 | LookUpPrecomputedScatteringPacked( 99 | camera_pos + EARTH_CENTER, view_dir, light_dir, sctr_params.mRayleighSctrCoeff, 100 | gTexture3Da, SamplerLinearClamp, 101 | inscatterR, inscatterM 102 | ); 103 | #else 104 | LookUpPrecomputedScatteringSeparated( 105 | camera_pos + EARTH_CENTER, view_dir, light_dir, 106 | gTexture3Db, gTexture3Dc, SamplerLinearClamp, 107 | inscatterR, inscatterM 108 | ); 109 | #endif 110 | float VoL = dot(view_dir, light_dir); 111 | inscatterR *= RayleighPhase(VoL); 112 | inscatterM *= MiePhase(VoL, mie_g); 113 | outColor.xyz = extraterrestrial_sunlight * (inscatterR + inscatterM); 114 | 115 | const float exposure_compensation = GetParam(6).z; 116 | outColor.xyz *= exp2(exposure_compensation); 117 | outColor.xyz = ACESFilm(outColor.xyz); 118 | outColor.xyz = pow(outColor.xyz, 1.0 / 2.2); 119 | 120 | // DebugDrawTexture3D(outColor, gTexture3Da, SamplerLinearClamp, inUV, float2(0.0 , 0.80), float2(0.25, 0.20)); 121 | // DebugDrawTexture3D(outColor, gTexture3Db, SamplerLinearClamp, inUV, float2(0.25, 0.80), float2(0.25, 0.20)); 122 | // DebugDrawTexture3D(outColor, gTexture3Dc, SamplerLinearClamp, inUV, float2(0.5 , 0.80), float2(0.25, 0.20)); 123 | // DebugDrawTexture2D(outColor, gTexture2Dc, SamplerLinearClamp, inUV, float2(0.0 , 0.80), float2(0.25, 0.20)); 124 | // DebugDrawTexture2D(outColor, gTexture2Dd, SamplerLinearClamp, inUV, float2(0.25, 0.80), float2(0.25, 0.20)); 125 | 126 | return outColor; 127 | } 128 | -------------------------------------------------------------------------------- /shader/atmosphere/GatherInscatterPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "Atmosphere.h" 2 | #include "AtmosphereConstants.h" 3 | #include "AtmosphericScattering.hlsl.h" 4 | #include "../Random.hlsl" 5 | 6 | Texture3D gTexture3Da : register(t4); 7 | Texture3D gTexture3Db : register(t5); 8 | 9 | struct PSOutput 10 | { 11 | float4 outColor0 : SV_Target0; 12 | float4 outColor1 : SV_Target1; 13 | }; 14 | 15 | PSOutput Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 16 | { 17 | PSOutput o; 18 | const float3 uvw = float3(inUV.x, inUV.y, GetWQ().x); 19 | 20 | float height, cos_view_zenith, cos_sun_zenith; 21 | LUTCoordToWorldCoord(uvw, height, cos_view_zenith, cos_sun_zenith); 22 | float3 start_pos = float3(0, height, 0); 23 | float3 view_dir = ComputeViewDir(cos_view_zenith); 24 | float3 light_dir = ComputeLightDir(view_dir, cos_sun_zenith); 25 | 26 | PrecomputedSctrParams params; 27 | params.mRayleighSctrCoeff = GetParam(0).xyz; 28 | params.mRayleighScaleHeight = GetParam(0).w; 29 | params.mMieSctrCoeff = GetParam(1).xyz; 30 | params.mMieScaleHeight = GetParam(1).w; 31 | params.mMieAbsorption = GetParam(2).x; 32 | 33 | float2 scale_height = float2(params.mRayleighScaleHeight, params.mMieScaleHeight); 34 | float2 height_factor = exp(-height / scale_height); 35 | 36 | #define NUM_RANDOMDIR_SAMPLES 128 37 | float3 inscatter_sum_r = float3(0, 0, 0); 38 | float3 inscatter_sum_m = float3(0, 0, 0); 39 | for (int i = 0; i < NUM_RANDOMDIR_SAMPLES; ++i) 40 | { 41 | float3 rand_dir = normalize(RandomUnitVector(uvw.xy * Hash21(float(i) + uvw.z * 2236.20679) * 1414.24356)); 42 | float mu = dot(view_dir, rand_dir); 43 | 44 | float3 inscatter_r, inscatter_m; 45 | LookUpPrecomputedScatteringSeparated( 46 | start_pos, rand_dir, light_dir, 47 | gTexture3Da, gTexture3Db, SamplerLinearClamp, 48 | inscatter_r, inscatter_m 49 | ); 50 | 51 | float mie_g = 0.0; // [Elek09] 52 | inscatter_r *= RayleighPhase(mu); 53 | inscatter_m *= CornetteShanksPhaseFunc(mu, mie_g); 54 | 55 | inscatter_sum_r += inscatter_r; 56 | inscatter_sum_m += inscatter_m; 57 | } 58 | 59 | o.outColor0 = float4(inscatter_sum_r * 4.0 * 3.14159265 / float(NUM_RANDOMDIR_SAMPLES), 0.0); 60 | o.outColor1 = float4(inscatter_sum_m * 4.0 * 3.14159265 / float(NUM_RANDOMDIR_SAMPLES), 0.0); 61 | 62 | return o; 63 | } 64 | -------------------------------------------------------------------------------- /shader/atmosphere/MultipleScatteringPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "Atmosphere.h" 2 | #include "AtmosphereConstants.h" 3 | #include "AtmosphericScattering.hlsl.h" 4 | #include "../Random.hlsl" 5 | 6 | Texture2D gTexture2Da : register(t0); 7 | Texture3D gTexture3Da : register(t4); 8 | Texture3D gTexture3Db : register(t5); 9 | 10 | struct PSOutput 11 | { 12 | float4 outColor0 : SV_Target0; 13 | float4 outColor1 : SV_Target1; 14 | }; 15 | 16 | PSOutput Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 17 | { 18 | PSOutput o; 19 | o.outColor0 = float4(0.0, 0.0, 0.0, 0.0); 20 | o.outColor1 = float4(0.0, 0.0, 0.0, 0.0); 21 | 22 | const float3 uvw = float3(inUV.x, inUV.y, GetWQ().x); 23 | 24 | float height, cos_view_zenith, cos_sun_zenith; 25 | LUTCoordToWorldCoord(uvw, height, cos_view_zenith, cos_sun_zenith); 26 | float3 start_pos = float3(0, height, 0); 27 | float3 view_dir = ComputeViewDir(cos_view_zenith); 28 | float3 light_dir = ComputeLightDir(view_dir, cos_sun_zenith); 29 | 30 | PrecomputedSctrParams params; 31 | params.mRayleighSctrCoeff = GetParam(0).xyz; 32 | params.mRayleighScaleHeight = GetParam(0).w; 33 | params.mMieSctrCoeff = GetParam(1).xyz; 34 | params.mMieScaleHeight = GetParam(1).w; 35 | params.mMieAbsorption = GetParam(2).x; 36 | 37 | // Intersect view ray with the top of the atmosphere and the earth 38 | float4 distances = RayDoubleSphereIntersect(start_pos - EARTH_CENTER, view_dir, float2(EARTH_RADIUS, ATM_TOP_RADIUS)); 39 | float2 ray_distance_to_earth = distances.xy; 40 | float2 ray_distance_to_atm_top = distances.zw; 41 | 42 | if (ray_distance_to_atm_top.y <= 0) 43 | return o; // Error: Ray misses the earth 44 | 45 | float ray_distance = ray_distance_to_atm_top.y; 46 | if (ray_distance_to_earth.x > 0) 47 | ray_distance = min(ray_distance, ray_distance_to_earth.x); // Ray hits the earth 48 | float3 end_pos = start_pos + view_dir * ray_distance; 49 | 50 | 51 | const float NUM_SAMPLES = 256.0; 52 | float step_length = ray_distance / NUM_SAMPLES; 53 | 54 | const float mie_g = 0.0; 55 | float mu = dot(light_dir, view_dir); 56 | 57 | float2 scale_height = float2(params.mRayleighScaleHeight, params.mMieScaleHeight); 58 | float2 height_factor = exp(-(length(start_pos - EARTH_CENTER) - EARTH_RADIUS) / scale_height); 59 | float3 inscatter_r = float3(0.0, 0.0, 0.0); 60 | float3 inscatter_m = float3(0.0, 0.0, 0.0); 61 | float3 transmittance; 62 | MultipleScattering( 63 | start_pos, end_pos, light_dir, params, 64 | gTexture3Da, gTexture3Db, SamplerLinearClamp, 65 | inscatter_r, inscatter_m, transmittance, INSCATTER_INTEGRAL_STEPS); 66 | 67 | o.outColor0.xyz = inscatter_r; 68 | o.outColor1.xyz = inscatter_m; 69 | 70 | // (We ignored the reflection from the ground) 71 | 72 | return o; 73 | } 74 | -------------------------------------------------------------------------------- /shader/atmosphere/OpticalDepthPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "Atmosphere.h" 2 | #include "AtmosphereConstants.h" 3 | #include "AtmosphericScattering.hlsl.h" 4 | 5 | float2 Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 6 | { 7 | const float2 scale_heights = float2(GetParam(0).w, GetParam(1).w); 8 | 9 | // u : height, v : zenith altitude 10 | float costheta = 2.0 * inUV.y - 1.0; 11 | float height = lerp(0.0, ATM_TOP_HEIGHT, inUV.x); 12 | height = clamp(height, LUT_HEIGHT_MARGIN, ATM_TOP_HEIGHT - LUT_HEIGHT_MARGIN); 13 | 14 | float sintheta = sqrt(saturate(1.0 - costheta * costheta)); 15 | float3 sample_pos = float3(0.0, height, 0.0); 16 | float3 ray_dir = float3(0.0, costheta, sintheta); 17 | 18 | const int num_steps = 128; 19 | return CalculateNaiveOpticalDepthAlongRay(sample_pos, ray_dir, scale_heights, num_steps); 20 | } 21 | -------------------------------------------------------------------------------- /shader/atmosphere/PackInscatterPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "Atmosphere.h" 2 | #include "AtmosphereConstants.h" 3 | #include "AtmosphericScattering.hlsl.h" 4 | #include "../Random.hlsl" 5 | 6 | Texture3D gTexture3Da : register(t4); 7 | Texture3D gTexture3Db : register(t5); 8 | Texture3D gTexture3Dc : register(t6); 9 | Texture3D gTexture3Dd : register(t7); 10 | 11 | struct PSOutput 12 | { 13 | float4 outColor0 : SV_Target0; 14 | }; 15 | 16 | PSOutput Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 17 | { 18 | PSOutput o; 19 | const uint slice = GetDepthSlice(); 20 | float4 color00 = gTexture3Da.Load(uint4(inPosition.xy, slice, 0)); 21 | float4 color01 = gTexture3Db.Load(uint4(inPosition.xy, slice, 0)); 22 | float4 color10 = gTexture3Dc.Load(uint4(inPosition.xy, slice, 0)); 23 | float4 color11 = gTexture3Dd.Load(uint4(inPosition.xy, slice, 0)); 24 | float3 rayleigh = (color00 + color10).xyz; 25 | float3 mie = (color01 + color11).xyz; 26 | o.outColor0 = PackInscatter(rayleigh, mie); 27 | return o; 28 | } 29 | -------------------------------------------------------------------------------- /shader/atmosphere/SingleScatteringPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "Atmosphere.h" 2 | #include "AtmosphereConstants.h" 3 | #include "AtmosphericScattering.hlsl.h" 4 | 5 | Texture2D gTexture2Da : register(t0); 6 | 7 | struct PSOutput 8 | { 9 | float4 outColor0 : SV_Target0; 10 | float4 outColor1 : SV_Target1; 11 | }; 12 | 13 | PSOutput Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 14 | { 15 | PSOutput o; 16 | o.outColor0 = float4(0.0, 0.0, 0.0, 1.0); 17 | o.outColor1 = float4(0.0, 0.0, 0.0, 1.0); 18 | 19 | const float3 uvw = float3(inUV.x, inUV.y, GetWQ().x); 20 | float height, cos_view_zenith, cos_sun_zenith; 21 | LUTCoordToWorldCoord(uvw, height, cos_view_zenith, cos_sun_zenith); 22 | float3 start_pos = float3(0, height, 0); 23 | float3 view_dir = ComputeViewDir(cos_view_zenith); 24 | float3 light_dir = ComputeLightDir(view_dir, cos_sun_zenith); 25 | 26 | // Intersect view ray with the top of the atmosphere and the earth 27 | float4 distances = RayDoubleSphereIntersect(start_pos - EARTH_CENTER, view_dir, float2(EARTH_RADIUS, ATM_TOP_RADIUS)); 28 | float2 ray_distance_to_earth = distances.xy; 29 | float2 ray_distance_to_atm_top = distances.zw; 30 | 31 | if (ray_distance_to_atm_top.y <= 0) 32 | return o; // Error: Ray misses the earth 33 | 34 | bool is_ground = false; 35 | float ray_distance = ray_distance_to_atm_top.y; 36 | if (ray_distance_to_earth.x > 0) 37 | { 38 | ray_distance = min(ray_distance, ray_distance_to_earth.x); // Ray hits the earth 39 | is_ground = true; 40 | } 41 | 42 | float3 end_pos = start_pos + view_dir * ray_distance; 43 | 44 | PrecomputedSctrParams params; 45 | params.mRayleighSctrCoeff = GetParam(0).xyz; 46 | params.mRayleighScaleHeight = GetParam(0).w; 47 | params.mMieSctrCoeff = GetParam(1).xyz; 48 | params.mMieScaleHeight = GetParam(1).w; 49 | params.mMieAbsorption = GetParam(2).x; 50 | 51 | // Integrate single-scattering 52 | float3 transmittance; 53 | float3 inscatterR; 54 | float3 inscatterM; 55 | SingleScattering( 56 | start_pos, 57 | end_pos, 58 | light_dir, 59 | params, 60 | gTexture2Da, // optical depth 61 | SamplerLinearClamp, 62 | inscatterR, 63 | inscatterM, 64 | transmittance, 65 | INSCATTER_INTEGRAL_STEPS 66 | ); 67 | 68 | if(is_ground) 69 | { 70 | float3 ground_albedo = float3(0.45, 0.45, 0.45); 71 | float height = (length(end_pos - EARTH_CENTER) - EARTH_RADIUS); 72 | float cos_light_zenith = dot(normalize(end_pos - EARTH_CENTER), light_dir); 73 | float2 optdepth_to_top = gTexture2Da.SampleLevel(SamplerLinearClamp, float2(height / ATM_TOP_HEIGHT, cos_light_zenith*0.5 + 0.5), 0).xy; 74 | float3 trans_to_top = exp(-params.mRayleighSctrCoeff * optdepth_to_top.x - params.mMieSctrCoeff * optdepth_to_top.y); 75 | inscatterR += ground_albedo * saturate(cos_light_zenith) * transmittance * trans_to_top; 76 | inscatterM += ground_albedo * saturate(cos_light_zenith) * transmittance * trans_to_top; 77 | } 78 | 79 | o.outColor0.xyz = inscatterR; 80 | o.outColor1.xyz = inscatterM; 81 | 82 | return o; 83 | } 84 | -------------------------------------------------------------------------------- /shader/atmosphere/TotalInscatterPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "Atmosphere.h" 2 | #include "AtmosphereConstants.h" 3 | #include "AtmosphericScattering.hlsl.h" 4 | #include "../Random.hlsl" 5 | 6 | Texture3D gTexture3Da : register(t4); 7 | Texture3D gTexture3Db : register(t5); 8 | Texture3D gTexture3Dc : register(t6); 9 | Texture3D gTexture3Dd : register(t7); 10 | 11 | struct PSOutput 12 | { 13 | float4 outColor0 : SV_Target0; 14 | float4 outColor1 : SV_Target1; 15 | }; 16 | 17 | PSOutput Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 18 | { 19 | PSOutput o; 20 | const uint slice = GetDepthSlice(); 21 | float4 color00 = gTexture3Da.Load(uint4(inPosition.xy, slice, 0)); 22 | float4 color01 = gTexture3Db.Load(uint4(inPosition.xy, slice, 0)); 23 | float4 color10 = gTexture3Dc.Load(uint4(inPosition.xy, slice, 0)); 24 | float4 color11 = gTexture3Dd.Load(uint4(inPosition.xy, slice, 0)); 25 | o.outColor0 = color00 + color10; 26 | o.outColor1 = color01 + color11; 27 | // o.outColor0 = color00; 28 | // o.outColor1 = color01; 29 | // o.outColor0 = color10; 30 | // o.outColor1 = color11; 31 | return o; 32 | } 33 | -------------------------------------------------------------------------------- /shader/helloworld/HelloWorld.h: -------------------------------------------------------------------------------- 1 | #ifndef HELLO_WORLD_H 2 | #define HELLO_WORLD_H 3 | #include "../Screen.h" 4 | 5 | Texture2D gTexture2Da : register(t0); 6 | Texture2D gTexture2Db : register(t1); 7 | Texture2D gTexture2Dc : register(t2); 8 | Texture2D gTexture2Dd : register(t3); 9 | Texture3D gTexture3Da : register(t4); 10 | Texture3D gTexture3Db : register(t5); 11 | Texture3D gTexture3Dc : register(t6); 12 | Texture3D gTexture3Dd : register(t7); 13 | 14 | #endif // HELLO_WORLD_H 15 | -------------------------------------------------------------------------------- /shader/helloworld/OffScreen2dPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "HelloWorld.h" 2 | 3 | float4 Entry(float4 Pos : SV_POSITION, float2 uv : TexCoord) : SV_Target 4 | { 5 | float time = GetElapsedTime(); 6 | float4 outColor = float4(0.0, 0.0, 0.0, 1.0); 7 | outColor.xyz = float3(uv.x, uv.y, 0.5 + 0.5 * sin(time)); 8 | return outColor; 9 | } 10 | -------------------------------------------------------------------------------- /shader/helloworld/OffScreen3dPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "HelloWorld.h" 2 | 3 | struct PSOutput 4 | { 5 | float4 outColor0 : SV_Target0; 6 | float4 outColor1 : SV_Target1; 7 | }; 8 | 9 | PSOutput Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 10 | { 11 | const float time = GetElapsedTime(); 12 | const float depth = GetCurrentDepth(); 13 | 14 | float4 outColor0 = float4(0.0, 0.0, 0.0, 1.0); 15 | float4 outColor1 = float4(0.0, 0.0, 0.0, 1.0); 16 | // outColor.xyz = float3(inUV.x, inUV.y, 0.5 + 0.5 * sin(time)); 17 | outColor0.xyz = float3(inUV.x, inUV.y, depth); 18 | outColor1.xyz = float3(inUV.x, depth, inUV.y); 19 | 20 | PSOutput o; 21 | o.outColor0 = outColor0; 22 | o.outColor1 = outColor1; 23 | return o; 24 | } 25 | -------------------------------------------------------------------------------- /shader/helloworld/ScreenPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "HelloWorld.h" 2 | #include "../Util.hlsl" 3 | 4 | float4 Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 5 | { 6 | const float time = GetElapsedTime(); 7 | const float2 resolution = GetScreenResolution(); 8 | 9 | float4 outColor = float4(0.0, 0.0, 0.0, 1.0); 10 | outColor.xyz = float3(inUV.x, inUV.y, 0.5 + 0.5 * sin(time)); 11 | outColor.xy = inPosition.xy / resolution; 12 | 13 | // outColor.xyz = 0; 14 | DebugDrawTexture2D(outColor, gTexture2Da, SamplerLinearClamp, inUV, float2(0.0, 0.0 ), float2(0.25, 0.25)); 15 | DebugDrawTexture3D(outColor, gTexture3Da, SamplerLinearClamp, inUV, float2(0.0, 0.25), float2(1.0 , 0.05)); 16 | DebugDrawTexture3D(outColor, gTexture3Db, SamplerLinearClamp, inUV, float2(0.0, 0.30), float2(1.0 , 0.05)); 17 | 18 | 19 | return outColor; 20 | } 21 | -------------------------------------------------------------------------------- /shader/noise/TilableNoise2dPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "../Random.hlsl" 2 | #include "../Util.hlsl" 3 | 4 | //=============================================== 5 | float ValueNoise31(float3 x, float3 boundary) 6 | { 7 | float3 b = boundary; 8 | float3 p = floor(x); 9 | float3 f = frac(x); 10 | f = f * f * (3.0 - 2.0 * f); 11 | 12 | return lerp( 13 | lerp( 14 | lerp( 15 | Hash31(fmod(p + float3(0, 0, 0), b)), 16 | Hash31(fmod(p + float3(1, 0, 0), b)), 17 | f.x 18 | ), 19 | lerp( 20 | Hash31(fmod(p + float3(0, 1, 0), b)), 21 | Hash31(fmod(p + float3(1, 1, 0), b)), 22 | f.x 23 | ), 24 | f.y 25 | ), 26 | lerp( 27 | lerp( 28 | Hash31(fmod(p + float3(0, 0, 1), b)), 29 | Hash31(fmod(p + float3(1, 0, 1), b)), 30 | f.x 31 | ), 32 | lerp( 33 | Hash31(fmod(p + float3(0, 1, 1), b)), 34 | Hash31(fmod(p + float3(1, 1, 1), b)), 35 | f.x 36 | ), 37 | f.y 38 | ), 39 | f.z 40 | ); 41 | } 42 | 43 | // x = [0,1] 44 | float TilableFbm31(float3 x, float inFrequency, const int inNumOctaves) 45 | { 46 | const float boundary = inFrequency; // take the boundary at max of 1st octave 47 | 48 | float amp = 1.0; 49 | float freq = inFrequency; 50 | float result= 0.0; 51 | float norm = amp; 52 | for (int i = 0; i < inNumOctaves; i++) 53 | { 54 | result += amp * ValueNoise31(x * freq, float3(boundary, boundary, boundary)); 55 | amp *= 0.5; 56 | freq *= 2.0; 57 | norm += amp; 58 | } 59 | 60 | return result / norm; 61 | } 62 | 63 | float4 Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 64 | { 65 | float4 outColor = float4(0.0, 0.0, 0.0, 1.0); 66 | 67 | float h = TilableFbm31(frac(inUV.xyy * 1.0), 15, 8); 68 | outColor.xyz = pow(h.xxx, 1.5); 69 | 70 | return outColor; 71 | } 72 | -------------------------------------------------------------------------------- /shader/noise/TilableNoise3dPS.hlsl: -------------------------------------------------------------------------------- 1 | #include "../Random.hlsl" 2 | #include "../Util.hlsl" 3 | #include "../Screen.h" 4 | 5 | //=============================================== 6 | float ValueNoise31(float3 x, float3 boundary) 7 | { 8 | float3 b = boundary; 9 | float3 p = floor(x); 10 | float3 f = frac(x); 11 | f = f * f * (3.0 - 2.0 * f); 12 | 13 | return lerp( 14 | lerp( 15 | lerp( 16 | Hash31(fmod(p + float3(0, 0, 0), b)), 17 | Hash31(fmod(p + float3(1, 0, 0), b)), 18 | f.x 19 | ), 20 | lerp( 21 | Hash31(fmod(p + float3(0, 1, 0), b)), 22 | Hash31(fmod(p + float3(1, 1, 0), b)), 23 | f.x 24 | ), 25 | f.y 26 | ), 27 | lerp( 28 | lerp( 29 | Hash31(fmod(p + float3(0, 0, 1), b)), 30 | Hash31(fmod(p + float3(1, 0, 1), b)), 31 | f.x 32 | ), 33 | lerp( 34 | Hash31(fmod(p + float3(0, 1, 1), b)), 35 | Hash31(fmod(p + float3(1, 1, 1), b)), 36 | f.x 37 | ), 38 | f.y 39 | ), 40 | f.z 41 | ); 42 | } 43 | 44 | // x = [0,1] 45 | float TilableFbm31(float3 x, float inFrequency, const int inNumOctaves) 46 | { 47 | const float boundary = inFrequency; // take the boundary at max of 1st octave 48 | 49 | float amp = 1.0; 50 | float freq = inFrequency; 51 | float result= 0.0; 52 | float norm = amp; 53 | for (int i = 0; i < inNumOctaves; i++) 54 | { 55 | result += amp * ValueNoise31(x * freq, float3(boundary, boundary, boundary)); 56 | amp *= 0.5; 57 | freq *= 2.0; 58 | norm += amp; 59 | } 60 | 61 | return result / norm; 62 | } 63 | 64 | float4 Entry(float4 inPosition : SV_POSITION, float2 inUV : TexCoord) : SV_Target 65 | { 66 | const float depth = GetWQ().x; 67 | const float3 uvw = float3(inUV, depth); 68 | 69 | float4 outColor = float4(0.0, 0.0, 0.0, 1.0); 70 | 71 | float h = TilableFbm31(uvw, 16, 8); 72 | outColor.xyz = h.xxx; 73 | 74 | return outColor; 75 | } 76 | -------------------------------------------------------------------------------- /src/app/PrecomputedAtmosphericScattering/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(project_name PrecomputedAtmosphericScattering) 2 | 3 | AddApplicationProject(${project_name}) 4 | 5 | # Properties->Linker->Input->Additional Dependencies 6 | target_link_libraries (${project_name} etc) 7 | target_link_libraries (${project_name} math) 8 | target_link_libraries (${project_name} window) 9 | target_link_libraries (${project_name} imgui) 10 | target_link_libraries (${project_name} gpu) 11 | 12 | if(MSVC) 13 | # Set the entry point 14 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /subsystem:console /ENTRY:mainCRTStartup") 15 | endif(MSVC) 16 | -------------------------------------------------------------------------------- /src/app/PrecomputedAtmosphericScattering/Camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "InputEvent.h" 11 | 12 | struct Camera 13 | { 14 | Camera(float x, float y, float z) 15 | { 16 | mCameraOrientation.x = 0.0f; 17 | mCameraOrientation.y = 0.0f; 18 | mPosition.x = x; 19 | mPosition.y = y; 20 | mPosition.z = z; 21 | UpdateCameraRotation(); 22 | } 23 | 24 | virtual ~Camera() {} 25 | 26 | const math::Float3x3& GetRotationMatrix() const { return mRotationMatrix; } 27 | const math::Float3& GetPosition() const { return mPosition; } 28 | void Rotate(float dPhi, float dTheta) { mCameraOrientation.x += dPhi; mCameraOrientation.y += dTheta; } 29 | 30 | enum struct Direction { RIGHT = 0, UP, FORWARD }; 31 | void Move(float dx, Direction dir) 32 | { 33 | int idx = static_cast(dir); 34 | math::Float3 forward(mRotationMatrix[0][idx], mRotationMatrix[1][idx], mRotationMatrix[2][idx]); 35 | mPosition = mPosition + forward * dx; 36 | } 37 | 38 | protected: 39 | math::Float3x3 mRotationMatrix; 40 | math::Float3 mPosition; 41 | math::Float2 mCameraOrientation; 42 | 43 | void UpdateCameraRotation() 44 | { 45 | float& phi = mCameraOrientation.x; 46 | float& theta = mCameraOrientation.y; 47 | phi = std::fmodf(phi, 2.0f * math::PI); 48 | theta = std::fmodf(theta, math::PI); 49 | mRotationMatrix = math::RotationXYZ(theta, phi, 0.0f); 50 | } 51 | }; 52 | 53 | 54 | 55 | struct TouchControlledCamera : Camera 56 | { 57 | TouchControlledCamera(float x, float y, float z) : Camera(x, y, z) {} 58 | virtual ~TouchControlledCamera() {} 59 | 60 | void Touch(float x, float y) { mTouchPos[0] = x; mTouchPos[1] = y; } 61 | void Right(float dx) { mDirectionalPad[0] = dx; } 62 | void Forward(float dy) { mDirectionalPad[1] = dy; } 63 | 64 | void Update(const float dt) 65 | { 66 | const float dcx = mTouchPos[0] - mPrevTouchPos[0]; 67 | const float dcy = mTouchPos[1] - mPrevTouchPos[1]; 68 | 69 | if (mToggleBitSet[static_cast(Toggle::ROTATE)]) 70 | Rotate(mRotationSpeed * dcx * dt, mRotationSpeed * dcy * dt); 71 | 72 | if (mToggleBitSet[static_cast(Toggle::UP_RIGHT)]) 73 | { 74 | Move(dcy * mTranslationSpeed * dt, Direction::UP); 75 | Move(dcx * mTranslationSpeed * dt, Direction::RIGHT); 76 | } 77 | 78 | if (mToggleBitSet[static_cast(Toggle::FORWARD)]) 79 | Move(dcy * mTranslationSpeed * dt, Direction::FORWARD); 80 | 81 | Move(mDirectionalPad[0] * mTranslationSpeed * dt, Direction::RIGHT); 82 | Move(mDirectionalPad[1] * mTranslationSpeed * dt, Direction::FORWARD); 83 | 84 | // store the cursor position 85 | mPrevTouchPos[0] = mTouchPos[0]; 86 | mPrevTouchPos[1] = mTouchPos[1]; 87 | 88 | UpdateCameraRotation(); 89 | } 90 | 91 | enum struct Toggle : std::uint8_t 92 | { 93 | NONE = 0, 94 | ROTATE = 1, 95 | UP_RIGHT = 2, 96 | FORWARD = 3, 97 | }; 98 | 99 | void ClearToggle() { mToggleBitSet &= 0; } 100 | 101 | void SwitchToggle(Toggle inToggle, bool isEnable) 102 | { 103 | std::uint8_t i = static_cast(inToggle); 104 | if (isEnable) 105 | mToggleBitSet.set(i); 106 | else 107 | mToggleBitSet.reset(i); 108 | } 109 | 110 | protected: 111 | float mDirectionalPad[2] = { 0.0f }; 112 | float mTouchPos[2] = { 0.0f }; 113 | float mPrevTouchPos[2] = { 0.0f }; 114 | float mRotationSpeed = 1.5e2f; 115 | float mTranslationSpeed = 5e2f; 116 | std::bitset<8> mToggleBitSet; 117 | }; 118 | 119 | //========================================================================== 120 | 121 | struct InputEventForCamera 122 | { 123 | InputEventForCamera(InputEventHandler& inEventHandler, wnd::WindowBase& inWindow, TouchControlledCamera& inCamera, const ImGuiIO& inImGuiIO) 124 | : mWindow(inWindow), mCamera(inCamera), mImGuiIO(inImGuiIO) 125 | { 126 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_BUTTONDOWN, std::bind(&InputEventForCamera::OnMouseDown, this, std::placeholders::_1)); 127 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_BUTTONUP, std::bind(&InputEventForCamera::OnMouseUp, this, std::placeholders::_1)); 128 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_MOVE, std::bind(&InputEventForCamera::OnMouseMove, this, std::placeholders::_1)); 129 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_DOWN, std::bind(&InputEventForCamera::OnKeyDown, this, std::placeholders::_1)); 130 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_UP, std::bind(&InputEventForCamera::OnKeyUp, this, std::placeholders::_1)); 131 | } 132 | 133 | void OnMouseDown(const wnd::InputArgument& arg) 134 | { 135 | // if (!mIsAltKeyDown) return; 136 | if (mImGuiIO.WantCaptureMouse) return; 137 | switch (arg.index) 138 | { 139 | case 0: // LEFT 140 | mCamera.SwitchToggle(TouchControlledCamera::Toggle::ROTATE, true); 141 | break; 142 | case 1: // RIGHT 143 | mCamera.SwitchToggle(TouchControlledCamera::Toggle::FORWARD, true); 144 | break; 145 | case 2: // MIDDLE 146 | mCamera.SwitchToggle(TouchControlledCamera::Toggle::UP_RIGHT, true); 147 | break; 148 | default: 149 | break; 150 | } 151 | } 152 | 153 | void OnMouseUp(const wnd::InputArgument& arg) 154 | { 155 | // if (!mIsAltKeyDown) return; 156 | switch (arg.index) 157 | { 158 | case 0: // LEFT 159 | mCamera.SwitchToggle(TouchControlledCamera::Toggle::ROTATE, false); 160 | break; 161 | case 1: // RIGHT 162 | mCamera.SwitchToggle(TouchControlledCamera::Toggle::FORWARD, false); 163 | break; 164 | case 2: // MIDDLE 165 | mCamera.SwitchToggle(TouchControlledCamera::Toggle::UP_RIGHT, false); 166 | break; 167 | default: 168 | break; 169 | } 170 | } 171 | 172 | void OnMouseMove(const wnd::InputArgument& arg) 173 | { 174 | auto mouse_pos_x = arg.x; 175 | auto mouse_pos_y = arg.y; 176 | float nx = static_cast(mouse_pos_x) / mWindow.GetInfo().mWindowSize[0]; 177 | float ny = static_cast(mouse_pos_y) / mWindow.GetInfo().mWindowSize[1]; 178 | nx = nx < 0.0f ? 0.0f : (nx > 1.0f ? 1.0f : nx); 179 | ny = ny < 0.0f ? 0.0f : (ny > 1.0f ? 1.0f : ny); 180 | mCamera.Touch(nx, ny); 181 | } 182 | 183 | void OnKeyDown(const wnd::InputArgument& arg) 184 | { 185 | switch (arg.index) 186 | { 187 | case 0x12: // Alt 188 | mIsAltKeyDown = true; 189 | break; 190 | case 0x41: // A 191 | case 0x25: // Left arrow 192 | mCamera.Right(-0.2f); 193 | break; 194 | case 0x44: // D 195 | case 0x27: // Right arrow 196 | mCamera.Right(0.2f); 197 | break; 198 | case 0x53: // S 199 | case 0x28: // Down arrow 200 | mCamera.Forward(-0.2f); 201 | break; 202 | case 0x57: // W 203 | case 0x26: // Up arrow 204 | mCamera.Forward(0.2f); 205 | break; 206 | default: 207 | break; 208 | } 209 | } 210 | 211 | void OnKeyUp(const wnd::InputArgument& arg) 212 | { 213 | switch (arg.index) 214 | { 215 | case 0x12: // Alt 216 | mIsAltKeyDown = false; 217 | break; 218 | case 0x41: // A 219 | case 0x44: // D 220 | case 0x25: // Left arrow 221 | case 0x27: // Right arrow 222 | mCamera.Right(0.0f); 223 | break; 224 | case 0x53: // S 225 | case 0x57: // W 226 | case 0x28: // Down arrow 227 | case 0x26: // Up arrow 228 | mCamera.Forward(0.0f); 229 | break; 230 | default: 231 | break; 232 | } 233 | } 234 | 235 | private: 236 | TouchControlledCamera & mCamera; 237 | wnd::WindowBase& mWindow; 238 | const ImGuiIO& mImGuiIO; 239 | bool mIsAltKeyDown = false; 240 | }; 241 | 242 | 243 | struct InputEventForShader 244 | { 245 | InputEventForShader(InputEventHandler& inEventHandler, wnd::WindowBase& inWindow) : mWindow(inWindow) 246 | { 247 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_BUTTONDOWN, std::bind(&InputEventForShader::OnMouseDown, this, std::placeholders::_1)); 248 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_BUTTONUP, std::bind(&InputEventForShader::OnMouseUp, this, std::placeholders::_1)); 249 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_MOVE, std::bind(&InputEventForShader::OnMouseMove, this, std::placeholders::_1)); 250 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_DOWN, std::bind(&InputEventForShader::OnKeyDown, this, std::placeholders::_1)); 251 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_UP, std::bind(&InputEventForShader::OnKeyUp, this, std::placeholders::_1)); 252 | } 253 | 254 | void OnMouseDown(const wnd::InputArgument& arg) 255 | { 256 | switch (arg.index) 257 | { 258 | case 0: // LEFT 259 | mIsMouseButtonDown = true; 260 | break; 261 | case 1: // RIGHT 262 | break; 263 | case 2: // MIDDLE 264 | break; 265 | default: 266 | break; 267 | } 268 | } 269 | 270 | void OnMouseUp(const wnd::InputArgument& arg) 271 | { 272 | switch (arg.index) 273 | { 274 | case 0: // LEFT 275 | mIsMouseButtonDown = false; 276 | break; 277 | case 1: // RIGHT 278 | break; 279 | case 2: // MIDDLE 280 | break; 281 | default: 282 | break; 283 | } 284 | } 285 | 286 | void OnMouseMove(const wnd::InputArgument& arg) 287 | { 288 | if (!mIsMouseButtonDown) return; 289 | mMouseX = arg.x; 290 | mMouseY = arg.y; 291 | } 292 | 293 | void OnKeyDown(const wnd::InputArgument&) 294 | { 295 | } 296 | 297 | void OnKeyUp(const wnd::InputArgument&) 298 | { 299 | } 300 | 301 | auto GetMouseX() const { return mMouseX; } 302 | auto GetMouseY() const { return mMouseY; } 303 | private: 304 | wnd::WindowBase& mWindow; 305 | std::uint16_t mMouseX = 0; 306 | std::uint16_t mMouseY = 0; 307 | bool mIsMouseButtonDown = false; 308 | }; 309 | -------------------------------------------------------------------------------- /src/app/PrecomputedAtmosphericScattering/InputEvent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | struct InputEventHandler 7 | { 8 | InputEventHandler(wnd::WindowBase& inWindow) 9 | { 10 | for (int i = 0; i < static_cast(wnd::InputEvent::COUNT); ++i) 11 | { 12 | auto ev = static_cast(i); 13 | inWindow.RegisterInputEventCallbackFunc(ev, std::bind(&InputEventHandler::OnInputEvent, this, ev, std::placeholders::_1)); 14 | } 15 | } 16 | 17 | template 18 | void RegisterInputEventObserver(wnd::InputEvent&& event, Observer&& observer) 19 | { 20 | mInputEventHandler.Register(std::move(event), std::forward(observer)); 21 | } 22 | 23 | void OnInputEvent(wnd::InputEvent inEvent, const wnd::InputArgument& inArg) 24 | { 25 | mInputEventHandler.Notify(inEvent, inArg); 26 | } 27 | 28 | protected: 29 | etc::EventHandler mInputEventHandler; 30 | }; 31 | 32 | //================================================================= 33 | 34 | struct InputEventForImGui 35 | { 36 | InputEventForImGui(InputEventHandler& inEventHandler, ImGuiIO& inImGuiIO) : mImGuiIO(inImGuiIO) 37 | { 38 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_BUTTONDOWN, std::bind(&InputEventForImGui::OnMouseDown, this, std::placeholders::_1)); 39 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_BUTTONUP, std::bind(&InputEventForImGui::OnMouseUp, this, std::placeholders::_1)); 40 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_WHEEL, std::bind(&InputEventForImGui::OnMouseWheel, this, std::placeholders::_1)); 41 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_MOVE, std::bind(&InputEventForImGui::OnMouseMove, this, std::placeholders::_1)); 42 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_DOWN, std::bind(&InputEventForImGui::OnKeyDown, this, std::placeholders::_1)); 43 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_UP, std::bind(&InputEventForImGui::OnKeyUp, this, std::placeholders::_1)); 44 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_CHAR, std::bind(&InputEventForImGui::OnChar, this, std::placeholders::_1)); 45 | } 46 | 47 | void OnMouseDown(const wnd::InputArgument& arg) 48 | { 49 | mImGuiIO.MouseDown[arg.index] = true; 50 | } 51 | 52 | void OnMouseUp(const wnd::InputArgument& arg) 53 | { 54 | mImGuiIO.MouseDown[arg.index] = false; 55 | } 56 | 57 | void OnMouseWheel(const wnd::InputArgument& arg) 58 | { 59 | mImGuiIO.MouseWheel += arg.index > 0 ? +1.0f : -1.0f; 60 | } 61 | 62 | void OnMouseMove(const wnd::InputArgument& arg) 63 | { 64 | mImGuiIO.MousePos.x = arg.x; 65 | mImGuiIO.MousePos.y = arg.y; 66 | } 67 | 68 | void OnKeyDown(const wnd::InputArgument& arg) 69 | { 70 | if(arg.index < 256) 71 | mImGuiIO.KeysDown[arg.index] = 1; 72 | } 73 | 74 | void OnKeyUp(const wnd::InputArgument& arg) 75 | { 76 | if (arg.index < 256) 77 | mImGuiIO.KeysDown[arg.index] = 0; 78 | } 79 | 80 | void OnChar(const wnd::InputArgument& arg) 81 | { 82 | if (arg.index > 0 && arg.index < 0x10000) 83 | mImGuiIO.AddInputCharacter(static_cast(arg.index)); 84 | } 85 | 86 | private: 87 | ImGuiIO& mImGuiIO; 88 | }; 89 | -------------------------------------------------------------------------------- /src/app/PrecomputedAtmosphericScattering/main.cpp: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // 3 | //-------------------------------------------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "InputEvent.h" 17 | #include "Camera.h" 18 | 19 | /* 20 | Calculate the scattering coefficients[Yusov13] 21 | @return scattering coefficients (R, G, B) [10^{-6}/m] 22 | */ 23 | math::Float3 ComputeRayleighScatteringCoefficients() 24 | { 25 | // For details, see "A practical Analytic Model for Daylight" by Preetham & Hoffman, p.23 26 | 27 | // Wave lengths 28 | // [BN08] follows [REK04] and gives the following values for Rayleigh scattering coefficients: 29 | // RayleighBeta(lambda = (680nm, 550nm, 440nm) ) = (5.8, 13.5, 33.1)e-6 30 | static const double dWaveLengths[] = 31 | { 32 | 680e-9, // red 33 | 550e-9, // green 34 | 440e-9 // blue 35 | }; 36 | 37 | math::Float3 out_coeff; 38 | 39 | // Calculate angular and total scattering coefficients for Rayleigh scattering: 40 | { 41 | double n = 1.0003; // - Refractive index of air in the visible spectrum 42 | double N = 2.545e+25; // - Number of molecules per unit volume 43 | double Pn = 0.035; // - Depolarization factor for air which expresses corrections 44 | // due to anisotropy of air molecules 45 | 46 | double dRayleighConst = 8.0*math::PI*math::PI*math::PI * (n*n - 1.0) * (n*n - 1.0) / (3.0 * N) * (6.0 + 3.0*Pn) / (6.0 - 7.0*Pn); 47 | for (int i = 0; i < 3; ++i) 48 | { 49 | double dSctrCoeff; 50 | { 51 | double Lambda2 = dWaveLengths[i] * dWaveLengths[i]; 52 | double Lambda4 = Lambda2 * Lambda2; 53 | dSctrCoeff = dRayleighConst / Lambda4; 54 | // Total Rayleigh scattering coefficient is the integral of angular scattering coefficient in all directions 55 | out_coeff[i] = static_cast(dSctrCoeff); 56 | } 57 | } 58 | // Air molecules do not absorb light, so extinction coefficient is only caused by out-scattering 59 | } 60 | return out_coeff; 61 | } 62 | 63 | //-------------------------------------------------------------------------------------------- 64 | // Utility class for full screen triangle 65 | //-------------------------------------------------------------------------------------------- 66 | template 67 | struct Screen 68 | { 69 | static_assert(TNumTextures <= TUpdater::sMaxNumResourceTextures, "Too many resource textures"); 70 | 71 | Screen() {} 72 | 73 | Screen(Device& inDevice, const TextureDesc& inDesc) 74 | { 75 | ScreenCreationContext creation_context(inDevice); 76 | for(size_t i = 0; i < TNumTextures; ++i) 77 | { 78 | mTextures[i] = std::make_unique(inDevice, inDesc); 79 | creation_context.mResourceTextures[i] = mTextures[i].get(); 80 | } 81 | mScreen = std::make_unique(creation_context); 82 | } 83 | 84 | Screen(Device& inDevice, std::array inTextures) 85 | { 86 | ScreenCreationContext creation_context(inDevice); 87 | for (size_t i = 0; i < TNumTextures; ++i) 88 | creation_context.mResourceTextures[i] = inTextures[i]; 89 | mScreen = std::make_unique(creation_context); 90 | } 91 | 92 | void Update() 93 | { 94 | mScreen->Update(mUpdateContext); 95 | } 96 | 97 | ScreenUpdateContext& GetUpdateContext() { return mUpdateContext; } 98 | 99 | const TTexture& GetTexture(size_t index) const { return *mTextures.at(index); } 100 | 101 | protected: 102 | std::unique_ptr mScreen = nullptr; 103 | std::array, TNumTextures> mTextures = { nullptr }; 104 | ScreenUpdateContext mUpdateContext; 105 | }; 106 | template using ScreenBuffer2D = Screen; 107 | template using ScreenBuffer3D = Screen; 108 | using PrimaryScreen = Screen; 109 | 110 | //-------------------------------------------------------------------------------------------- 111 | // Precomputed Atmospheric Scattering 112 | //-------------------------------------------------------------------------------------------- 113 | struct PrecomputedAtmosphericScattering 114 | { 115 | enum BufferType { 116 | BUF_OPTICAL_DEPTH = 0, 117 | BUF_SINGLE_SCATTERING, 118 | BUF_MULTIPLE_SCATTERING, 119 | BUF_GATHER_INSCATTER, 120 | BUF_ACCUMULATE_INSCATTER, 121 | BUF_TOTAL_INSCATTER, 122 | BUF_PACK_INSCATTER, 123 | NUM_BUFFERS, 124 | }; 125 | 126 | enum TextureIndex { 127 | RAYLEIGH = 0, 128 | MIE, 129 | }; 130 | 131 | struct Desc 132 | { 133 | TextureDesc mTextureDesc[NUM_BUFFERS]; 134 | SamplerDesc mSamplerLinearClampDesc; 135 | BlendStateDesc mNoBlendDesc; 136 | BlendStateDesc mAddBlendDesc; 137 | Desc() 138 | { 139 | mSamplerLinearClampDesc.mBoundaryCondition = SamplerBoundaryCondition::CLAMP; 140 | mAddBlendDesc.mBlendType = BlendType::ADDITIVE; 141 | mNoBlendDesc.mBlendType = BlendType::NONE; 142 | 143 | mTextureDesc[BUF_OPTICAL_DEPTH].mHeight = 512; 144 | mTextureDesc[BUF_OPTICAL_DEPTH].mWidth = 512; 145 | mTextureDesc[BUF_OPTICAL_DEPTH].mFormat = TextureFormat::R32G32; 146 | 147 | mTextureDesc[BUF_SINGLE_SCATTERING].mWidth = TEX4D_U; 148 | mTextureDesc[BUF_SINGLE_SCATTERING].mHeight = TEX4D_V; 149 | mTextureDesc[BUF_SINGLE_SCATTERING].mDepth = TEX4D_W; 150 | 151 | mTextureDesc[BUF_GATHER_INSCATTER].mWidth = TEX4D_U; 152 | mTextureDesc[BUF_GATHER_INSCATTER].mHeight = TEX4D_V; 153 | mTextureDesc[BUF_GATHER_INSCATTER].mDepth = TEX4D_W; 154 | 155 | mTextureDesc[BUF_MULTIPLE_SCATTERING].mWidth = TEX4D_U; 156 | mTextureDesc[BUF_MULTIPLE_SCATTERING].mHeight = TEX4D_V; 157 | mTextureDesc[BUF_MULTIPLE_SCATTERING].mDepth = TEX4D_W; 158 | 159 | mTextureDesc[BUF_ACCUMULATE_INSCATTER].mWidth = TEX4D_U; 160 | mTextureDesc[BUF_ACCUMULATE_INSCATTER].mHeight = TEX4D_V; 161 | mTextureDesc[BUF_ACCUMULATE_INSCATTER].mDepth = TEX4D_W; 162 | 163 | mTextureDesc[BUF_TOTAL_INSCATTER].mWidth = TEX4D_U; 164 | mTextureDesc[BUF_TOTAL_INSCATTER].mHeight = TEX4D_V; 165 | mTextureDesc[BUF_TOTAL_INSCATTER].mDepth = TEX4D_W; 166 | 167 | mTextureDesc[BUF_PACK_INSCATTER].mWidth = TEX4D_U; 168 | mTextureDesc[BUF_PACK_INSCATTER].mHeight = TEX4D_V; 169 | mTextureDesc[BUF_PACK_INSCATTER].mDepth = TEX4D_W; 170 | } 171 | }; 172 | 173 | PrecomputedAtmosphericScattering(Device& inDevice, const Desc& inDesc) 174 | : mDevice(inDevice) 175 | , mDesc(inDesc) 176 | , mTotalInscatter(inDevice, inDesc.mTextureDesc[BUF_TOTAL_INSCATTER]) 177 | , mPackInscatter(inDevice, inDesc.mTextureDesc[BUF_PACK_INSCATTER]) 178 | , mSamplerLinearClamp(inDevice, inDesc.mSamplerLinearClampDesc) 179 | , mNoBlend(inDevice, inDesc.mNoBlendDesc) 180 | , mAddBlend(inDevice, inDesc.mAddBlendDesc) 181 | { 182 | { 183 | // single scattering + multiple scattering 184 | ScreenUpdateContext& ctx = mTotalInscatter.GetUpdateContext(); 185 | ctx.mPixelShader = &mPixelShaders[BUF_TOTAL_INSCATTER]; 186 | ctx.mVertexShader = &mVertexShader; 187 | ctx.mBlendState = &mNoBlend; 188 | ctx.mTextureSamplers[0] = &mSamplerLinearClamp; 189 | } 190 | 191 | { 192 | // single scattering + multiple scattering with packing into a single texture 193 | ScreenUpdateContext& ctx = mPackInscatter.GetUpdateContext(); 194 | ctx.mPixelShader = &mPixelShaders[BUF_PACK_INSCATTER]; 195 | ctx.mVertexShader = &mVertexShader; 196 | ctx.mBlendState = &mNoBlend; 197 | ctx.mTextureSamplers[0] = &mSamplerLinearClamp; 198 | } 199 | 200 | ResetScatteringParameters(Planet::Earth); 201 | CompileShaders(); 202 | CreateBuffers(); 203 | } 204 | 205 | void ReleaseBuffers() 206 | { 207 | mOpticalDepth = nullptr; 208 | mSingleScattering = nullptr; 209 | mInscatterGathering = nullptr; 210 | mMultipleScattering = nullptr; 211 | mAccumulateInscatter = nullptr; 212 | } 213 | 214 | void CreateBuffers() 215 | { 216 | assert(mOpticalDepth == nullptr); 217 | assert(mSingleScattering == nullptr); 218 | assert(mInscatterGathering == nullptr); 219 | assert(mMultipleScattering == nullptr); 220 | assert(mAccumulateInscatter == nullptr); 221 | 222 | // Create buffers 223 | { 224 | // optical depth 225 | mOpticalDepth = std::make_unique< ScreenBuffer2D<1> >(mDevice, mDesc.mTextureDesc[BUF_OPTICAL_DEPTH]); 226 | ScreenUpdateContext& ctx = mOpticalDepth->GetUpdateContext(); 227 | ctx.mPixelShader = &mPixelShaders[BUF_OPTICAL_DEPTH]; 228 | ctx.mVertexShader = &mVertexShader; 229 | ctx.mBlendState = &mNoBlend; 230 | } 231 | { 232 | // inscatter 233 | mSingleScattering = std::make_unique< ScreenBuffer3D<2> >(mDevice, mDesc.mTextureDesc[BUF_SINGLE_SCATTERING]); 234 | ScreenUpdateContext& ctx = mSingleScattering->GetUpdateContext(); 235 | ctx.mPixelShader = &mPixelShaders[BUF_SINGLE_SCATTERING]; 236 | ctx.mVertexShader = &mVertexShader; 237 | ctx.mBlendState = &mNoBlend; 238 | ctx.mTextureSamplers[0] = &mSamplerLinearClamp; 239 | } 240 | { 241 | // inscatter gather 242 | mInscatterGathering = std::make_unique< ScreenBuffer3D<2> >(mDevice, mDesc.mTextureDesc[BUF_GATHER_INSCATTER]); 243 | ScreenUpdateContext& ctx = mInscatterGathering->GetUpdateContext(); 244 | ctx.mPixelShader = &mPixelShaders[BUF_GATHER_INSCATTER]; 245 | ctx.mVertexShader = &mVertexShader; 246 | ctx.mBlendState = &mNoBlend; 247 | ctx.mTextureSamplers[0] = &mSamplerLinearClamp; 248 | } 249 | { 250 | // multiple scattering 251 | mMultipleScattering = std::make_unique< ScreenBuffer3D<2> >(mDevice, mDesc.mTextureDesc[BUF_MULTIPLE_SCATTERING]); 252 | ScreenUpdateContext& ctx = mMultipleScattering->GetUpdateContext(); 253 | ctx.mPixelShader = &mPixelShaders[BUF_MULTIPLE_SCATTERING]; 254 | ctx.mVertexShader = &mVertexShader; 255 | ctx.mBlendState = &mNoBlend; 256 | ctx.mTextureSamplers[0] = &mSamplerLinearClamp; 257 | } 258 | { 259 | // accumulate multiple scattering 260 | mAccumulateInscatter = std::make_unique< ScreenBuffer3D<2> >(mDevice, mDesc.mTextureDesc[BUF_ACCUMULATE_INSCATTER]); 261 | ScreenUpdateContext& ctx = mAccumulateInscatter->GetUpdateContext(); 262 | ctx.mPixelShader = &mPixelShaders[BUF_ACCUMULATE_INSCATTER]; 263 | ctx.mVertexShader = &mVertexShader; 264 | ctx.mBlendState = &mAddBlend; 265 | ctx.mTextureSamplers[0] = &mSamplerLinearClamp; 266 | } 267 | } 268 | 269 | enum class Planet { Earth = 0, Mars }; 270 | void ResetScatteringParameters(Planet inPlanet) 271 | { 272 | // ToDo: scattering coeff. calculation (https://www.cs.utah.edu/~shirley/papers/sunsky/sunsky.pdf, Appendix 3) 273 | auto& param = mPrecomputedParam; 274 | switch (inPlanet) 275 | { 276 | case PrecomputedAtmosphericScattering::Planet::Earth: 277 | param.mRayleighSctrCoeff = 1e6f * ComputeRayleighScatteringCoefficients(); 278 | param.mRayleighScaleHeight = 7.997f; 279 | param.mMieSctrCoeff = math::Float3(20.0f, 20.0f, 20.0f); 280 | param.mMieScaleHeight = 1.2f; 281 | param.mMieAbsorption = 1.11f; 282 | break; 283 | default: 284 | assert(false); 285 | } 286 | } 287 | 288 | void UpdateShaderParameters(ScreenUpdateContext::ShaderParam& inParam, size_t inStartIndex = 0) 289 | { 290 | assert(inStartIndex + 2 < inParam.mFloat4.size()); 291 | const auto& param = mPrecomputedParam; 292 | inParam.mFloat4.at(inStartIndex + 0).x = param.mRayleighSctrCoeff.x * 1e-3f; 293 | inParam.mFloat4.at(inStartIndex + 0).y = param.mRayleighSctrCoeff.y * 1e-3f; 294 | inParam.mFloat4.at(inStartIndex + 0).z = param.mRayleighSctrCoeff.z * 1e-3f; 295 | inParam.mFloat4.at(inStartIndex + 0).w = param.mRayleighScaleHeight; 296 | inParam.mFloat4.at(inStartIndex + 1).x = param.mMieSctrCoeff.x * 1e-3f; 297 | inParam.mFloat4.at(inStartIndex + 1).y = param.mMieSctrCoeff.y * 1e-3f; 298 | inParam.mFloat4.at(inStartIndex + 1).z = param.mMieSctrCoeff.z * 1e-3f; 299 | inParam.mFloat4.at(inStartIndex + 1).w = param.mMieScaleHeight; 300 | inParam.mFloat4.at(inStartIndex + 2).x = param.mMieAbsorption; 301 | } 302 | 303 | void UpdateShaderParameters() 304 | { 305 | UpdateShaderParameters(mOpticalDepth->GetUpdateContext().mShaderParam); 306 | UpdateShaderParameters(mSingleScattering->GetUpdateContext().mShaderParam); 307 | UpdateShaderParameters(mInscatterGathering->GetUpdateContext().mShaderParam); 308 | UpdateShaderParameters(mMultipleScattering->GetUpdateContext().mShaderParam); 309 | } 310 | 311 | void CompileShaders() 312 | { 313 | std::string error_message; 314 | for (auto& ps : mPixelShaders) 315 | if (!ps.Compile(mDevice, error_message)) 316 | std::cout << error_message << std::endl; 317 | if (!mVertexShader.Compile(mDevice, error_message)) 318 | std::cout << error_message << std::endl; 319 | } 320 | 321 | void GeneratePrecomputedTexture() 322 | { 323 | 324 | ReleaseBuffers(); 325 | CreateBuffers(); 326 | UpdateShaderParameters(); 327 | 328 | { 329 | // optical depth 330 | mOpticalDepth->Update(); 331 | } 332 | { 333 | // single scattering 334 | ScreenUpdateContext& ctx = mSingleScattering->GetUpdateContext(); 335 | ctx.mInputTexture2Ds[0] = &mOpticalDepth->GetTexture(0); 336 | mSingleScattering->Update(); 337 | } 338 | 339 | // 340 | // Multiple scattering 341 | // 342 | if(mNumScattering > 1) 343 | { 344 | { 345 | // gather inscatter 346 | ScreenUpdateContext& ctx = mInscatterGathering->GetUpdateContext(); 347 | ctx.mInputTexture3Ds[RAYLEIGH] = &mSingleScattering->GetTexture(RAYLEIGH); 348 | ctx.mInputTexture3Ds[MIE] = &mSingleScattering->GetTexture(MIE); 349 | mInscatterGathering->Update(); 350 | } 351 | { 352 | // multiple scattering 353 | ScreenUpdateContext& ctx = mMultipleScattering->GetUpdateContext(); 354 | ctx.mInputTexture2Ds[0] = &mOpticalDepth->GetTexture(0); 355 | ctx.mInputTexture3Ds[RAYLEIGH] = &mInscatterGathering->GetTexture(RAYLEIGH); 356 | ctx.mInputTexture3Ds[MIE] = &mInscatterGathering->GetTexture(MIE); 357 | mMultipleScattering->Update(); 358 | } 359 | { 360 | // accumulate multiple scattering 361 | ScreenUpdateContext& ctx = mAccumulateInscatter->GetUpdateContext(); 362 | ctx.mInputTexture3Ds[RAYLEIGH] = &mMultipleScattering->GetTexture(RAYLEIGH); 363 | ctx.mInputTexture3Ds[MIE] = &mMultipleScattering->GetTexture(MIE); 364 | mAccumulateInscatter->Update(); 365 | } 366 | } 367 | 368 | for (std::uint32_t i = 2; i < mNumScattering; ++i) 369 | { 370 | { 371 | // gather inscattering 372 | ScreenUpdateContext& ctx = mInscatterGathering->GetUpdateContext(); 373 | ctx.mInputTexture3Ds[RAYLEIGH] = &mMultipleScattering->GetTexture(RAYLEIGH); 374 | ctx.mInputTexture3Ds[MIE] = &mMultipleScattering->GetTexture(MIE); 375 | mInscatterGathering->Update(); 376 | } 377 | { 378 | // multiple scattering 379 | ScreenUpdateContext& ctx = mMultipleScattering->GetUpdateContext(); 380 | ctx.mInputTexture2Ds[0] = &mOpticalDepth->GetTexture(0); 381 | ctx.mInputTexture3Ds[RAYLEIGH] = &mInscatterGathering->GetTexture(RAYLEIGH); 382 | ctx.mInputTexture3Ds[MIE] = &mInscatterGathering->GetTexture(MIE); 383 | mMultipleScattering->Update(); 384 | } 385 | { 386 | // accumulate multiple scattering 387 | ScreenUpdateContext& ctx = mAccumulateInscatter->GetUpdateContext(); 388 | ctx.mInputTexture3Ds[RAYLEIGH] = &mMultipleScattering->GetTexture(RAYLEIGH); 389 | ctx.mInputTexture3Ds[MIE] = &mMultipleScattering->GetTexture(MIE); 390 | mAccumulateInscatter->Update(); 391 | } 392 | } 393 | 394 | // 395 | // Result 396 | // 397 | { 398 | // single scattering + multiple scattering 399 | ScreenUpdateContext& ctx = mTotalInscatter.GetUpdateContext(); 400 | ctx.mInputTexture3Ds[RAYLEIGH] = &mSingleScattering->GetTexture(RAYLEIGH); 401 | ctx.mInputTexture3Ds[MIE] = &mSingleScattering->GetTexture(MIE); 402 | ctx.mInputTexture3Ds[RAYLEIGH + 2] = &mAccumulateInscatter->GetTexture(RAYLEIGH); 403 | ctx.mInputTexture3Ds[MIE + 2] = &mAccumulateInscatter->GetTexture(MIE); 404 | mTotalInscatter.Update(); 405 | } 406 | 407 | { 408 | // single scattering + multiple scattering with packing into a single texture 409 | ScreenUpdateContext& ctx = mPackInscatter.GetUpdateContext(); 410 | ctx.mInputTexture3Ds[RAYLEIGH] = &mSingleScattering->GetTexture(RAYLEIGH); 411 | ctx.mInputTexture3Ds[MIE] = &mSingleScattering->GetTexture(MIE); 412 | ctx.mInputTexture3Ds[RAYLEIGH + 2] = &mAccumulateInscatter->GetTexture(RAYLEIGH); 413 | ctx.mInputTexture3Ds[MIE + 2] = &mAccumulateInscatter->GetTexture(MIE); 414 | mPackInscatter.Update(); 415 | } 416 | } 417 | 418 | const Texture3D& GetSingleScatteringTexture(TextureIndex index) const { return mSingleScattering->GetTexture(index); } 419 | const Texture3D& GetMultipleScatteringTexture(TextureIndex index) const { return mMultipleScattering->GetTexture(index); } 420 | const Texture2D& GetOpticalDepthTexture() const { return mOpticalDepth->GetTexture(0); } 421 | const Texture3D& GetInscatterGatherTexture(TextureIndex index) const { return mInscatterGathering->GetTexture(index); } 422 | const Texture3D& GetAccumulateInscatterTexture(TextureIndex index) const { return mAccumulateInscatter->GetTexture(index); } 423 | const Texture3D& GetTotalInscatterTexture(TextureIndex index) const { return mTotalInscatter.GetTexture(index); } 424 | const Texture3D& GetPackedTotalInscatterTexture() const { return mPackInscatter.GetTexture(0); } 425 | 426 | PrecomputedSctrParams& GetParam() { return mPrecomputedParam; } 427 | 428 | void SetNumScattering(std::uint32_t n) { mNumScattering = n; } 429 | std::uint32_t GetNumScattering() const { return mNumScattering; } 430 | 431 | protected: 432 | Device& mDevice; 433 | const Desc& mDesc; 434 | PrecomputedSctrParams mPrecomputedParam; 435 | std::uint32_t mNumScattering = 6; 436 | 437 | std::array mPixelShaders = { 438 | "shader/atmosphere/OpticalDepthPS.hlsl", 439 | "shader/atmosphere/SingleScatteringPS.hlsl", 440 | "shader/atmosphere/MultipleScatteringPS.hlsl", 441 | "shader/atmosphere/GatherInscatterPS.hlsl", 442 | "shader/atmosphere/AddScatteringPS.hlsl", 443 | "shader/atmosphere/TotalInscatterPS.hlsl", 444 | "shader/atmosphere/PackInscatterPS.hlsl", 445 | }; 446 | VertexShader mVertexShader = { 447 | "shader/ScreenVS.hlsl" 448 | }; 449 | Sampler mSamplerLinearClamp; 450 | BlendState mNoBlend; 451 | BlendState mAddBlend; 452 | 453 | std::unique_ptr< ScreenBuffer2D<1> > mOpticalDepth = nullptr; 454 | std::unique_ptr< ScreenBuffer3D<2> > mSingleScattering = nullptr; 455 | std::unique_ptr< ScreenBuffer3D<2> > mInscatterGathering = nullptr; 456 | std::unique_ptr< ScreenBuffer3D<2> > mMultipleScattering = nullptr; 457 | std::unique_ptr< ScreenBuffer3D<2> > mAccumulateInscatter= nullptr; 458 | ScreenBuffer3D<2> mTotalInscatter; 459 | ScreenBuffer3D<1> mPackInscatter; 460 | }; 461 | 462 | 463 | //-------------------------------------------------------------------------------------------- 464 | // Main 465 | //-------------------------------------------------------------------------------------------- 466 | int main() 467 | { 468 | int exit_code; 469 | 470 | std::unique_ptr window( wnd::WindowBase::Create() ); 471 | if (!window->Initialize("Precomputed Atmospheric Scattering v0.1")) 472 | { 473 | exit_code = -1; 474 | return exit_code; 475 | } 476 | 477 | void* handle = window->GetWindowHandle(); 478 | Device device(&handle); 479 | ImGui_ImplDX11_Init(handle, &device.GetD3D11Device(), &device.GetD3D11DeviceContext()); 480 | 481 | InputEventHandler input_event_handler(*window); 482 | InputEventForImGui imgui_input_event(input_event_handler, ImGui::GetIO()); 483 | TouchControlledCamera camera(0.0, 6.0f + EARTH_RADIUS, 0.0f); 484 | InputEventForCamera camera_input_event(input_event_handler, *window, camera, ImGui::GetIO()); 485 | 486 | enum PixelShaderIndices : char { 487 | PS_ATMOSPHERIC_SCATTERING, 488 | NUM_PIXELSHADERS, 489 | }; 490 | std::array pixel_shaders = { 491 | "shader/atmosphere/AtmosphericScatteringPS.hlsl", 492 | }; 493 | VertexShader default_vs("shader/ScreenVS.hlsl"); 494 | 495 | std::string error_message; 496 | for (auto& ps : pixel_shaders) 497 | if (!ps.Compile(device, error_message)) 498 | std::cout << error_message << std::endl; 499 | if (!default_vs.Compile(device, error_message)) 500 | std::cout << error_message << std::endl; 501 | BackBuffer back_buffer(device); 502 | 503 | SamplerDesc sampler_clamp_desc; 504 | SamplerDesc sampler_wrap_desc; 505 | sampler_clamp_desc.mBoundaryCondition = SamplerBoundaryCondition::CLAMP; 506 | sampler_wrap_desc.mBoundaryCondition = SamplerBoundaryCondition::WRAP; 507 | Sampler sampler_clamp(device, sampler_clamp_desc); 508 | Sampler sampler_wrap(device, sampler_wrap_desc); 509 | 510 | BlendStateDesc no_blend_desc; 511 | no_blend_desc.mBlendType = BlendType::NONE; 512 | BlendState blend_state_none(device, no_blend_desc); 513 | 514 | // precomputed atmospheric scattering 515 | PrecomputedAtmosphericScattering::Desc atmosphere_desc; 516 | PrecomputedAtmosphericScattering atmosphere(device, atmosphere_desc); 517 | atmosphere.GeneratePrecomputedTexture(); 518 | 519 | // primary screen 520 | std::array primary_screen_textures = { &back_buffer }; 521 | PrimaryScreen primary_screen(device, primary_screen_textures); 522 | { 523 | ScreenUpdateContext& ctx = primary_screen.GetUpdateContext(); 524 | ctx.mPixelShader = &pixel_shaders[PS_ATMOSPHERIC_SCATTERING]; 525 | ctx.mVertexShader = &default_vs; 526 | ctx.mInputTexture3Ds[0] = &atmosphere.GetPackedTotalInscatterTexture(); 527 | ctx.mInputTexture3Ds[1] = &atmosphere.GetTotalInscatterTexture(PrecomputedAtmosphericScattering::RAYLEIGH); 528 | ctx.mInputTexture3Ds[2] = &atmosphere.GetTotalInscatterTexture(PrecomputedAtmosphericScattering::MIE); 529 | ctx.mInputTexture2Ds[0] = &atmosphere.GetOpticalDepthTexture(); 530 | ctx.mTextureSamplers[0] = &sampler_clamp; 531 | ctx.mTextureSamplers[1] = &sampler_wrap; 532 | ctx.mBlendState = &blend_state_none; 533 | } 534 | 535 | const wnd::Info& window_info = window->GetInfo(); 536 | const float window_size[2] = { float(window_info.mWindowSize[0]), float(window_info.mWindowSize[1]) }; 537 | 538 | PrecomputedSctrParams& precomp_params = atmosphere.GetParam(); 539 | RuntimeSctrParams runtime_params; 540 | 541 | auto time_start = std::chrono::system_clock::now(); 542 | auto time_prev = time_start; 543 | bool ui_compilation_requested = false; 544 | bool ui_precomputation_requested = false; 545 | bool ui_use_vsync = true; 546 | float ui_exposure_compensation = -13.5f; 547 | math::Float2 ui_light_angle(89.0f, 120.0f); 548 | while (true) 549 | { 550 | wnd::WindowBase::UpdateResult result; 551 | window->Update(result); 552 | if (result.mState == wnd::WindowBase::UpdateResult::State::Exit) 553 | { 554 | exit_code = result.mExitCode; 555 | break; 556 | } 557 | 558 | auto time_now = std::chrono::system_clock::now(); 559 | float elapsed_time_sec = static_cast(1e-3 * std::chrono::duration_cast(time_now - time_start).count()); 560 | float dt = static_cast(1e-3 * std::chrono::duration_cast(time_now - time_prev).count()); 561 | dt = std::max(1e-3f, dt); 562 | time_prev = time_now; 563 | 564 | float theta = ui_light_angle.x * math::PI / 180.f; 565 | float phi = ui_light_angle.y * math::PI / 180.0f; 566 | math::Float3 light_dir(std::cos(phi) * std::sin(theta), std::cos(theta), std::sin(phi) * std::sin(theta)); 567 | 568 | camera.Update(dt); 569 | const math::Float3x3& camera_rot = camera.GetRotationMatrix(); 570 | const math::Float3& camera_pos = camera.GetPosition(); 571 | 572 | //------------------------- 573 | // Set shader parameters 574 | //------------------------- 575 | { 576 | // primary screen 577 | ScreenUpdateContext& ctx = primary_screen.GetUpdateContext(); 578 | ctx.mShaderParam.mFloat4[0].x = elapsed_time_sec; 579 | ctx.mShaderParam.mFloat4[0].y = window_size[0]; 580 | ctx.mShaderParam.mFloat4[0].z = window_size[1]; 581 | ctx.mShaderParam.mFloat4[1].x = camera_rot[0][0]; 582 | ctx.mShaderParam.mFloat4[1].y = camera_rot[0][1]; 583 | ctx.mShaderParam.mFloat4[1].z = camera_rot[0][2]; 584 | ctx.mShaderParam.mFloat4[1].w = 0.0f; 585 | ctx.mShaderParam.mFloat4[2].x = camera_rot[1][0]; 586 | ctx.mShaderParam.mFloat4[2].y = camera_rot[1][1]; 587 | ctx.mShaderParam.mFloat4[2].z = camera_rot[1][2]; 588 | ctx.mShaderParam.mFloat4[2].w = 0.0f; 589 | ctx.mShaderParam.mFloat4[3].x = camera_rot[2][0]; 590 | ctx.mShaderParam.mFloat4[3].y = camera_rot[2][1]; 591 | ctx.mShaderParam.mFloat4[3].z = camera_rot[2][2]; 592 | ctx.mShaderParam.mFloat4[3].w = 0.0f; 593 | ctx.mShaderParam.mFloat4[4].x = camera_pos[0]; 594 | ctx.mShaderParam.mFloat4[4].y = camera_pos[1]; 595 | ctx.mShaderParam.mFloat4[4].z = camera_pos[2]; 596 | ctx.mShaderParam.mFloat4[4].w = 0.0f; 597 | ctx.mShaderParam.mFloat4[5].x = light_dir.x; 598 | ctx.mShaderParam.mFloat4[5].y = light_dir.y; 599 | ctx.mShaderParam.mFloat4[5].z = light_dir.z; 600 | ctx.mShaderParam.mFloat4[6].y = runtime_params.mMieAsymmetry; 601 | ctx.mShaderParam.mFloat4[6].z = ui_exposure_compensation; 602 | 603 | atmosphere.UpdateShaderParameters(ctx.mShaderParam, 8); 604 | } 605 | 606 | switch (result.mState) 607 | { 608 | case wnd::WindowBase::UpdateResult::State::Idle: 609 | if (ui_compilation_requested) 610 | { 611 | for (auto& ps : pixel_shaders) 612 | if (!ps.Compile(device, error_message)) 613 | std::cout << error_message << std::endl; 614 | if (!default_vs.Compile(device, error_message)) 615 | std::cout << error_message << std::endl; 616 | atmosphere.CompileShaders(); 617 | ui_compilation_requested = false; 618 | } 619 | 620 | if (ui_precomputation_requested) 621 | { 622 | atmosphere.GeneratePrecomputedTexture(); 623 | ScreenUpdateContext& ctx = primary_screen.GetUpdateContext(); 624 | ctx.mInputTexture3Ds[0] = &atmosphere.GetPackedTotalInscatterTexture(); 625 | ctx.mInputTexture3Ds[1] = &atmosphere.GetTotalInscatterTexture(PrecomputedAtmosphericScattering::RAYLEIGH); 626 | ctx.mInputTexture3Ds[2] = &atmosphere.GetTotalInscatterTexture(PrecomputedAtmosphericScattering::MIE); 627 | ctx.mInputTexture2Ds[0] = &atmosphere.GetOpticalDepthTexture(); 628 | ui_precomputation_requested = false; 629 | } 630 | 631 | ImGui_ImplDX11_NewFrame(); 632 | if (ImGui::Begin("ToyModel")) 633 | { 634 | if (ImGui::Button("Compile")) 635 | { 636 | ui_compilation_requested = true; 637 | ui_precomputation_requested = true; 638 | } 639 | ImGui::Text("%.2f [s], %.2f ms/frame", elapsed_time_sec, 1000.0f / ImGui::GetIO().Framerate); 640 | // ImGui::Text("Camera pos = (%.2f, %.2f, %.2f)", camera_pos.x, camera_pos.y, camera_pos.z); 641 | 642 | if (ImGui::TreeNode("Precomputation")) 643 | { 644 | if (ImGui::Button("Precompute")) 645 | ui_precomputation_requested = true; 646 | 647 | int num_scattering = atmosphere.GetNumScattering(); 648 | ImGui::DragInt("Num. Scattering", &num_scattering, 1.0f, 1, 11); 649 | atmosphere.SetNumScattering(num_scattering); 650 | 651 | ImGui::InputFloat3("Rayleigh Scattering Coeff", (float*)&precomp_params.mRayleighSctrCoeff, 2); 652 | ImGui::InputFloat("Rayleigh Scale Height", &precomp_params.mRayleighScaleHeight, 0.0f, 0.0f, 2); 653 | ImGui::InputFloat3("Mie Scattering Coeff", (float*)&precomp_params.mMieSctrCoeff, 2); 654 | ImGui::InputFloat("Mie Scale Height", &precomp_params.mMieScaleHeight, 0.0f, 0.0f, 2); 655 | ImGui::InputFloat("Mie Absorption", &precomp_params.mMieAbsorption, 0.0f, 0.0f, 2); 656 | ImGui::TreePop(); 657 | } 658 | 659 | if (ImGui::TreeNode("Runtime")) 660 | { 661 | const math::Float3& fwd = camera_rot[static_cast(Camera::Direction::FORWARD)]; 662 | ImGui::Text("Camera / (%.1f, %.1f, %.1f), (%.2f, %.2f, %.2f)", camera_pos.x, camera_pos.y, camera_pos.z, fwd.x, fwd.y, fwd.z); 663 | ImGui::SliderFloat("Exposure Compensation", &ui_exposure_compensation, -16.0f, 16.0f); 664 | // ImGui::RadioButton("View", &ui_camera_mode, 0); ImGui::SameLine(); 665 | // ImGui::RadioButton("Omni", &ui_camera_mode, 1); 666 | 667 | ImGui::Text("Sun"); 668 | ImGui::SliderFloat("Theta", &ui_light_angle.x, 0.0f, 180.0f); 669 | ImGui::SliderFloat("Phi", &ui_light_angle.y, -180.0f, 180.f); 670 | 671 | ImGui::Text("Atmosphere"); 672 | ImGui::SliderFloat("Mie Asymmetry", &runtime_params.mMieAsymmetry, 0.0f, 1.0f); 673 | ImGui::TreePop(); 674 | } 675 | 676 | ImGui::End(); 677 | } 678 | 679 | primary_screen.Update(); 680 | ImGui::Render(); 681 | device.Present(ui_use_vsync); 682 | break; 683 | case wnd::WindowBase::UpdateResult::State::Exit: 684 | break; 685 | case wnd::WindowBase::UpdateResult::State::Busy: 686 | break; 687 | default: 688 | break; 689 | } 690 | } 691 | 692 | ImGui_ImplDX11_Shutdown(); 693 | 694 | return exit_code; 695 | } 696 | -------------------------------------------------------------------------------- /src/app/PureLatticeGaugeModel/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(project_name PureLatticeGaugeModel) 2 | 3 | AddApplicationProject(${project_name}) 4 | 5 | # Properties->Linker->Input->Additional Dependencies 6 | target_link_libraries (${project_name} etc) 7 | target_link_libraries (${project_name} math) 8 | target_link_libraries (${project_name} window) 9 | target_link_libraries (${project_name} imgui) 10 | target_link_libraries (${project_name} gpu) 11 | 12 | if(MSVC) 13 | # Set the entry point 14 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /subsystem:console /ENTRY:mainCRTStartup") 15 | endif(MSVC) 16 | -------------------------------------------------------------------------------- /src/app/PureLatticeGaugeModel/main.cpp: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // 3 | //-------------------------------------------------------------------------------------- 4 | 5 | #include 6 | 7 | int main() 8 | { 9 | int exit_code = 0; 10 | return exit_code; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/helloworld/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(project_name helloworld) 2 | 3 | AddApplicationProject(${project_name}) 4 | 5 | # Properties->Linker->Input->Additional Dependencies 6 | target_link_libraries (${project_name} etc) 7 | target_link_libraries (${project_name} math) 8 | target_link_libraries (${project_name} window) 9 | target_link_libraries (${project_name} imgui) 10 | target_link_libraries (${project_name} gpu) 11 | 12 | if(MSVC) 13 | # Set the entry point 14 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /subsystem:console /ENTRY:mainCRTStartup") 15 | endif(MSVC) 16 | -------------------------------------------------------------------------------- /src/app/helloworld/InputEvent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | struct InputEventHandler 7 | { 8 | InputEventHandler(wnd::WindowBase& inWindow) 9 | { 10 | for (int i = 0; i < static_cast(wnd::InputEvent::COUNT); ++i) 11 | { 12 | auto ev = static_cast(i); 13 | inWindow.RegisterInputEventCallbackFunc(ev, std::bind(&InputEventHandler::OnInputEvent, this, ev, std::placeholders::_1)); 14 | } 15 | } 16 | 17 | template 18 | void RegisterInputEventObserver(wnd::InputEvent&& event, Observer&& observer) 19 | { 20 | mInputEventHandler.Register(std::move(event), std::forward(observer)); 21 | } 22 | 23 | void OnInputEvent(wnd::InputEvent inEvent, const wnd::InputArgument& inArg) 24 | { 25 | mInputEventHandler.Notify(inEvent, inArg); 26 | } 27 | 28 | protected: 29 | etc::EventHandler mInputEventHandler; 30 | }; 31 | 32 | //================================================================= 33 | 34 | struct InputEventForImGui 35 | { 36 | InputEventForImGui(InputEventHandler& inEventHandler, ImGuiIO& inImGuiIO) : mImGuiIO(inImGuiIO) 37 | { 38 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_BUTTONDOWN, std::bind(&InputEventForImGui::OnMouseDown, this, std::placeholders::_1)); 39 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_BUTTONUP, std::bind(&InputEventForImGui::OnMouseUp, this, std::placeholders::_1)); 40 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_WHEEL, std::bind(&InputEventForImGui::OnMouseWheel, this, std::placeholders::_1)); 41 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::MOUSE_MOVE, std::bind(&InputEventForImGui::OnMouseMove, this, std::placeholders::_1)); 42 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_DOWN, std::bind(&InputEventForImGui::OnKeyDown, this, std::placeholders::_1)); 43 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_UP, std::bind(&InputEventForImGui::OnKeyUp, this, std::placeholders::_1)); 44 | inEventHandler.RegisterInputEventObserver(wnd::InputEvent::KEY_CHAR, std::bind(&InputEventForImGui::OnChar, this, std::placeholders::_1)); 45 | } 46 | 47 | void OnMouseDown(const wnd::InputArgument& arg) 48 | { 49 | mImGuiIO.MouseDown[arg.index] = true; 50 | } 51 | 52 | void OnMouseUp(const wnd::InputArgument& arg) 53 | { 54 | mImGuiIO.MouseDown[arg.index] = false; 55 | } 56 | 57 | void OnMouseWheel(const wnd::InputArgument&) 58 | { 59 | } 60 | 61 | void OnMouseMove(const wnd::InputArgument& arg) 62 | { 63 | mImGuiIO.MousePos.x = arg.x; 64 | mImGuiIO.MousePos.y = arg.y; 65 | } 66 | 67 | void OnKeyDown(const wnd::InputArgument&) 68 | { 69 | } 70 | 71 | void OnKeyUp(const wnd::InputArgument&) 72 | { 73 | } 74 | 75 | void OnChar(const wnd::InputArgument&) 76 | { 77 | } 78 | 79 | private: 80 | ImGuiIO& mImGuiIO; 81 | }; 82 | -------------------------------------------------------------------------------- /src/app/helloworld/main.cpp: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // 3 | //-------------------------------------------------------------------------------------- 4 | #define USE_IMGUI 0 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #if USE_IMGUI 16 | #include 17 | #include 18 | #include 19 | #include "InputEvent.h" 20 | #endif 21 | #include 22 | 23 | int main() 24 | { 25 | int exit_code; 26 | 27 | std::unique_ptr window( wnd::WindowBase::Create() ); 28 | if (!window->Initialize("Hello, world")) 29 | { 30 | exit_code = -1; 31 | return exit_code; 32 | } 33 | 34 | void* handle = window->GetWindowHandle(); 35 | Device device(&handle); 36 | #if USE_IMGUI 37 | ImGui_ImplDX11_Init(handle, &device.GetD3D11Device(), &device.GetD3D11DeviceContext()); 38 | 39 | InputEventHandler input_event_handler(*window); 40 | InputEventForImGui imgui_input_event(input_event_handler, ImGui::GetIO()); 41 | #endif 42 | 43 | std::string error_message; 44 | PixelShader default_ps("shader/helloworld/ScreenPS.hlsl"); 45 | PixelShader offscr2d_ps("shader/helloworld/OffScreen2dPS.hlsl"); 46 | PixelShader offscr3d_ps("shader/helloworld/OffScreen3dPS.hlsl"); 47 | VertexShader default_vs("shader/ScreenVS.hlsl"); 48 | if (!default_ps.Compile(device, error_message)) 49 | std::cout << error_message << std::endl; 50 | if (!offscr2d_ps.Compile(device, error_message)) 51 | std::cout << error_message << std::endl; 52 | if (!offscr3d_ps.Compile(device, error_message)) 53 | std::cout << error_message << std::endl; 54 | if (!default_vs.Compile(device, error_message)) 55 | std::cout << error_message << std::endl; 56 | BackBuffer back_buffer(device); 57 | 58 | SamplerDesc sampler_clamp_desc; 59 | SamplerDesc sampler_wrap_desc; 60 | sampler_clamp_desc.mBoundaryCondition = SamplerBoundaryCondition::CLAMP; 61 | sampler_wrap_desc.mBoundaryCondition = SamplerBoundaryCondition::WRAP; 62 | Sampler sampler_clamp(device, sampler_clamp_desc); 63 | Sampler sampler_wrap(device, sampler_wrap_desc); 64 | 65 | // off screen 2d 66 | std::unique_ptr offscreen2d; 67 | TextureDesc offscr2d_texture_desc; 68 | offscr2d_texture_desc.mHeight = 128; 69 | offscr2d_texture_desc.mWidth = 128; 70 | Texture2D offscr2d_texture(device, offscr2d_texture_desc); 71 | ScreenUpdateContext offscr2d_update_context; 72 | { 73 | ScreenCreationContext creation_context(device); 74 | creation_context.mResourceTextures[0] = &offscr2d_texture; 75 | offscreen2d = std::make_unique(creation_context); 76 | 77 | offscr2d_update_context.mPixelShader = &offscr2d_ps; 78 | offscr2d_update_context.mVertexShader = &default_vs; 79 | offscr2d_update_context.mTextureSamplers[0] = &sampler_clamp; 80 | offscr2d_update_context.mTextureSamplers[1] = &sampler_wrap; 81 | } 82 | 83 | // off screen 3d 84 | std::unique_ptr offscreen3d; 85 | TextureDesc offscr3d_texture_desc; 86 | offscr3d_texture_desc.mHeight = 32; 87 | offscr3d_texture_desc.mWidth = 32; 88 | offscr3d_texture_desc.mDepth = 32; 89 | Texture3D offscr3d_texture0(device, offscr3d_texture_desc); 90 | Texture3D offscr3d_texture1(device, offscr3d_texture_desc); 91 | ScreenUpdateContext offscr3d_update_context; 92 | { 93 | ScreenCreationContext creation_context(device); 94 | creation_context.mResourceTextures[0] = &offscr3d_texture0; 95 | creation_context.mResourceTextures[1] = &offscr3d_texture1; 96 | offscreen3d = std::make_unique(creation_context); 97 | 98 | offscr3d_update_context.mPixelShader = &offscr3d_ps; 99 | offscr3d_update_context.mVertexShader = &default_vs; 100 | offscr3d_update_context.mTextureSamplers[0] = &sampler_clamp; 101 | offscr3d_update_context.mTextureSamplers[1] = &sampler_wrap; 102 | } 103 | 104 | // primary screen 105 | std::unique_ptr screen; 106 | ScreenUpdateContext update_context; 107 | { 108 | ScreenCreationContext creation_context(device); 109 | creation_context.mResourceTextures[0] = &back_buffer; 110 | screen = std::make_unique(creation_context); 111 | 112 | update_context.mPixelShader = &default_ps; 113 | update_context.mVertexShader = &default_vs; 114 | update_context.mInputTexture2Ds[0] = &offscr2d_texture; 115 | update_context.mInputTexture3Ds[0] = &offscr3d_texture0; 116 | update_context.mInputTexture3Ds[1] = &offscr3d_texture1; 117 | update_context.mTextureSamplers[0] = &sampler_clamp; 118 | update_context.mTextureSamplers[0] = &sampler_wrap; 119 | } 120 | 121 | const wnd::Info& window_info = window->GetInfo(); 122 | const float window_size[2] = { float(window_info.mWindowSize[0]), float(window_info.mWindowSize[1]) }; 123 | std::cout << "window size : " << window_size[0] << ", " << window_size[1] << std::endl; 124 | 125 | auto time_start = std::chrono::system_clock::now(); 126 | bool ui_precomputation_requested = false; 127 | while (true) 128 | { 129 | wnd::WindowBase::UpdateResult result; 130 | window->Update(result); 131 | 132 | if (result.mState == wnd::WindowBase::UpdateResult::State::Exit) 133 | { 134 | exit_code = result.mExitCode; 135 | break; 136 | } 137 | 138 | auto time_now = std::chrono::system_clock::now(); 139 | float elapsed_time_sec = static_cast(1e-3 * std::chrono::duration_cast(time_now - time_start).count()); 140 | 141 | switch (result.mState) 142 | { 143 | case wnd::WindowBase::UpdateResult::State::Idle: 144 | if (ui_precomputation_requested) 145 | { 146 | if (!default_ps.Compile(device, error_message)) 147 | std::cout << error_message << std::endl; 148 | if (!offscr2d_ps.Compile(device, error_message)) 149 | std::cout << error_message << std::endl; 150 | if (!offscr3d_ps.Compile(device, error_message)) 151 | std::cout << error_message << std::endl; 152 | if (!default_vs.Compile(device, error_message)) 153 | std::cout << error_message << std::endl; 154 | ui_precomputation_requested = false; 155 | } 156 | #if USE_IMGUI 157 | ImGui_ImplDX11_NewFrame(); 158 | if (ImGui::Begin("ToyModel")) 159 | { 160 | if (ImGui::Button("Compile")) 161 | ui_precomputation_requested = true; 162 | ImGui::Text("%.2f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 163 | ImGui::Text("Time = %.2f [s]", elapsed_time_sec); 164 | ImGui::End(); 165 | } 166 | #endif 167 | 168 | update_context.mShaderParam.mFloat4[0].x = elapsed_time_sec; 169 | update_context.mShaderParam.mFloat4[0].y = window_size[0]; 170 | update_context.mShaderParam.mFloat4[0].z = window_size[1]; 171 | offscr2d_update_context.mShaderParam.mFloat4[0].x = elapsed_time_sec; 172 | offscr2d_update_context.mShaderParam.mFloat4[0].y = window_size[0]; 173 | offscr2d_update_context.mShaderParam.mFloat4[0].z = window_size[1]; 174 | offscr3d_update_context.mShaderParam.mFloat4[0].x = elapsed_time_sec; 175 | offscr3d_update_context.mShaderParam.mFloat4[0].y = window_size[0]; 176 | offscr3d_update_context.mShaderParam.mFloat4[0].z = window_size[1]; 177 | 178 | offscreen3d->Update(offscr3d_update_context); 179 | offscreen2d->Update(offscr2d_update_context); 180 | screen->Update(update_context); 181 | #if USE_IMGUI 182 | ImGui::Render(); 183 | #endif 184 | device.Present(true); 185 | break; 186 | case wnd::WindowBase::UpdateResult::State::Exit: 187 | break; 188 | case wnd::WindowBase::UpdateResult::State::Busy: 189 | break; 190 | default: 191 | break; 192 | } 193 | } 194 | #if USE_IMGUI 195 | ImGui_ImplDX11_Shutdown(); 196 | #endif 197 | return exit_code; 198 | } 199 | -------------------------------------------------------------------------------- /src/lib/etc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | AddLibraryProject(etc) 2 | -------------------------------------------------------------------------------- /src/lib/etc/EventHandler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include // for std::forward 5 | #include 6 | 7 | namespace etc 8 | { 9 | // https://github.com/juanchopanza/cppblog/tree/master/Patterns/Observer 10 | template 11 | struct EventHandler 12 | { 13 | EventHandler() = default; 14 | 15 | template 16 | void Register(const Event& event, Observer&& observer) 17 | { 18 | mObservers[event].push_back(std::forward(observer)); 19 | } 20 | 21 | template 22 | void Register(Event&& event, Observer&& observer) 23 | { 24 | mObservers[std::move(event)].push_back(std::forward(observer)); 25 | } 26 | 27 | void Notify(const Event& event, const Argument& arg) const 28 | { 29 | const auto iter = mObservers.find(event); 30 | if (iter != mObservers.end()) 31 | for (const auto& observer : iter->second) 32 | observer(arg); 33 | } 34 | 35 | // disallow copying and assigning 36 | EventHandler(const EventHandler&) = delete; 37 | EventHandler& operator=(const EventHandler&) = delete; 38 | 39 | private: 40 | std::unordered_map > > mObservers; 41 | }; 42 | 43 | } // core -------------------------------------------------------------------------------- /src/lib/etc/dummy.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k-ishiyama/toymodels/dba66c4438ba1b73bca2b209fe2b1727f3b1c294/src/lib/etc/dummy.cpp -------------------------------------------------------------------------------- /src/lib/gpu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(project_name gpu) 2 | 3 | AddLibraryProject(${project_name}) 4 | 5 | # Properties->Linker->Input->Additional Dependencies 6 | target_link_libraries(${project_name} d3d11) 7 | target_link_libraries(${project_name} d3dcompiler) 8 | target_link_libraries(${project_name} dxguid) 9 | -------------------------------------------------------------------------------- /src/lib/gpu/DirectXUtil.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "GPU.hpp" 4 | 5 | DXGI_FORMAT GetDXGIFormat(TextureFormat inFormat) 6 | { 7 | switch (inFormat) 8 | { 9 | case TextureFormat::R32: 10 | return DXGI_FORMAT_R32_FLOAT; 11 | case TextureFormat::R32G32: 12 | return DXGI_FORMAT_R32G32_FLOAT; 13 | case TextureFormat::R32G32B32: 14 | return DXGI_FORMAT_R32G32B32_FLOAT; 15 | case TextureFormat::R32G32B32A32: 16 | return DXGI_FORMAT_R32G32B32A32_FLOAT; 17 | default: 18 | assert(false); 19 | }; 20 | return DXGI_FORMAT_UNKNOWN; 21 | } -------------------------------------------------------------------------------- /src/lib/gpu/FullScreenTriangle.cpp: -------------------------------------------------------------------------------- 1 | #include "FullScreenTriangle.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace detail 7 | { 8 | static std::hash sStringHash; 9 | 10 | inline void UpdateConstantBuffer(ID3D11DeviceContext *pDeviceCtx, ID3D11Buffer *pCB, const void *pData, size_t DataSize) 11 | { 12 | D3D11_MAPPED_SUBRESOURCE MappedData; 13 | pDeviceCtx->Map(pCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedData); 14 | memcpy(MappedData.pData, pData, DataSize); 15 | pDeviceCtx->Unmap(pCB, 0); 16 | } 17 | } 18 | 19 | enum ConstantBufferSlot 20 | { 21 | SLOT_RESERVED_PARAM = 0, 22 | SLOT_TEX3D_PARAM, 23 | }; 24 | 25 | //================================================================================ 26 | 27 | template ScreenUpdaterBase::ScreenUpdaterBase(const ScreenCreationContext& inContext) : mDevice(inContext.mDevice) 28 | {} 29 | 30 | template void ScreenUpdaterBase::DrawFullscreenTriangle(std::uint32_t inScreenWidth, std::uint32_t inScreenHeight) 31 | { 32 | ID3D11DeviceContext& d3d_context = mDevice.GetD3D11DeviceContext(); 33 | 34 | // Setup viewport 35 | D3D11_VIEWPORT vp; 36 | vp.Width = float(inScreenWidth); 37 | vp.Height = float(inScreenHeight); 38 | vp.MinDepth = 0.0f; 39 | vp.MaxDepth = 1.0f; 40 | vp.TopLeftX = 0; 41 | vp.TopLeftY = 0; 42 | d3d_context.RSSetViewports(1, &vp); 43 | 44 | // Draw fullscreen triangle 45 | d3d_context.IASetInputLayout(NULL); 46 | d3d_context.IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 47 | d3d_context.Draw(3, 0); 48 | } 49 | 50 | template void ScreenUpdaterBase::SetRenderTechnique(const ScreenUpdateContext & inContext) 51 | { 52 | ID3D11DeviceContext& d3d_context = mDevice.GetD3D11DeviceContext(); 53 | 54 | // Samplers 55 | for (size_t i = 0; i < inContext.mTextureSamplers.size(); ++i) 56 | { 57 | if (!inContext.mTextureSamplers[i]) continue; 58 | ID3D11SamplerState* sampler = inContext.mTextureSamplers[i]->Get(); 59 | d3d_context.PSSetSamplers(i, 1, &sampler); 60 | } 61 | 62 | // Shaders 63 | ID3D11PixelShader* pixel_shader = inContext.mPixelShader->Get(); 64 | ID3D11VertexShader* vertex_shader = inContext.mVertexShader->Get(); 65 | d3d_context.PSSetShader(pixel_shader, nullptr, 0); 66 | d3d_context.VSSetShader(vertex_shader, nullptr, 0); 67 | 68 | // Blend state 69 | float blending_coeff[] = { 0.0f, 0.0f, 0.0f, 0.0f }; // R, G, B, A 70 | uint32_t sample_mask = 0xffffffff; 71 | if(inContext.mBlendState) 72 | { 73 | ID3D11BlendState* blend_state = inContext.mBlendState->Get(); 74 | d3d_context.OMSetBlendState(blend_state, blending_coeff, sample_mask); 75 | } 76 | } 77 | 78 | template void ScreenUpdaterBase::SetShaderResources(const ScreenUpdateContext & inContext) 79 | { 80 | ID3D11DeviceContext& d3d_context = mDevice.GetD3D11DeviceContext(); 81 | assert(inContext.mInputTexture2Ds.size() == ScreenUpdateContext::sNumInputTextures); 82 | for (size_t i = 0; i < inContext.mInputTexture2Ds.size(); ++i) 83 | { 84 | const Texture2D* texture = inContext.mInputTexture2Ds[i]; 85 | if (!texture) 86 | continue; 87 | ID3D11ShaderResourceView* srv = texture->GetShaderResourceView(); 88 | if (srv) 89 | d3d_context.PSSetShaderResources(i, 1, &srv); 90 | } 91 | 92 | assert(inContext.mInputTexture3Ds.size() == ScreenUpdateContext::sNumInputTextures); 93 | for (size_t i = 0; i < inContext.mInputTexture3Ds.size(); ++i) 94 | { 95 | const Texture3D* texture = inContext.mInputTexture3Ds[i]; 96 | if (!texture) 97 | continue; 98 | ID3D11ShaderResourceView* srv = texture->GetShaderResourceView(); 99 | if (srv) 100 | d3d_context.PSSetShaderResources(i + ScreenUpdateContext::sNumInputTextures, 1, &srv); 101 | } 102 | } 103 | 104 | template void ScreenUpdaterBase::UnbindResources() 105 | { 106 | ID3D11DeviceContext& d3d_context = mDevice.GetD3D11DeviceContext(); 107 | ID3D11ShaderResourceView* const pSRV[2 * ScreenUpdateContext::sNumInputTextures] = { nullptr }; 108 | d3d_context.PSSetShaderResources(0, 2 * ScreenUpdateContext::sNumInputTextures, pSRV); 109 | } 110 | 111 | //================================================================================ 112 | 113 | ScreenUpdater::ScreenUpdater(const ScreenCreationContext& inContext) : ScreenUpdaterBase(inContext) 114 | { 115 | ID3D11Device& d3d_device = mDevice.GetD3D11Device(); 116 | 117 | for (size_t i = 0; i < inContext.mResourceTextures.size(); ++i) 118 | if (inContext.mResourceTextures[i]) 119 | mResourceTextures[i] = inContext.mResourceTextures[i]; 120 | 121 | // Create render target view (assign back buffer for now) 122 | HRESULT result; 123 | ID3D11RenderTargetView* rtv; 124 | const Texture2D* texture2d = inContext.mResourceTextures[0]; 125 | assert(texture2d); 126 | ID3D11Texture2D* texture_resource = texture2d->Get(); 127 | assert(texture_resource); 128 | 129 | // Create render target view from the texture resource 130 | result = d3d_device.CreateRenderTargetView(texture_resource, nullptr, &rtv); 131 | assert(SUCCEEDED(result)); 132 | 133 | // create a constant buffer 134 | D3D11_BUFFER_DESC CBDesc = 135 | { 136 | sizeof(ScreenUpdateContext::ShaderParam), 137 | D3D11_USAGE_DYNAMIC, 138 | D3D11_BIND_CONSTANT_BUFFER, 139 | D3D11_CPU_ACCESS_WRITE, //UINT CPUAccessFlags 140 | 0, //UINT MiscFlags; 141 | 0, //UINT StructureByteStride; 142 | }; 143 | ID3D11Buffer* buffer; 144 | result = d3d_device.CreateBuffer(&CBDesc, NULL, &buffer); 145 | assert(SUCCEEDED(result)); 146 | 147 | mRenderTargetViews[0].push_back(detail::unique_iunknown_ptr(rtv)); 148 | mConstantBuffer = detail::unique_iunknown_ptr(buffer); 149 | } 150 | 151 | ScreenUpdater::~ScreenUpdater() 152 | { 153 | } 154 | 155 | void ScreenUpdater::Update(const ScreenUpdateContext & inContext) 156 | { 157 | assert(mRenderTargetViews[0].size() == 1); 158 | 159 | ID3D11DeviceContext& d3d_context = mDevice.GetD3D11DeviceContext(); 160 | IDXGISwapChain& swapchain = mDevice.GetSwapChain(); 161 | 162 | ID3D11Buffer* constant_buffer = mConstantBuffer.get(); 163 | ID3D11RenderTargetView* rtv = mResourceTextures[0]->GetRenderTargetViews()[0].get(); 164 | assert(constant_buffer); 165 | 166 | // Update constant buffer 167 | const ScreenUpdateContext::ShaderParam& reserved_param = inContext.mShaderParam; 168 | detail::UpdateConstantBuffer(&d3d_context, constant_buffer, &reserved_param, sizeof(reserved_param)); 169 | d3d_context.PSSetConstantBuffers(SLOT_RESERVED_PARAM, 1, &constant_buffer); 170 | 171 | d3d_context.OMSetRenderTargets(1, &rtv, NULL); 172 | 173 | // Clear the back buffer 174 | float ClearColor[4] = { 0.f, 0.f, 0.f, 1.0f }; 175 | d3d_context.ClearRenderTargetView(rtv, ClearColor); 176 | 177 | // Set shader resource view 178 | SetShaderResources(inContext); 179 | 180 | // Set samplers and shaders 181 | SetRenderTechnique(inContext); 182 | 183 | DXGI_SWAP_CHAIN_DESC swap_chain_desc; 184 | HRESULT hr = swapchain.GetDesc(&swap_chain_desc); 185 | assert(SUCCEEDED(hr)); 186 | DrawFullscreenTriangle(swap_chain_desc.BufferDesc.Width, swap_chain_desc.BufferDesc.Height); 187 | 188 | // Unbind resources 189 | UnbindResources(); 190 | } 191 | 192 | //================================================================================ 193 | 194 | ScreenBufferUpdater2D::ScreenBufferUpdater2D(const ScreenCreationContext& inContext) : ScreenUpdaterBase(inContext) 195 | { 196 | for(size_t i = 0; i < inContext.mResourceTextures.size(); ++i) 197 | if(inContext.mResourceTextures[i]) 198 | mResourceTextures[i] = inContext.mResourceTextures[i]; 199 | ID3D11Texture2D* texture = mResourceTextures[0]->Get(); 200 | assert(texture); 201 | 202 | ID3D11Device& d3d_device = mDevice.GetD3D11Device(); 203 | HRESULT result; 204 | 205 | // Setup the description of the render target view. 206 | D3D11_TEXTURE2D_DESC textureDesc; 207 | texture->GetDesc(&textureDesc); 208 | 209 | D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; 210 | renderTargetViewDesc.Format = textureDesc.Format; 211 | renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; 212 | renderTargetViewDesc.Texture2D.MipSlice = 0; 213 | 214 | // create a constant buffer 215 | D3D11_BUFFER_DESC CBDesc = 216 | { 217 | sizeof(ScreenUpdateContext::ShaderParam), 218 | D3D11_USAGE_DYNAMIC, 219 | D3D11_BIND_CONSTANT_BUFFER, 220 | D3D11_CPU_ACCESS_WRITE, //UINT CPUAccessFlags 221 | 0, //UINT MiscFlags; 222 | 0, //UINT StructureByteStride; 223 | }; 224 | ID3D11Buffer* buffer; 225 | result = d3d_device.CreateBuffer(&CBDesc, NULL, &buffer); 226 | assert(SUCCEEDED(result)); 227 | mConstantBuffer = detail::unique_iunknown_ptr(buffer); 228 | } 229 | 230 | ScreenBufferUpdater2D::~ScreenBufferUpdater2D() 231 | { 232 | } 233 | 234 | void ScreenBufferUpdater2D::Update(const ScreenUpdateContext & inContext) 235 | { 236 | assert(mRenderTargetViews.size() <= sMaxNumResourceTextures); 237 | ID3D11DeviceContext& d3d_context = mDevice.GetD3D11DeviceContext(); 238 | 239 | ID3D11Buffer* constant_buffer = mConstantBuffer.get(); 240 | ID3D11RenderTargetView* rtv = mResourceTextures[0]->GetRenderTargetViews()[0].get(); 241 | ID3D11Texture2D* texture = mResourceTextures[0]->Get(); 242 | 243 | // Update constant buffer 244 | const ScreenUpdateContext::ShaderParam& reserved_param = inContext.mShaderParam; 245 | detail::UpdateConstantBuffer(&d3d_context, constant_buffer, &reserved_param, sizeof(reserved_param)); 246 | d3d_context.PSSetConstantBuffers(SLOT_RESERVED_PARAM, 1, &constant_buffer); 247 | 248 | // Set render targets 249 | d3d_context.OMSetRenderTargets(1, &rtv, NULL); 250 | 251 | // Clear the back buffer 252 | float ClearColor[4] = { 0.f, 0.f, 0.f, 1.0f }; 253 | d3d_context.ClearRenderTargetView(rtv, ClearColor); 254 | 255 | // Set shader resource view 256 | SetShaderResources(inContext); 257 | 258 | // Set samplers and shaders 259 | SetRenderTechnique(inContext); 260 | 261 | D3D11_TEXTURE2D_DESC texture_desc; 262 | texture->GetDesc(&texture_desc); 263 | DrawFullscreenTriangle(texture_desc.Width, texture_desc.Height); 264 | 265 | // Unbind resources 266 | UnbindResources(); 267 | } 268 | 269 | //================================================================================ 270 | struct Tex3DShaderParams 271 | { 272 | float wq[2]; // Used when pre-computing inscattering look-up table 273 | std::uint32_t mDepthSlice; 274 | float mPadding; 275 | }; 276 | static_assert(sizeof(Tex3DShaderParams) % 16 == 0, "sizeof(Tex3DShaderParams) is not multiple of 16"); 277 | 278 | ScreenBufferUpdater3D::ScreenBufferUpdater3D(const ScreenCreationContext& inContext) : ScreenUpdaterBase(inContext) 279 | { 280 | ID3D11Device& d3d_device = mDevice.GetD3D11Device(); 281 | ID3D11DeviceContext& d3d_context = mDevice.GetD3D11DeviceContext(); 282 | HRESULT result; 283 | 284 | for (size_t i = 0; i < inContext.mResourceTextures.size(); ++i) 285 | { 286 | if (!inContext.mResourceTextures[i]) 287 | continue; 288 | mResourceTextures[i] = inContext.mResourceTextures[i]; 289 | ID3D11Texture3D* texture = mResourceTextures[i]->Get(); 290 | D3D11_TEXTURE3D_DESC textureDesc; 291 | texture->GetDesc(&textureDesc); 292 | mRenderTargetViews[i].reserve(textureDesc.Depth); 293 | 294 | // Setup the render target view. 295 | for (size_t depth = 0; depth < textureDesc.Depth; ++depth) 296 | { 297 | // Clear render target views. 298 | ID3D11RenderTargetView* rtv = mResourceTextures[i]->GetRenderTargetViews()[depth].get(); 299 | const float clear_color[4] = { 0.0f }; 300 | d3d_context.ClearRenderTargetView(rtv, clear_color); 301 | } 302 | } 303 | 304 | // create a constant buffers 305 | D3D11_BUFFER_DESC CBDesc = 306 | { 307 | sizeof(ScreenUpdateContext::ShaderParam), 308 | D3D11_USAGE_DYNAMIC, 309 | D3D11_BIND_CONSTANT_BUFFER, 310 | D3D11_CPU_ACCESS_WRITE, //UINT CPUAccessFlags 311 | 0, //UINT MiscFlags; 312 | 0, //UINT StructureByteStride; 313 | }; 314 | ID3D11Buffer* buffer; 315 | result = d3d_device.CreateBuffer(&CBDesc, nullptr, &buffer); 316 | assert(SUCCEEDED(result)); 317 | mConstantBuffer = detail::unique_iunknown_ptr(buffer); 318 | 319 | CBDesc.ByteWidth = sizeof(Tex3DShaderParams); 320 | result = d3d_device.CreateBuffer(&CBDesc, nullptr, &buffer); 321 | assert(SUCCEEDED(result)); 322 | mTex3dConstantBuffer = detail::unique_iunknown_ptr(buffer); 323 | } 324 | 325 | ScreenBufferUpdater3D::~ScreenBufferUpdater3D() {} 326 | 327 | void ScreenBufferUpdater3D::Update(const ScreenUpdateContext & inContext) 328 | { 329 | ID3D11DeviceContext& d3d_context = mDevice.GetD3D11DeviceContext(); 330 | ID3D11Buffer* constant_buffer = mConstantBuffer.get(); 331 | ID3D11Buffer* tex3d_constant_buffer = mTex3dConstantBuffer.get(); 332 | 333 | ID3D11Texture3D* texture = mResourceTextures[0]->Get(); 334 | D3D11_TEXTURE3D_DESC texture_desc; 335 | texture->GetDesc(&texture_desc); 336 | 337 | const int num_3d_slices = texture_desc.Depth / inContext.mNum4dSlices; 338 | assert(num_3d_slices > 0); 339 | 340 | // Set samplers and shaders 341 | SetRenderTechnique(inContext); 342 | 343 | // Update constant buffer 344 | const ScreenUpdateContext::ShaderParam& reserved_param = inContext.mShaderParam; 345 | detail::UpdateConstantBuffer(&d3d_context, constant_buffer, &reserved_param, sizeof(reserved_param)); 346 | d3d_context.PSSetConstantBuffers(SLOT_RESERVED_PARAM, 1, &constant_buffer); 347 | 348 | for (size_t depth = 0; depth < texture_desc.Depth; ++depth) 349 | { 350 | // Set render target view 351 | size_t num_rtvs_to_draw = 0; 352 | ID3D11RenderTargetView* rtvs_buffer[sMaxNumResourceTextures] = { nullptr }; 353 | for (size_t i = 0; i < sMaxNumResourceTextures; ++i) 354 | { 355 | if (!mResourceTextures[i]) 356 | continue; 357 | const auto& rtvs = mResourceTextures[i]->GetRenderTargetViews(); 358 | if (rtvs.size() == 0) 359 | continue; 360 | assert(rtvs.size() == texture_desc.Depth); 361 | rtvs_buffer[i] = rtvs[depth].get(); 362 | num_rtvs_to_draw++; 363 | } 364 | d3d_context.OMSetRenderTargets(num_rtvs_to_draw, rtvs_buffer, NULL); 365 | 366 | // Set shader resource view 367 | SetShaderResources(inContext); 368 | 369 | // Update the constant buffer of tex3d 370 | Tex3DShaderParams tex3d_params; 371 | tex3d_params.mDepthSlice = depth; 372 | UINT uiW = depth % num_3d_slices; 373 | UINT uiQ = depth / num_3d_slices; 374 | tex3d_params.wq[0] = ((float)uiW + 0.5f) / (float)num_3d_slices; 375 | tex3d_params.wq[1] = ((float)uiQ + 0.5f) / (float)inContext.mNum4dSlices; 376 | assert(0 < tex3d_params.wq[0] && tex3d_params.wq[0] < 1); 377 | assert(0 < tex3d_params.wq[1] && tex3d_params.wq[1] < 1); 378 | detail::UpdateConstantBuffer(&d3d_context, tex3d_constant_buffer, &tex3d_params, sizeof(tex3d_params)); 379 | d3d_context.PSSetConstantBuffers(SLOT_TEX3D_PARAM, 1, &tex3d_constant_buffer); 380 | 381 | DrawFullscreenTriangle(texture_desc.Width, texture_desc.Height); 382 | } 383 | 384 | // Unbind resources 385 | UnbindResources(); 386 | } 387 | -------------------------------------------------------------------------------- /src/lib/gpu/FullScreenTriangle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Render.hpp" 3 | #include // std::conditional 4 | #include // std::vector 5 | #include // std::array 6 | 7 | template struct ScreenUpdaterBase; 8 | 9 | template struct GPU_EXPORT ScreenCreationContext 10 | { 11 | ScreenCreationContext(const Device& inDevice) : mDevice(inDevice) {} 12 | const Device& mDevice; 13 | std::array::sMaxNumResourceTextures> mResourceTextures = { nullptr }; // Used to generate render targets 14 | }; 15 | 16 | struct GPU_EXPORT ScreenUpdateContext 17 | { 18 | static const size_t sNumInputTextures = 4; 19 | static const size_t sNumTextureSamplers = 2; 20 | 21 | struct GPU_EXPORT /* alignas(16) */ ShaderParam 22 | { 23 | struct float4 { float x, y, z, w; }; 24 | std::array mFloat4; // float4 x 16, shader parameter for "screen updater" system 25 | }; 26 | static_assert( sizeof(ShaderParam) % 16 == 0, "sizeof(""ShaderParam"") is not multiple of 16" ); 27 | ShaderParam mShaderParam; 28 | const PixelShader* mPixelShader = nullptr; 29 | const VertexShader* mVertexShader = nullptr; 30 | const BlendState* mBlendState = nullptr; 31 | std::array mTextureSamplers = { nullptr }; 32 | std::array mInputTexture2Ds = { nullptr }; 33 | std::array mInputTexture3Ds = { nullptr }; 34 | std::uint32_t mNum4dSlices = 1; // length of the 4th dimension. the division factor of the depth of 3d texture 35 | }; 36 | 37 | struct ID3D11Buffer; 38 | struct ID3D11RenderTargetView; 39 | struct ID3D11ShaderResourceView; 40 | 41 | //------------------------------------------------------------------ 42 | 43 | template struct ScreenUpdaterBase 44 | { 45 | static const size_t sMaxNumResourceTextures = 2; 46 | 47 | ScreenUpdaterBase(const ScreenCreationContext& inContext); 48 | virtual ~ScreenUpdaterBase() = default; 49 | virtual void Update(const ScreenUpdateContext& inContext) = 0; 50 | 51 | protected: 52 | void DrawFullscreenTriangle(std::uint32_t inScreenWidth, std::uint32_t inScreenHeight); 53 | void SetRenderTechnique(const ScreenUpdateContext &inContext); 54 | void SetShaderResources(const ScreenUpdateContext &inContext); 55 | void UnbindResources(); 56 | 57 | const Device& mDevice; 58 | std::array mResourceTextures = { nullptr }; 59 | detail::unique_iunknown_ptr mConstantBuffer = nullptr; 60 | std::array>, sMaxNumResourceTextures> mRenderTargetViews; 61 | }; 62 | 63 | struct GPU_EXPORT ScreenUpdater : ScreenUpdaterBase 64 | { 65 | ScreenUpdater(const ScreenCreationContext& inContext); 66 | virtual ~ScreenUpdater(); 67 | virtual void Update(const ScreenUpdateContext& inContext); 68 | }; 69 | 70 | //------------------------------------------------------------------ 71 | 72 | struct GPU_EXPORT ScreenBufferUpdater2D : ScreenUpdaterBase 73 | { 74 | ScreenBufferUpdater2D(const ScreenCreationContext& inContext); 75 | virtual ~ScreenBufferUpdater2D(); 76 | virtual void Update(const ScreenUpdateContext& inContext); 77 | }; 78 | 79 | //------------------------------------------------------------------ 80 | 81 | struct GPU_EXPORT ScreenBufferUpdater3D : ScreenUpdaterBase 82 | { 83 | ScreenBufferUpdater3D(const ScreenCreationContext& inContext); 84 | virtual ~ScreenBufferUpdater3D(); 85 | virtual void Update(const ScreenUpdateContext& inContext); 86 | protected: 87 | detail::unique_iunknown_ptr mTex3dConstantBuffer = nullptr; 88 | }; -------------------------------------------------------------------------------- /src/lib/gpu/GPU.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GPUExports.hpp" 3 | #include 4 | 5 | enum struct TextureFormat 6 | { 7 | R32, 8 | R32G32, 9 | R32G32B32, 10 | R32G32B32A32, 11 | }; 12 | 13 | enum struct TextureFlags : std::uint8_t 14 | { 15 | NONE = 0, 16 | CUBEMAP, 17 | }; 18 | using TextureFlagSet = std::bitset<8>; 19 | 20 | struct GPU_EXPORT TextureDesc 21 | { 22 | size_t mHeight = 256; 23 | size_t mWidth = 256; 24 | size_t mDepth = 1; 25 | TextureFormat mFormat = TextureFormat::R32G32B32A32; 26 | }; 27 | -------------------------------------------------------------------------------- /src/lib/gpu/GPUExports.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_WIN32) && defined(BUILD_SHARED_LIBS) 4 | #ifdef gpu_EXPORTS 5 | #define GPU_EXPORT __declspec( dllexport ) 6 | #else 7 | #define GPU_EXPORT __declspec( dllimport ) 8 | #endif 9 | #else 10 | #define GPU_EXPORT 11 | #endif -------------------------------------------------------------------------------- /src/lib/gpu/Render.cpp: -------------------------------------------------------------------------------- 1 | #include "Render.hpp" 2 | 3 | #ifdef RENDER_DIRECTX11 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "DirectXUtil.hpp" 12 | 13 | namespace detail 14 | { 15 | void IUnknownDeleter::operator()(IUnknown* r) 16 | { 17 | r->Release(); 18 | } 19 | 20 | static std::hash sStringHash; 21 | 22 | HRESULT CompileShaderFromFile( 23 | const WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, 24 | ID3DBlob** ppOutCodeBlob, ID3DBlob** ppErrorMsgBlob) 25 | { 26 | HRESULT hr = S_OK; 27 | 28 | DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS; 29 | #if defined( DEBUG ) || defined( _DEBUG ) 30 | // Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders. 31 | // Setting this flag improves the shader debugging experience, but still allows 32 | // the shaders to be optimized and to run exactly the way they will run in 33 | // the release configuration of this program. 34 | dwShaderFlags |= D3DCOMPILE_DEBUG; 35 | #endif 36 | 37 | hr = D3DCompileFromFile(szFileName, NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, szEntryPoint, szShaderModel, 38 | dwShaderFlags, 0, ppOutCodeBlob, ppErrorMsgBlob); 39 | 40 | return hr; 41 | } 42 | 43 | ID3D11PixelShader* CompilePixelShader( 44 | ID3D11Device* inDevice, const WCHAR* inFileName, LPCSTR inEntryPoint, std::string& outErrorMsg) 45 | { 46 | HRESULT result = E_FAIL; 47 | ID3DBlob* blob = nullptr; 48 | ID3DBlob* pErrorBlob = nullptr; 49 | result = CompileShaderFromFile(inFileName, inEntryPoint, "ps_4_0", &blob, &pErrorBlob); 50 | 51 | if (FAILED(result)) 52 | { 53 | if (pErrorBlob != nullptr) 54 | { 55 | outErrorMsg = static_cast(pErrorBlob->GetBufferPointer()); 56 | } 57 | else 58 | { 59 | std::stringstream ss; 60 | ss << "undefined error :" << result; 61 | outErrorMsg = ss.str(); 62 | } 63 | if (pErrorBlob) 64 | pErrorBlob->Release(); 65 | return nullptr; 66 | } 67 | if (pErrorBlob) pErrorBlob->Release(); 68 | 69 | if (FAILED(result)) 70 | { 71 | MessageBox(NULL, 72 | "The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", "Error", MB_OK); 73 | return nullptr; 74 | } 75 | 76 | // Create a shader from ID3DBlob 77 | ID3D11PixelShader* pixel_shader = nullptr; 78 | result = inDevice->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &pixel_shader); 79 | blob->Release(); 80 | if (FAILED(result)) 81 | { 82 | return nullptr; 83 | } 84 | return pixel_shader; 85 | } 86 | 87 | ID3D11VertexShader* CompileVertexShader( 88 | ID3D11Device* inDevice, const WCHAR* inFileName, LPCSTR inEntryPoint, std::string& outErrorMsg) 89 | { 90 | HRESULT result = E_FAIL; 91 | ID3DBlob* blob = nullptr; 92 | ID3DBlob* pErrorBlob = nullptr; 93 | result = CompileShaderFromFile(inFileName, inEntryPoint, "vs_4_0", &blob, &pErrorBlob); 94 | 95 | if (FAILED(result)) 96 | { 97 | if (pErrorBlob != NULL) 98 | { 99 | OutputDebugStringA((char*)pErrorBlob->GetBufferPointer()); 100 | outErrorMsg = static_cast(pErrorBlob->GetBufferPointer()); 101 | } 102 | if (pErrorBlob) 103 | pErrorBlob->Release(); 104 | return nullptr; 105 | } 106 | if (pErrorBlob) pErrorBlob->Release(); 107 | 108 | if (FAILED(result)) 109 | { 110 | MessageBox(NULL, 111 | "The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", "Error", MB_OK); 112 | return nullptr; 113 | } 114 | 115 | // Create a shader from ID3DBlob 116 | ID3D11VertexShader* vertex_shader = nullptr; 117 | result = inDevice->CreateVertexShader( 118 | blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &vertex_shader 119 | ); 120 | 121 | blob->Release(); 122 | if (FAILED(result)) 123 | { 124 | return nullptr; 125 | } 126 | return vertex_shader; 127 | } 128 | } 129 | 130 | //========================================================================== 131 | 132 | PixelShader::PixelShader(const std::string inFilePath) : mFilePath(inFilePath) {} 133 | PixelShader::~PixelShader() {} 134 | 135 | bool PixelShader::Compile(Device & inDevice, std::string & outMessage) 136 | { 137 | ID3D11Device& d3d_device = inDevice.GetD3D11Device(); 138 | std::wstring_convert, wchar_t> cv; 139 | std::wstring wfilepath = cv.from_bytes(mFilePath); 140 | 141 | ID3D11PixelShader* ps = nullptr; 142 | ps = detail::CompilePixelShader(&d3d_device, wfilepath.c_str(), "Entry", outMessage); 143 | if(ps) 144 | mUniquePtr = detail::unique_iunknown_ptr(ps); 145 | 146 | return ps != nullptr; 147 | } 148 | 149 | 150 | //========================================================================== 151 | 152 | VertexShader::VertexShader(const std::string inFilePath) : mFilePath(inFilePath) {} 153 | VertexShader::~VertexShader() {} 154 | 155 | bool VertexShader::Compile(Device & inDevice, std::string & outMessage) 156 | { 157 | ID3D11Device& d3d_device = inDevice.GetD3D11Device(); 158 | std::wstring_convert, wchar_t> cv; 159 | std::wstring wfilepath = cv.from_bytes(mFilePath); 160 | 161 | ID3D11VertexShader* ps = nullptr; 162 | ps = detail::CompileVertexShader(&d3d_device, wfilepath.c_str(), "Entry", outMessage); 163 | if (ps) 164 | mUniquePtr = detail::unique_iunknown_ptr(ps); 165 | 166 | return ps != nullptr; 167 | } 168 | 169 | //========================================================================== 170 | 171 | BlendState::BlendState(Device& inDevice, const BlendStateDesc& inDesc) 172 | { 173 | ID3D11Device& d3d_device = inDevice.GetD3D11Device(); 174 | 175 | D3D11_BLEND_DESC blend_desc; 176 | blend_desc.IndependentBlendEnable = FALSE; 177 | blend_desc.AlphaToCoverageEnable = FALSE; 178 | switch (inDesc.mBlendType) 179 | { 180 | case BlendType::NONE: 181 | for (auto& t : blend_desc.RenderTarget) 182 | t.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 183 | blend_desc.RenderTarget[0].BlendEnable = FALSE; 184 | blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; 185 | blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; 186 | blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 187 | blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; 188 | blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; 189 | blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 190 | break; 191 | case BlendType::ADDITIVE: 192 | for(auto& t : blend_desc.RenderTarget) 193 | t.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 194 | blend_desc.RenderTarget[0].BlendEnable = TRUE; 195 | blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; 196 | blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; 197 | blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 198 | blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; 199 | blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; 200 | blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 201 | break; 202 | case BlendType::ALPHA: 203 | for (auto& t : blend_desc.RenderTarget) 204 | t.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 205 | blend_desc.RenderTarget[0].BlendEnable = TRUE; 206 | blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; 207 | blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; 208 | blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 209 | blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; 210 | blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; 211 | blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 212 | break; 213 | default: 214 | assert(false); 215 | } 216 | 217 | ID3D11BlendState* bs = nullptr; 218 | HRESULT result = d3d_device.CreateBlendState(&blend_desc, &bs); 219 | assert(SUCCEEDED(result)); 220 | 221 | mUniquePtr = detail::unique_iunknown_ptr(bs); 222 | } 223 | 224 | BlendState::~BlendState() {} 225 | 226 | //========================================================================== 227 | 228 | Sampler::Sampler(Device& inDevice, const SamplerDesc& inDesc) 229 | { 230 | ID3D11Device& d3d_device = inDevice.GetD3D11Device(); 231 | 232 | D3D11_TEXTURE_ADDRESS_MODE address_mode = D3D11_TEXTURE_ADDRESS_CLAMP; 233 | switch (inDesc.mBoundaryCondition) 234 | { 235 | case SamplerBoundaryCondition::CLAMP: 236 | address_mode = D3D11_TEXTURE_ADDRESS_CLAMP; 237 | break; 238 | case SamplerBoundaryCondition::WRAP: 239 | address_mode = D3D11_TEXTURE_ADDRESS_WRAP; 240 | break; 241 | default: 242 | assert(false); 243 | } 244 | 245 | ID3D11SamplerState* sampler = nullptr; 246 | D3D11_SAMPLER_DESC desc = 247 | { 248 | D3D11_FILTER_MIN_MAG_MIP_LINEAR, 249 | address_mode, 250 | address_mode, 251 | address_mode, 252 | 0, //FLOAT MipLODBias; 253 | 0, //UINT MaxAnisotropy; 254 | D3D11_COMPARISON_NEVER, // D3D11_COMPARISON_FUNC ComparisonFunc; 255 | { 0.f, 0.f, 0.f, 0.f }, //FLOAT BorderColor[ 4 ]; 256 | -FLT_MAX, //FLOAT MinLOD; 257 | +FLT_MAX //FLOAT MaxLOD; 258 | }; 259 | HRESULT result = d3d_device.CreateSamplerState(&desc, &sampler); 260 | assert(SUCCEEDED(result)); 261 | 262 | mUniquePtr = detail::unique_iunknown_ptr(sampler); 263 | } 264 | 265 | Sampler::~Sampler(){} 266 | 267 | //========================================================================== 268 | 269 | Texture2D::Texture2D(){} 270 | 271 | Texture2D::Texture2D(Device& inDevice, const TextureDesc& inDesc) 272 | { 273 | assert(inDesc.mDepth == 1); // depth > 1 is not supported now 274 | 275 | mDesc = inDesc; 276 | ID3D11Device& d3d_device = inDevice.GetD3D11Device(); 277 | 278 | D3D11_TEXTURE2D_DESC desc; 279 | ZeroMemory(&desc, sizeof(desc)); 280 | 281 | // Setup the render target texture description. 282 | desc.Width = inDesc.mWidth; 283 | desc.Height = inDesc.mHeight; 284 | desc.ArraySize = 1; 285 | desc.MipLevels = 1; 286 | desc.Format = GetDXGIFormat(inDesc.mFormat); 287 | desc.SampleDesc.Count = 1; 288 | desc.Usage = D3D11_USAGE_DEFAULT; 289 | desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; 290 | desc.CPUAccessFlags = 0; 291 | desc.MiscFlags = 0; 292 | 293 | // Create the render target texture. 294 | ID3D11Texture2D* texture = nullptr; 295 | HRESULT result = d3d_device.CreateTexture2D(&desc, NULL, &texture); 296 | assert(SUCCEEDED(result)); 297 | mUniquePtr = detail::unique_iunknown_ptr(texture); 298 | 299 | // Create render target view. 300 | D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; 301 | renderTargetViewDesc.Format = desc.Format; 302 | renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; 303 | renderTargetViewDesc.Texture2D.MipSlice = 0; 304 | 305 | ID3D11RenderTargetView* rtv; 306 | result = d3d_device.CreateRenderTargetView(texture, &renderTargetViewDesc, &rtv); 307 | assert(SUCCEEDED(result)); 308 | mRenderTargetViews.push_back(detail::unique_iunknown_ptr(rtv)); 309 | 310 | // Create the shader resource view 311 | D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc; 312 | shaderResourceViewDesc.Format = desc.Format; 313 | shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; 314 | shaderResourceViewDesc.Texture2D.MostDetailedMip = 0; 315 | shaderResourceViewDesc.Texture2D.MipLevels = 1; 316 | 317 | ID3D11ShaderResourceView* srv = nullptr; 318 | result = d3d_device.CreateShaderResourceView(texture, &shaderResourceViewDesc, &srv); 319 | assert(SUCCEEDED(result)); 320 | mShaderResourceView = detail::unique_iunknown_ptr(srv); 321 | } 322 | 323 | Texture2D::~Texture2D(){} 324 | 325 | //========================================================================== 326 | 327 | Texture3D::Texture3D() {} 328 | 329 | Texture3D::Texture3D(Device& inDevice, const TextureDesc& inDesc) 330 | { 331 | mDesc = inDesc; 332 | 333 | ID3D11Device& d3d_device = inDevice.GetD3D11Device(); 334 | ID3D11DeviceContext& d3d_context = inDevice.GetD3D11DeviceContext(); 335 | 336 | // Setup the render target texture description. 337 | D3D11_TEXTURE3D_DESC desc; 338 | ZeroMemory(&desc, sizeof(desc)); 339 | desc.Width = inDesc.mWidth; 340 | desc.Height = inDesc.mHeight; 341 | desc.Depth = inDesc.mDepth; 342 | desc.MipLevels = 1; 343 | desc.Format = GetDXGIFormat(inDesc.mFormat); 344 | desc.Usage = D3D11_USAGE_DEFAULT; 345 | desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; 346 | desc.CPUAccessFlags = 0; 347 | desc.MiscFlags = 0; 348 | 349 | // Create the render target texture. 350 | ID3D11Texture3D* texture = nullptr; 351 | HRESULT result = d3d_device.CreateTexture3D(&desc, NULL, &texture); 352 | assert(SUCCEEDED(result)); 353 | mUniquePtr = detail::unique_iunknown_ptr(texture); 354 | 355 | // Create render target views 356 | for (size_t depth = 0; depth < desc.Depth; ++depth) 357 | { 358 | D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; 359 | renderTargetViewDesc.Format = desc.Format; 360 | renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; 361 | renderTargetViewDesc.Texture3D.MipSlice = 0; 362 | renderTargetViewDesc.Texture3D.FirstWSlice = depth; 363 | renderTargetViewDesc.Texture3D.WSize = 1; 364 | 365 | // Create and clear render target views. 366 | ID3D11RenderTargetView* rtv; 367 | result = d3d_device.CreateRenderTargetView(texture, &renderTargetViewDesc, &rtv); 368 | assert(SUCCEEDED(result)); 369 | const float clear_color[4] = { 0.0f }; 370 | d3d_context.ClearRenderTargetView(rtv, clear_color); 371 | mRenderTargetViews.push_back(detail::unique_iunknown_ptr(rtv)); 372 | } 373 | 374 | // Create shader resource view 375 | D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc; 376 | shaderResourceViewDesc.Format = desc.Format; 377 | shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; 378 | shaderResourceViewDesc.Texture2D.MostDetailedMip = 0; 379 | shaderResourceViewDesc.Texture2D.MipLevels = 1; 380 | 381 | ID3D11ShaderResourceView* srv = nullptr; 382 | result = d3d_device.CreateShaderResourceView(texture, &shaderResourceViewDesc, &srv); 383 | assert(SUCCEEDED(result)); 384 | mShaderResourceView = detail::unique_iunknown_ptr(srv); 385 | } 386 | 387 | Texture3D::~Texture3D() {} 388 | 389 | //========================================================================== 390 | 391 | BackBuffer::BackBuffer(Device& inDevice) : Texture2D() 392 | { 393 | ID3D11Device& d3d_device = inDevice.GetD3D11Device(); 394 | 395 | IDXGISwapChain& swapchain = inDevice.GetSwapChain(); 396 | ID3D11Texture2D* texture = nullptr; 397 | HRESULT result = swapchain.GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&texture); 398 | assert(SUCCEEDED(result)); 399 | mUniquePtr = detail::unique_iunknown_ptr(texture); 400 | 401 | D3D11_TEXTURE2D_DESC desc; 402 | texture->GetDesc(&desc); 403 | 404 | // Create render target view. 405 | D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; 406 | renderTargetViewDesc.Format = desc.Format; 407 | renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; 408 | renderTargetViewDesc.Texture2D.MipSlice = 0; 409 | 410 | ID3D11RenderTargetView* rtv; 411 | result = d3d_device.CreateRenderTargetView(texture, &renderTargetViewDesc, &rtv); 412 | assert(SUCCEEDED(result)); 413 | mRenderTargetViews.push_back(detail::unique_iunknown_ptr(rtv)); 414 | 415 | mShaderResourceView = nullptr; 416 | } 417 | 418 | BackBuffer::~BackBuffer(){} 419 | 420 | //========================================================================== 421 | 422 | Device::Device(void** inWindowHandle) 423 | { 424 | HRESULT hr = S_OK; 425 | 426 | RECT rc; 427 | GetClientRect(HWND(inWindowHandle[0]), &rc); 428 | UINT width = rc.right - rc.left; 429 | UINT height = rc.bottom - rc.top; 430 | 431 | UINT createDeviceFlags = 0; 432 | #ifdef _DEBUG 433 | createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 434 | #endif 435 | 436 | D3D_DRIVER_TYPE driverTypes[] = 437 | { 438 | D3D_DRIVER_TYPE_HARDWARE, 439 | D3D_DRIVER_TYPE_WARP, 440 | D3D_DRIVER_TYPE_REFERENCE, 441 | }; 442 | UINT numDriverTypes = ARRAYSIZE(driverTypes); 443 | 444 | D3D_FEATURE_LEVEL featureLevels[] = 445 | { 446 | D3D_FEATURE_LEVEL_11_0, 447 | D3D_FEATURE_LEVEL_10_1, 448 | D3D_FEATURE_LEVEL_10_0, 449 | }; 450 | UINT numFeatureLevels = ARRAYSIZE(featureLevels); 451 | 452 | DXGI_SWAP_CHAIN_DESC sd; 453 | ZeroMemory(&sd, sizeof(sd)); 454 | sd.BufferCount = 1; 455 | sd.BufferDesc.Width = width; 456 | sd.BufferDesc.Height = height; 457 | sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 458 | sd.BufferDesc.RefreshRate.Numerator = 60; // 60FPS 459 | sd.BufferDesc.RefreshRate.Denominator = 1; 460 | sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 461 | sd.OutputWindow = HWND(inWindowHandle[0]); 462 | sd.SampleDesc.Count = 1; 463 | sd.SampleDesc.Quality = 0; 464 | sd.Windowed = TRUE; 465 | 466 | ID3D11Device* device; 467 | ID3D11DeviceContext* context; 468 | IDXGISwapChain* swapchain; 469 | D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_NULL; 470 | D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0; 471 | for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) 472 | { 473 | driverType = driverTypes[driverTypeIndex]; 474 | 475 | hr = D3D11CreateDeviceAndSwapChain(NULL, driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels, 476 | D3D11_SDK_VERSION, &sd, &swapchain, &device, &featureLevel, &context); 477 | if (SUCCEEDED(hr)) 478 | break; 479 | } 480 | if (FAILED(hr)) 481 | assert(false); 482 | mD3dDevice = detail::unique_iunknown_ptr(device); 483 | mImmediateContext = detail::unique_iunknown_ptr(context); 484 | mSwapChain = detail::unique_iunknown_ptr(swapchain); 485 | } 486 | 487 | Device::~Device() 488 | { 489 | if (mImmediateContext) mImmediateContext->ClearState(); 490 | } 491 | 492 | void Device::Present(bool vSyncEnabled) 493 | { 494 | IDXGISwapChain& swapchain = GetSwapChain(); 495 | unsigned int sync_interval = vSyncEnabled ? 2 : 0; 496 | swapchain.Present(sync_interval, 0); 497 | } 498 | 499 | //======================================================== 500 | 501 | #endif // RENDER_DIRECTX11 -------------------------------------------------------------------------------- /src/lib/gpu/Render.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GPU.hpp" 3 | #include 4 | #include 5 | #include // std::vector 6 | 7 | #define RENDER_DIRECTX11 8 | 9 | struct IUnknown; 10 | namespace detail 11 | { 12 | struct IUnknownDeleter 13 | { 14 | void operator()(IUnknown* r); 15 | }; 16 | 17 | template 18 | using unique_iunknown_ptr = std::unique_ptr; 19 | } 20 | 21 | struct Device; 22 | struct ResourcePool; 23 | 24 | //============================================================= 25 | 26 | //============================================================= 27 | struct ID3D11Device; 28 | struct ID3D11DeviceContext; 29 | struct IDXGISwapChain; 30 | struct ID3D11PixelShader; 31 | struct ID3D11VertexShader; 32 | struct ID3D11SamplerState; 33 | struct ID3D11BlendState; 34 | struct ID3D11Texture2D; 35 | struct ID3D11Texture3D; 36 | struct ID3D11RenderTargetView; 37 | struct ID3D11ShaderResourceView; 38 | 39 | struct GPU_EXPORT Device 40 | { 41 | Device(void** inWindowHandle); 42 | ~Device(); 43 | void Present(bool vSyncEnabled); 44 | 45 | ID3D11Device& GetD3D11Device() { return *mD3dDevice; } 46 | ID3D11DeviceContext& GetD3D11DeviceContext() { return *mImmediateContext; } 47 | IDXGISwapChain& GetSwapChain() { return *mSwapChain; } 48 | 49 | ID3D11Device& GetD3D11Device() const { return *mD3dDevice; } 50 | ID3D11DeviceContext& GetD3D11DeviceContext() const { return *mImmediateContext; } 51 | IDXGISwapChain& GetSwapChain() const { return *mSwapChain; } 52 | private: 53 | detail::unique_iunknown_ptr mD3dDevice = nullptr; 54 | detail::unique_iunknown_ptr mImmediateContext = nullptr; 55 | detail::unique_iunknown_ptr mSwapChain = nullptr; 56 | }; 57 | 58 | //============================================================= 59 | 60 | struct GPU_EXPORT PixelShader 61 | { 62 | PixelShader(const std::string inFilePath); 63 | ~PixelShader(); 64 | ID3D11PixelShader* Get() const { return mUniquePtr.get(); } 65 | bool Compile(Device& inDevice, std::string& outMessage); 66 | protected: 67 | detail::unique_iunknown_ptr mUniquePtr = nullptr; 68 | std::string mFilePath; 69 | }; 70 | 71 | //============================================================= 72 | 73 | struct GPU_EXPORT VertexShader 74 | { 75 | VertexShader(const std::string inFilePath); 76 | ~VertexShader(); 77 | ID3D11VertexShader* Get() const { return mUniquePtr.get(); } 78 | bool Compile(Device& inDevice, std::string& outMessage); 79 | protected: 80 | detail::unique_iunknown_ptr mUniquePtr = nullptr; 81 | std::string mFilePath; 82 | }; 83 | 84 | //============================================================= 85 | 86 | enum struct SamplerBoundaryCondition 87 | { 88 | CLAMP, 89 | WRAP, 90 | }; 91 | 92 | struct GPU_EXPORT SamplerDesc 93 | { 94 | SamplerBoundaryCondition mBoundaryCondition = SamplerBoundaryCondition::CLAMP; 95 | }; 96 | 97 | struct GPU_EXPORT Sampler 98 | { 99 | Sampler(Device& inDevice, const SamplerDesc& inDesc); 100 | ~Sampler(); 101 | ID3D11SamplerState* Get() const { return mUniquePtr.get(); } 102 | protected: 103 | detail::unique_iunknown_ptr mUniquePtr = nullptr; 104 | }; 105 | 106 | //============================================================= 107 | 108 | enum struct BlendType 109 | { 110 | NONE, 111 | ADDITIVE, 112 | ALPHA 113 | }; 114 | 115 | struct GPU_EXPORT BlendStateDesc 116 | { 117 | BlendType mBlendType = BlendType::NONE; 118 | }; 119 | 120 | struct GPU_EXPORT BlendState 121 | { 122 | BlendState(Device& inDevice, const BlendStateDesc& inDesc); 123 | ~BlendState(); 124 | ID3D11BlendState* Get() const { return mUniquePtr.get(); } 125 | protected: 126 | detail::unique_iunknown_ptr mUniquePtr = nullptr; 127 | }; 128 | 129 | //============================================================= 130 | 131 | 132 | struct Texture 133 | { 134 | const auto GetShaderResourceView() const { return mShaderResourceView.get(); } 135 | const auto& GetRenderTargetViews() const { return mRenderTargetViews; } 136 | const auto& GetTextureDesc() const { return mDesc; } 137 | protected: 138 | TextureDesc mDesc; 139 | detail::unique_iunknown_ptr mShaderResourceView = nullptr; 140 | std::vector> mRenderTargetViews; 141 | }; 142 | 143 | struct GPU_EXPORT Texture2D : Texture 144 | { 145 | Texture2D(); 146 | Texture2D(Device& inDevice, const TextureDesc& inDesc); 147 | virtual ~Texture2D(); 148 | ID3D11Texture2D* Get() const { return mUniquePtr.get(); } 149 | protected: 150 | detail::unique_iunknown_ptr mUniquePtr; 151 | }; 152 | 153 | struct GPU_EXPORT Texture3D : Texture 154 | { 155 | Texture3D(); 156 | Texture3D(Device& inDevice, const TextureDesc& inDesc); 157 | virtual ~Texture3D(); 158 | ID3D11Texture3D* Get() const { return mUniquePtr.get(); } 159 | protected: 160 | detail::unique_iunknown_ptr mUniquePtr; 161 | }; 162 | 163 | //============================================================= 164 | 165 | struct GPU_EXPORT BackBuffer : Texture2D 166 | { 167 | BackBuffer(Device& inDevice); 168 | virtual ~BackBuffer(); 169 | }; 170 | 171 | //============================================================= 172 | -------------------------------------------------------------------------------- /src/lib/gpu/TextureIO.cpp: -------------------------------------------------------------------------------- 1 | #include "TextureIO.hpp" 2 | #include 3 | #include 4 | 5 | Image::Image(const ImageMetaData& inDesc) 6 | : mDesc(inDesc) 7 | { 8 | size_t mipLevels = inDesc.mipLevels; 9 | 10 | size_t dimension = 1; 11 | dimension += inDesc.height > 1 ? 1 : 0; 12 | dimension += inDesc.depth > 1 ? 1 : 0; 13 | 14 | assert(mipLevels == 1); // ToDo 15 | switch (dimension) 16 | { 17 | case 1: 18 | assert(false); // ToDo 19 | break; 20 | 21 | case 2: 22 | mWidth = inDesc.width; 23 | mHeight = inDesc.height; 24 | break; 25 | 26 | case 3: 27 | assert(false); // ToDo 28 | break; 29 | 30 | default: 31 | assert(false); 32 | } 33 | } 34 | 35 | //========================================================== 36 | 37 | std::unique_ptr CaptureTexture(const Device& inDevice, const Texture2D& inTexture2D) 38 | { 39 | HRESULT hr; 40 | 41 | ID3D11Texture2D* src_texture = inTexture2D.Get(); 42 | assert(src_texture); 43 | 44 | D3D11_TEXTURE2D_DESC desc; 45 | src_texture->GetDesc(&desc); 46 | 47 | detail::unique_iunknown_ptr staging_texture = nullptr; 48 | if (desc.SampleDesc.Count > 1) 49 | { 50 | // detail::unique_iunknown_ptr staging_texture = nullptr; 51 | assert(false); // todo 52 | } 53 | else if ((desc.Usage == D3D11_USAGE_STAGING) && (desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)) 54 | { 55 | // Handle case where the source is already a staging texture we can use directly 56 | assert(false); // todo 57 | } 58 | else 59 | { 60 | desc.BindFlags = 0; 61 | desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE; 62 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; 63 | desc.Usage = D3D11_USAGE_STAGING; 64 | 65 | ID3D11Texture2D* raw_staging_texture = staging_texture.get(); 66 | hr = inDevice.GetD3D11Device().CreateTexture2D(&desc, 0, &raw_staging_texture); 67 | assert(SUCCEEDED(hr)); 68 | assert(staging_texture); 69 | 70 | inDevice.GetD3D11DeviceContext().CopyResource(raw_staging_texture, src_texture); 71 | } 72 | 73 | ImageMetaData meta_data; 74 | meta_data.width = desc.Width; 75 | meta_data.height = desc.Height; 76 | meta_data.depth = 1; 77 | meta_data.mipLevels = desc.MipLevels; 78 | meta_data.flagSet = static_cast(TextureFlags::NONE); 79 | meta_data.format = inTexture2D.GetTextureDesc().mFormat; 80 | if (desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) 81 | meta_data.flagSet.set(static_cast(TextureFlags::CUBEMAP)); 82 | 83 | std::unique_ptr outImage = std::make_unique(meta_data); 84 | 85 | // (Under construction) 86 | 87 | return nullptr; 88 | } -------------------------------------------------------------------------------- /src/lib/gpu/TextureIO.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // 3 | // References 4 | // https://github.com/Microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexD3D11.cpp 5 | // 6 | #include "Render.hpp" 7 | 8 | // Forward declarations 9 | struct ID3D11Device; 10 | struct ID3D11DeviceContext; 11 | struct ID3D11Resource; 12 | 13 | struct ImageMetaData 14 | { 15 | size_t width; 16 | size_t height; 17 | size_t depth; 18 | size_t mipLevels; 19 | // size_t arraySize; 20 | TextureFormat format; 21 | TextureFlagSet flagSet; 22 | }; 23 | 24 | struct Image 25 | { 26 | Image(const ImageMetaData& inDesc); 27 | private: 28 | const ImageMetaData& mDesc; 29 | size_t mWidth; 30 | size_t mHeight; 31 | size_t mRowPitch; 32 | size_t mSlicePitch; 33 | uint8_t* mPixels; 34 | }; 35 | 36 | std::unique_ptr CaptureTexture(const Device& inDevice, const Texture2D& inTexture2D); -------------------------------------------------------------------------------- /src/lib/math/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | AddLibraryProject(math) 2 | -------------------------------------------------------------------------------- /src/lib/math/Math.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace math { 5 | 6 | template constexpr T PI = T(3.14159265358979323846L); 7 | 8 | //===================================================== 9 | 10 | template struct Vector2 11 | { 12 | T x, y; 13 | T& operator[](size_t _i) { return (&x)[_i]; } 14 | constexpr T const& operator[](size_t _i) const { return (&x)[_i]; } 15 | T& at(size_t _i) { assert(_i < 2); return (&x)[_i] } 16 | constexpr T const& at(size_t _i) const { assert(_i < 2); return (&x)[_i] } 17 | 18 | constexpr Vector2() = default; 19 | constexpr Vector2(Vector2 const& _v) : x(_v.x), y(_v.y) {} 20 | constexpr explicit Vector2(T _s) : x(_s), y(_s) {} 21 | constexpr explicit Vector2(T _x, T _y) : x(_x), y(_y) {} 22 | }; 23 | 24 | template struct Vector4 25 | { 26 | T x, y, z, w; 27 | T& operator[](size_t _i) { return (&x)[_i]; } 28 | constexpr T const& operator[](size_t _i) const { return (&x)[_i]; } 29 | T& at(size_t _i) { assert(_i < 4); return (&x)[_i]; } 30 | constexpr T const& at(size_t _i) const { assert(_i < 4); return (&x)[_i]; } 31 | 32 | constexpr Vector4() = default; 33 | constexpr Vector4(const Vector4& _v) : x(_v.x), y(_v.y), z(_v.z), w(_v.w) {} 34 | constexpr explicit Vector4(T _s) : x(_s), y(_s), z(_s), w(_s) {} 35 | constexpr explicit Vector4(T _x, T _y, T _z, T _w) : x(_x), y(_y), z(_z), w(_w) {} 36 | }; 37 | 38 | //===================================================== 39 | 40 | template struct Vector3 41 | { 42 | T x, y, z; 43 | T& operator[](size_t _i) { return (&x)[_i]; } 44 | constexpr T const& operator[](size_t _i) const { return (&x)[_i]; } 45 | T& at(size_t _i) { assert(_i < 3); return (&x)[_i]; } 46 | constexpr T const& at(size_t _i) const { assert(_i < 3); return (&x)[_i]; } 47 | 48 | constexpr Vector3() = default; 49 | constexpr Vector3(const Vector3& _v) : x(_v.x), y(_v.y), z(_v.z) {} 50 | constexpr explicit Vector3(T _s) : x(_s), y(_s), z(_s) {} 51 | constexpr explicit Vector3(T _x, T _y, T _z) : x(_x), y(_y), z(_z) {} 52 | }; 53 | 54 | template constexpr Vector3 operator-(const Vector3& v) 55 | { 56 | return Vector3(-v[0], -v[1], -v[2]); 57 | } 58 | 59 | template constexpr Vector3 operator+(const Vector3& a, const Vector3& b) 60 | { 61 | return Vector3(a[0] + b[0], a[1] + b[1], a[2] + b[2]); 62 | } 63 | 64 | template constexpr Vector3 operator*(const Vector3& v, T const s) 65 | { 66 | return Vector3(v[0] * s, v[1] * s, v[2] * s); 67 | } 68 | 69 | template constexpr Vector3 operator*(T const s, const Vector3& v) 70 | { 71 | return Vector3(s * v[0], s * v[1], s * v[2]); 72 | } 73 | 74 | // entrywise multiplication 75 | template constexpr Vector3 operator*(const Vector3& a, const Vector3& b) 76 | { 77 | return Vector3(a[0] * b[0], a[1] * b[1], a[2] * b[2]); 78 | } 79 | 80 | template constexpr Vector3 operator/(const Vector3& v, T const s) 81 | { 82 | return Vector3(v[0] / s, v[1] / s, v[2] / s); 83 | } 84 | 85 | // entrywise division 86 | template constexpr Vector3 operator/(const Vector3& a, const Vector3& b) 87 | { 88 | return Vector3(a[0] / b[0], a[1] / b[1], a[2] / b[2]); 89 | } 90 | 91 | template constexpr bool NearlyEqual(T a, T b, T epsilon = std::numeric_limits::epsilon()) 92 | { 93 | return std::abs(a - b) < epsilon; 94 | } 95 | 96 | template constexpr T InnerProduct(const Vector3& a, const Vector3& b) 97 | { 98 | return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; 99 | } 100 | 101 | template constexpr T L1Norm(const Vector3& v) 102 | { 103 | return std::abs(v[0]) + std::abs(v[1]) + std::abs(v[2]); 104 | } 105 | 106 | template constexpr T L2Norm(const Vector3& v) 107 | { 108 | return std::sqrt(InnerProduct(v, v)); 109 | } 110 | 111 | template constexpr Vector3 L2Normalize(const Vector3& v) 112 | { 113 | return v / L2Norm(v); 114 | } 115 | 116 | template constexpr Vector3 Cross(const Vector3& a, const Vector3& b) 117 | { 118 | return Vector3(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]); 119 | } 120 | 121 | //================================================= 122 | 123 | template struct Matrix3x3 124 | { 125 | Vector3 x, y, z; 126 | constexpr Matrix3x3() = default; 127 | constexpr Matrix3x3(const Matrix3x3& _m) : x(_m.x), y(_m.y), z(_m.z) {} 128 | constexpr explicit Matrix3x3(Vector3 const& _v0, Vector3 const& _v1, Vector3 const& _v2) 129 | : x(_v0), y(_v1), z(_v2) {} 130 | constexpr explicit Matrix3x3(T _00, T _01, T _02, T _10, T _11, T _12, T _20, T _21, T _22) 131 | : x(_00, _01, _02), y(_10, _11, _12), z(_20, _21, _22) {} 132 | 133 | Vector3& operator[](size_t _i) { return (&x)[_i]; } 134 | constexpr Vector3 const& operator[](size_t _i) const { return (&x)[_i]; } 135 | Vector3& at(size_t _i) { assert(_i < 3); return (&x)[_i]; } 136 | constexpr Vector3 const& at(size_t _i) const { assert(_i < 3); (&x)[_i]; } 137 | }; 138 | 139 | template constexpr T Determinant(const Matrix3x3& m) 140 | { 141 | return m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) 142 | - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) 143 | + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]); 144 | } 145 | 146 | template /*constexpr*/ Matrix3x3 Inverse(const Matrix3x3& m) 147 | { 148 | T denom = static_cast(1) / Determinant(m); 149 | return Matrix3x3( 150 | (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * denom, 151 | - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * denom, 152 | (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * denom, 153 | - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * denom, 154 | (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * denom, 155 | - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * denom, 156 | (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * denom, 157 | - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * denom, 158 | (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * denom); 159 | } 160 | 161 | template constexpr Matrix3x3 operator*(const Matrix3x3& a, const Matrix3x3& b) 162 | { 163 | return Matrix3x3( 164 | a[0][0] * b[0][0] + a[1][0] * b[0][1] + a[2][0] * b[0][2], 165 | a[0][1] * b[0][0] + a[1][1] * b[0][1] + a[2][1] * b[0][2], 166 | a[0][2] * b[0][0] + a[1][2] * b[0][1] + a[2][2] * b[0][2], 167 | a[0][0] * b[1][0] + a[1][0] * b[1][1] + a[2][0] * b[1][2], 168 | a[0][1] * b[1][0] + a[1][1] * b[1][1] + a[2][1] * b[1][2], 169 | a[0][2] * b[1][0] + a[1][2] * b[1][1] + a[2][2] * b[1][2], 170 | a[0][0] * b[2][0] + a[1][0] * b[2][1] + a[2][0] * b[2][2], 171 | a[0][1] * b[2][0] + a[1][1] * b[2][1] + a[2][1] * b[2][2], 172 | a[0][2] * b[2][0] + a[1][2] * b[2][1] + a[2][2] * b[2][2] 173 | ); 174 | } 175 | 176 | template constexpr Vector3 operator*(const Matrix3x3& m, const Vector3& v) 177 | { 178 | return Vector3( 179 | m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2], 180 | m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2], 181 | m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] 182 | ); 183 | } 184 | 185 | template constexpr Matrix3x3 operator*(T const& s, Matrix3x3 const& m) 186 | { 187 | return Matrix3x3(s * m[0], s * m[1], s* m[2]); 188 | } 189 | 190 | //================================================= 191 | 192 | using Int2 = Vector2; 193 | using Float2 = Vector2; 194 | using Double2 = Vector2; 195 | 196 | using Int3 = Vector3; 197 | using Float3 = Vector3; 198 | using Double3 = Vector3; 199 | 200 | using Float3x3 = Matrix3x3; 201 | 202 | } // namespace math -------------------------------------------------------------------------------- /src/lib/math/SO3.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Math.hpp" 3 | 4 | namespace math { 5 | 6 | template /* constexpr */ Matrix3x3 RotationXYZ(T ax, T ay, T az) 7 | { 8 | float cx = std::cos(ax); 9 | float sx = std::sin(ax); 10 | float cy = std::cos(ay); 11 | float sy = std::sin(ay); 12 | float cz = std::cos(az); 13 | float sz = std::sin(az); 14 | return Matrix3x3( 15 | cz * cy, cz * sy * sx - sz * cx, cz * sy * cx + sz * sx, 16 | sz * cy, sz * sy * sx + cz * cx, sz * sy * cx - cz * sx, 17 | -sy, cy * sx, cy * cx); 18 | } 19 | 20 | } // namespace math -------------------------------------------------------------------------------- /src/lib/math/dummy.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/k-ishiyama/toymodels/dba66c4438ba1b73bca2b209fe2b1727f3b1c294/src/lib/math/dummy.cpp -------------------------------------------------------------------------------- /src/lib/window/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | AddLibraryProject(window) 2 | -------------------------------------------------------------------------------- /src/lib/window/Log.cpp: -------------------------------------------------------------------------------- 1 | #include "Log.hpp" 2 | #include 3 | 4 | #if _UNICODE 5 | #define _T(x) L##x 6 | #else 7 | #define _T(x) x 8 | #endif 9 | 10 | namespace sys 11 | { 12 | 13 | void sys::Log(const char *inMessage) 14 | { 15 | OutputDebugString(_T(inMessage)); 16 | } 17 | 18 | } // namespace sys -------------------------------------------------------------------------------- /src/lib/window/Log.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "WINDOWExport.hpp" 3 | 4 | namespace sys 5 | { 6 | void WINDOW_EXPORT Log(const char* inMessage); 7 | } // namespace sys -------------------------------------------------------------------------------- /src/lib/window/Window.cpp: -------------------------------------------------------------------------------- 1 | #include "Window.hpp" 2 | #include "Log.hpp" 3 | #include 4 | #include // GET_X_LPARAM, GET_Y_LPARAM 5 | #include 6 | 7 | #if _UNICODE 8 | #define _T(x) L##x 9 | #else 10 | #define _T(x) x 11 | #endif 12 | 13 | namespace wnd 14 | { 15 | struct Window_win32 : WindowBase 16 | { 17 | public: 18 | Window_win32() {}; 19 | virtual ~Window_win32() {}; 20 | virtual void Update(UpdateResult& outResult); 21 | // Register class and create window 22 | virtual bool Initialize(const char* inWindowName); 23 | virtual void* GetWindowHandle(); 24 | 25 | protected: 26 | // Called every time the application receives a message 27 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 28 | { 29 | PAINTSTRUCT ps; 30 | HDC hdc; 31 | 32 | InputArgument input_arg; 33 | InputEventCallbackFunc callback = nullptr; 34 | switch (message) 35 | { 36 | case WM_SIZE: 37 | break; 38 | 39 | case WM_PAINT: 40 | hdc = BeginPaint(hWnd, &ps); 41 | EndPaint(hWnd, &ps); 42 | break; 43 | 44 | case WM_DESTROY: 45 | PostQuitMessage(0); 46 | break; 47 | 48 | case WM_LBUTTONDOWN: 49 | input_arg.index = 0; 50 | callback = mInputEventCallbackFunc[static_cast(InputEvent::MOUSE_BUTTONDOWN)]; 51 | SetCapture(hWnd); 52 | break; 53 | 54 | case WM_LBUTTONUP: 55 | input_arg.index = 0; 56 | callback = mInputEventCallbackFunc[static_cast(InputEvent::MOUSE_BUTTONUP)]; 57 | ReleaseCapture(); 58 | break; 59 | 60 | case WM_RBUTTONDOWN: 61 | input_arg.index = 1; 62 | callback = mInputEventCallbackFunc[static_cast(InputEvent::MOUSE_BUTTONDOWN)]; 63 | SetCapture(hWnd); 64 | break; 65 | 66 | case WM_RBUTTONUP: 67 | input_arg.index = 1; 68 | callback = mInputEventCallbackFunc[static_cast(InputEvent::MOUSE_BUTTONUP)]; 69 | ReleaseCapture(); 70 | break; 71 | 72 | case WM_MBUTTONDOWN: 73 | input_arg.index = 2; 74 | callback = mInputEventCallbackFunc[static_cast(InputEvent::MOUSE_BUTTONDOWN)]; 75 | SetCapture(hWnd); 76 | break; 77 | 78 | case WM_MBUTTONUP: 79 | input_arg.index = 2; 80 | callback = mInputEventCallbackFunc[static_cast(InputEvent::MOUSE_BUTTONUP)]; 81 | ReleaseCapture(); 82 | break; 83 | 84 | case WM_MOUSEMOVE: 85 | input_arg.x = static_cast(GET_X_LPARAM(lParam)); 86 | input_arg.y = static_cast(GET_Y_LPARAM(lParam)); 87 | callback = mInputEventCallbackFunc[static_cast(InputEvent::MOUSE_MOVE)]; 88 | break; 89 | 90 | case WM_MOUSEWHEEL: 91 | input_arg.index = GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? 1 : 0; 92 | callback = mInputEventCallbackFunc[static_cast(InputEvent::MOUSE_WHEEL)]; 93 | return 0; 94 | 95 | 96 | case WM_KEYDOWN: 97 | if(wParam < 256) 98 | { 99 | input_arg.index = wParam; 100 | callback = mInputEventCallbackFunc[static_cast(InputEvent::KEY_DOWN)]; 101 | } 102 | break; 103 | 104 | case WM_KEYUP: 105 | if (wParam < 256) 106 | { 107 | input_arg.index = wParam; 108 | callback = mInputEventCallbackFunc[static_cast(InputEvent::KEY_UP)]; 109 | } 110 | break; 111 | 112 | case WM_SYSKEYDOWN: 113 | if (wParam < 256) 114 | { 115 | input_arg.index = wParam; 116 | callback = mInputEventCallbackFunc[static_cast(InputEvent::KEY_DOWN)]; 117 | } 118 | SetCapture(hWnd); 119 | break; 120 | 121 | case WM_SYSKEYUP: 122 | if (wParam < 256) 123 | { 124 | input_arg.index = wParam; 125 | callback = mInputEventCallbackFunc[static_cast(InputEvent::KEY_UP)]; 126 | } 127 | ReleaseCapture(); 128 | break; 129 | 130 | case WM_CHAR: 131 | if (wParam > 0 && wParam < 0x10000) 132 | { 133 | input_arg.index = wParam; 134 | callback = mInputEventCallbackFunc[static_cast(InputEvent::KEY_CHAR)]; 135 | } 136 | break; 137 | 138 | default: 139 | return DefWindowProc(hWnd, message, wParam, lParam); 140 | } 141 | 142 | if (callback) 143 | callback(input_arg); 144 | 145 | return 0; 146 | } 147 | 148 | static LRESULT CALLBACK sBaseWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 149 | { 150 | Window_win32* pTargetWnd = (Window_win32*)GetProp(hWnd, _T("Window_win32")); 151 | 152 | if (!pTargetWnd) 153 | { 154 | if ((uMsg == WM_CREATE) || (uMsg == WM_NCCREATE)) 155 | pTargetWnd = (Window_win32*)((LPCREATESTRUCT)lParam)->lpCreateParams; 156 | else if (uMsg == WM_INITDIALOG) 157 | pTargetWnd = (Window_win32*)lParam; 158 | } 159 | else 160 | { 161 | LRESULT lResult = pTargetWnd->WndProc(hWnd, uMsg, wParam, lParam); 162 | return lResult; 163 | 164 | } 165 | return DefWindowProc(hWnd, uMsg, wParam, lParam); 166 | } 167 | 168 | HWND mWindowHandle = NULL; 169 | HINSTANCE mInstance = NULL; 170 | }; 171 | 172 | void Window_win32::Update(UpdateResult& outResult) 173 | { 174 | outResult.mState = UpdateResult::State::Idle; 175 | outResult.mExitCode = 0; 176 | 177 | MSG msg = { 0 }; 178 | BOOL msg_result = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 179 | if (msg_result) 180 | { 181 | if (WM_QUIT == msg.message) 182 | { 183 | outResult.mState = UpdateResult::State::Exit; 184 | outResult.mExitCode = (int)msg.wParam; 185 | return; 186 | } 187 | TranslateMessage(&msg); 188 | DispatchMessage(&msg); 189 | outResult.mState = UpdateResult::State::Busy; 190 | } 191 | } 192 | 193 | bool Window_win32::Initialize(const char* inWindowName) 194 | { 195 | HINSTANCE hInstance = GetModuleHandle(NULL); // handle of this app's instance 196 | // LPTSTR CommandLineParams = GetCommandLine(); // command line params 197 | 198 | STARTUPINFO StartupInfo; 199 | GetStartupInfo(&StartupInfo); // initial state of this window 200 | // int nCmdShow = StartupInfo.wShowWindow; // Notice(VS2017) : https://stackoverflow.com/questions/36953886/startupinfo-wshowwindow-is-0-when-running-from-visual-studio 201 | int nCmdShow = SW_SHOWNORMAL; 202 | 203 | // Register class 204 | WNDCLASSEX wcex; 205 | wcex.cbSize = sizeof(WNDCLASSEX); 206 | wcex.style = CS_HREDRAW | CS_VREDRAW; 207 | wcex.lpfnWndProc = this->sBaseWndProc; 208 | wcex.cbClsExtra = 0; 209 | wcex.cbWndExtra = 0; 210 | wcex.hInstance = hInstance; 211 | wcex.hIcon = NULL; 212 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 213 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 214 | wcex.lpszMenuName = NULL; 215 | wcex.lpszClassName = "WindowClass"; 216 | wcex.hIconSm = NULL; 217 | if (!RegisterClassEx(&wcex)) 218 | return false; 219 | 220 | // Create window 221 | mInstance = hInstance; 222 | // RECT rc = { 0, 0, 480, 320 }; 223 | RECT rc = { 0, 0, 640, 480 }; 224 | // RECT rc = { 0, 0, 1280, 960 }; 225 | 226 | mInfo.mWindowSize[0] = rc.right - rc.left; 227 | mInfo.mWindowSize[1] = rc.bottom - rc.top; 228 | 229 | const bool is_resizable = false; 230 | DWORD dwStyle = WS_OVERLAPPEDWINDOW; 231 | if (!is_resizable) 232 | dwStyle = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); 233 | 234 | AdjustWindowRect(&rc, dwStyle, FALSE); 235 | 236 | mWindowHandle = CreateWindow("WindowClass", inWindowName, 237 | dwStyle, 238 | CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, 239 | NULL); 240 | if (!mWindowHandle) 241 | return false; 242 | 243 | ShowWindow(mWindowHandle, nCmdShow); 244 | 245 | // Combine the window handle and WindowBase object 246 | SetProp(mWindowHandle, _T("Window_win32"), (HANDLE)this); 247 | 248 | return true; 249 | } 250 | 251 | void* Window_win32::GetWindowHandle() 252 | { 253 | return mWindowHandle; 254 | } 255 | 256 | WindowBase* WindowBase::Create() 257 | { 258 | return new Window_win32(); 259 | } 260 | 261 | } // namespace wnd -------------------------------------------------------------------------------- /src/lib/window/Window.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace wnd 5 | { 6 | struct Info 7 | { 8 | int mWindowSize[2] = { 0 }; // width, height 9 | }; 10 | 11 | enum struct InputEvent 12 | { 13 | MOUSE_MOVE = 0, 14 | MOUSE_WHEEL, 15 | MOUSE_BUTTONDOWN, 16 | MOUSE_BUTTONUP, 17 | KEY_DOWN, 18 | KEY_UP, 19 | KEY_CHAR, 20 | COUNT, 21 | }; 22 | 23 | struct InputArgument 24 | { 25 | std::uint32_t index; 26 | std::uint16_t x; 27 | std::uint16_t y; 28 | }; 29 | 30 | using InputEventCallbackFunc = std::function; 31 | 32 | struct WindowBase 33 | { 34 | public: 35 | WindowBase() {} 36 | static WindowBase* Create(); 37 | virtual ~WindowBase() {} 38 | 39 | struct UpdateResult 40 | { 41 | enum struct State { Idle, Busy, Exit }; 42 | State mState; 43 | int mExitCode; 44 | }; 45 | virtual bool Initialize(const char* inWindowName) = 0; 46 | virtual void Update(UpdateResult& outResult) = 0; 47 | virtual void* GetWindowHandle() = 0; 48 | const Info& GetInfo() { return mInfo; } 49 | 50 | void RegisterInputEventCallbackFunc(InputEvent inEvent, InputEventCallbackFunc inFunc) 51 | { 52 | mInputEventCallbackFunc[static_cast(inEvent)] = inFunc; 53 | } 54 | 55 | protected: 56 | Info mInfo; 57 | InputEventCallbackFunc mInputEventCallbackFunc[static_cast(InputEvent::COUNT)] = { nullptr }; 58 | }; 59 | 60 | 61 | } // namespace sys 62 | 63 | -------------------------------------------------------------------------------- /src/lib/window/WindowExport.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_WIN32) && defined(BUILD_SHARED_LIBS) 4 | #ifdef window_EXPORTS 5 | #define WINDOW_EXPORT __declspec( dllexport ) 6 | #else 7 | #define WINDOW_EXPORT __declspec( dllimport ) 8 | #endif 9 | #else 10 | #define WINDOW_EXPORT 11 | #endif -------------------------------------------------------------------------------- /src/test/lib/math/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Define the target project for test 2 | set(test_target math) 3 | 4 | # Properties->C/C++->General->Additional Include Directories 5 | include_directories ("${PROJECT_SOURCE_DIR}") 6 | 7 | # Collect sources 8 | file(GLOB sources "*.hpp" "*.cpp") 9 | 10 | # Create named folders for the sources within the .vcproj 11 | # Empty name lists them directly under the .vcproj 12 | source_group("" FILES ${sources}) 13 | 14 | add_executable(${test_target}_test ${sources}) 15 | 16 | target_link_libraries(${test_target}_test ${test_target}) 17 | set_property(TARGET ${test_target}_test PROPERTY FOLDER "test") 18 | 19 | add_test(NAME ${test_target}_test COMMAND ${test_target}_test) 20 | -------------------------------------------------------------------------------- /src/test/lib/math/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int main() 9 | { 10 | using namespace math; 11 | 12 | const int seed = static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); 13 | std::mt19937 rand_engine(seed); 14 | std::uniform_real_distribution uniform_dist(-1e6f, 1e6f); 15 | 16 | float n[9]; 17 | for (int i = 0; i < 9; ++i) 18 | n[i] = uniform_dist(rand_engine); 19 | Float3x3 mat33 = Float3x3(Float3(n[0], n[1], n[2]), Float3(n[3], n[4], n[5]), Float3(n[6], n[7], n[8])); 20 | assert(NearlyEqual(1.0f / Determinant(mat33), Determinant(Inverse(mat33)))); 21 | 22 | Float3x3 inv_mat33 = Inverse(mat33); 23 | Float3x3 mat33B = mat33 * inv_mat33; 24 | 25 | return 0; 26 | } -------------------------------------------------------------------------------- /src/thirdparty/imgui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Define the project name 2 | set(project_name imgui) 3 | 4 | # Collect sources into the variable SOURCES 5 | file (GLOB MAIN_SOURCES "imgui/*.h" "imgui/*.cpp") 6 | file (GLOB DX11_SOURCES "imgui/examples/directx11_example/*.h" "imgui/examples/directx11_example/*.cpp") 7 | 8 | # Create named folders for the sources within the .vcproj 9 | source_group("" FILES ${MAIN_SOURCES}) 10 | source_group("examples\\directx11_example" FILES ${DX11_SOURCES}) 11 | 12 | # Properties->C/C++->General->Additional Include Directories 13 | include_directories(./imgui) 14 | 15 | # Set Properties->General->Configuration Type 16 | if (build_shared_libs) 17 | add_definitions(-DBUILD_SHARED_LIBS) 18 | add_library(${project_name} SHARED ${MAIN_SOURCES} ${DX11_SOURCES}) 19 | else (build_shared_libs) 20 | add_library(${project_name} STATIC ${MAIN_SOURCES} ${DX11_SOURCES}) 21 | endif (build_shared_libs) 22 | 23 | # Creates a folder and adds target project under it 24 | set_property(TARGET ${project_name} PROPERTY FOLDER "thirdparty") 25 | 26 | # Properties->General->Output Directory 27 | set_target_properties(${project_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) 28 | 29 | if (build_shared_libs) 30 | # Adds logic to INSTALL.vcproj to copy ${project_name}.dll to the destination directory 31 | install (TARGETS ${project_name} 32 | RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/_install 33 | LIBRARY DESTINATION ${PROJECT_SOURCE_DIR}/_install) 34 | endif (build_shared_libs) 35 | 36 | # Properties->Linker->Input->Additional Dependencies 37 | target_link_libraries(${project_name} d3d11) 38 | target_link_libraries(${project_name} d3dcompiler) 39 | target_link_libraries(${project_name} dxguid) 40 | --------------------------------------------------------------------------------