diff --git a/.lfsconfig b/.lfsconfig index b1cea2523..b5a7e69fc 100644 --- a/.lfsconfig +++ b/.lfsconfig @@ -1,3 +1,4 @@ # Redirect to our own Git LFS server [lfs] url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs" +locksverify = false diff --git a/Content/Shaders/AtmospherePreCompute.flax b/Content/Shaders/AtmospherePreCompute.flax index 80279402c..753bb46dc 100644 --- a/Content/Shaders/AtmospherePreCompute.flax +++ b/Content/Shaders/AtmospherePreCompute.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71772e7059bc377bd2fc14e5e193af24e4e4c03f1d782fbf779e87901db0c329 -size 13430 +oid sha256:7435c6133694bd0f4fbff46978b5813bdbf9faa21763e9cf702410a6cd041585 +size 11720 diff --git a/Content/Shaders/ColorGrading.flax b/Content/Shaders/ColorGrading.flax index 7ffc7ff4f..eef24db35 100644 --- a/Content/Shaders/ColorGrading.flax +++ b/Content/Shaders/ColorGrading.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a5b9c4b320ca1926bbc5a0c0b57b758e89cbc15cfa801db8c11714c06decc578 -size 11553 +oid sha256:e25c173644fa6e459791e1222514b77d71847bcc1d063accbf5e94e16d83527f +size 11057 diff --git a/Content/Shaders/Fog.flax b/Content/Shaders/Fog.flax index 3bb6a755e..126388165 100644 --- a/Content/Shaders/Fog.flax +++ b/Content/Shaders/Fog.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f87bf73c8c4f77c4817d80d0fea85e006369ae508fb0f8922a502c393176f7b8 -size 3129 +oid sha256:17bb8171cdafe227429d694733060a5ce7c647a48da9d6f4215f336ada03dc56 +size 2943 diff --git a/Content/Shaders/Histogram.flax b/Content/Shaders/Histogram.flax index 0579197bd..557232811 100644 --- a/Content/Shaders/Histogram.flax +++ b/Content/Shaders/Histogram.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ccd2302c7b28d088ea2f810d22f81bb5beccd7e483ae0f7248ccbe0fd64ce70b -size 2928 +oid sha256:d308ec40abf308fe3d713abb124dbc7f0094c8e141dfa9a9600888deb0601804 +size 2609 diff --git a/Content/Shaders/MotionBlur.flax b/Content/Shaders/MotionBlur.flax index 1314b0326..5da5d5bff 100644 --- a/Content/Shaders/MotionBlur.flax +++ b/Content/Shaders/MotionBlur.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d070a6cffc576f807e91f023f9331f6f2785f1ad48cd463b1b8431bd4373813 -size 13463 +oid sha256:46132e260d5f8b92e81760685903ea8fcfb2e13cca234076046b838a7f904b43 +size 13051 diff --git a/Content/Shaders/PostProcessing.flax b/Content/Shaders/PostProcessing.flax index 7ce10e953..cd3923673 100644 --- a/Content/Shaders/PostProcessing.flax +++ b/Content/Shaders/PostProcessing.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8d7c53061c2f0f6335cae78f09e11f08818196a3f0f40f3bced2c9b46cfe0b5 -size 16988 +oid sha256:6933ed1b8e8257ca9bd0a5e25deda41d3d79fff2d3aefb2b6be5b8e8d308c5f6 +size 17028 diff --git a/Content/Shaders/ProbesFilter.flax b/Content/Shaders/ProbesFilter.flax index 7a8c0b14d..c95b5aac3 100644 --- a/Content/Shaders/ProbesFilter.flax +++ b/Content/Shaders/ProbesFilter.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cb6bf18e4179a4e2d85b23b3a7877dc50354d5030b0357cc365fc204b7a968f -size 5395 +oid sha256:24e0095be6046f8cd05ed79f25c6b90b8c257420b686e050fdcedb6b210d963c +size 4999 diff --git a/Content/Shaders/VolumetricFog.flax b/Content/Shaders/VolumetricFog.flax index e8a1ae9ca..e62d7f4c1 100644 --- a/Content/Shaders/VolumetricFog.flax +++ b/Content/Shaders/VolumetricFog.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be3a9f6acede8a4901e9f3944b9a0ae586adee234eb3be44b343f21f21728b05 -size 16131 +oid sha256:daa92cd2b9f3dbc55923cf92561d6d91ab8f5d14dec183f418e03932d09f26b3 +size 15820 diff --git a/Development/Scripts/Windows/CallBuildTool.bat b/Development/Scripts/Windows/CallBuildTool.bat index 1ee01db38..021eeeed2 100644 --- a/Development/Scripts/Windows/CallBuildTool.bat +++ b/Development/Scripts/Windows/CallBuildTool.bat @@ -2,93 +2,56 @@ rem Copyright (c) 2012-2020 Wojciech Figat. All rights reserved. -rem Make sure the batch file exists in the root folder. -if not exist "Development\Scripts\Windows\GetMSBuildPath.bat" goto Error_BatchFileInWrongLocation +if not exist "Development\Scripts\Windows\GetMSBuildPath.bat" goto Error_InvalidLocation -rem Get the path to MSBuild executable. call "Development\Scripts\Windows\GetMSBuildPath.bat" if errorlevel 1 goto Error_NoVisualStudioEnvironment -rem If using VS2017, check that NuGet package manager is installed. -if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto NoVsWhere - -set MSBUILD_15_EXE= +if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto Compile for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath') do ( for %%j in (15.0, Current) do ( if exist "%%i\MSBuild\%%j\Bin\MSBuild.exe" ( - set MSBUILD_15_EXE="%%i\MSBuild\%%j\Bin\MSBuild.exe" - goto FoundMsBuild15 + set MSBUILD_PATH="%%i\MSBuild\%%j\Bin\MSBuild.exe" + goto Compile ) ) ) -:FoundMsBuild15 -set MSBUILD_15_EXE_WITH_NUGET= -for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -products * -requires Microsoft.Component.MSBuild -requires Microsoft.VisualStudio.Component.NuGet -property installationPath') do ( - if exist "%%i\MSBuild\15.0\Bin\MSBuild.exe" ( - set MSBUILD_15_EXE_WITH_NUGET="%%i\MSBuild\15.0\Bin\MSBuild.exe" - goto FoundMsBuild15WithNuget - ) -) -:FoundMsBuild15WithNuget - -if not [%MSBUILD_15_EXE%] == [] ( - set MSBUILD_EXE=%MSBUILD_15_EXE% - goto NoVsWhere -) - -if not [%MSBUILD_EXE%] == [%MSBUILD_15_EXE_WITH_NUGET%] goto Error_RequireNugetPackageManager - -:NoVsWhere - -rem Check to see if the build tool source files have changed. Some can be included conditionally based on NDA access. +:Compile md Cache\Intermediate >nul 2>nul dir /s /b Source\Tools\Flax.Build\*.cs >Cache\Intermediate\Flax.Build.Files.txt fc /b Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Flax.Build.PrevFiles.txt >nul 2>nul if not errorlevel 1 goto SkipClean -copy /y Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Flax.Build.PrevFiles.txt >nul -%MSBUILD_EXE% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Clean -:SkipClean -%MSBUILD_EXE% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Build -if errorlevel 1 goto Error_CompileFailed -rem Run the build tool using the provided arguments. +copy /y Cache\Intermediate\Build\Flax.Build.Files.txt Cache\Intermediate\Build\Flax.Build.PrevFiles.txt >nul +%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Clean +:SkipClean +%MSBUILD_PATH% /nologo /verbosity:quiet Source\Tools\Flax.Build\Flax.Build.csproj /property:Configuration=Release /property:Platform=AnyCPU /target:Build +if errorlevel 1 goto Error_CompilationFailed + Binaries\Tools\Flax.Build.exe %* if errorlevel 1 goto Error_FlaxBuildFailed - -rem Done. exit /B 0 -:Error_BatchFileInWrongLocation +:Error_InvalidLocation echo. -echo CallBuildTool ERROR: The batch file does not appear to be located in the root directory. This script must be run from within that directory. +echo CallBuildTool ERROR: The script is in invalid directory. echo. goto Exit - :Error_NoVisualStudioEnvironment echo. -echo CallBuildTool ERROR: We couldn't find a valid installation of Visual Studio. This program requires Visual Studio 2015. Please check that you have Visual Studio installed, then verify that the HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0\InstallDir (or HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\14.0\InstallDir on 32-bit machines) registry value is set. Visual Studio configures this value when it is installed, and this program expects it to be set to the '\Common7\IDE\' sub-folder under a valid Visual Studio installation directory. +echo CallBuildTool ERROR: Missing Visual Studio 2015 or newer. echo. goto Exit - -:Error_RequireNugetPackageManager -echo. -echo CallBuildTool ERROR: NuGet Package Manager is requried to be installed to use %MSBUILD_EXE%. Please run the Visual Studio Installer and add it from the individual components list (in the 'Code Tools' category). -echo. -goto Exit - -:Error_CompileFailed +:Error_CompilationFailed echo. echo CallBuildTool ERROR: Failed to compile Flax.Build project. echo. goto Exit - :Error_FlaxBuildFailed echo. echo CallBuildTool ERROR: Flax.Build tool failed. echo. goto Exit - :Exit -rem Exit with error. exit /B 1 diff --git a/Development/Scripts/Windows/GetMSBuildPath.bat b/Development/Scripts/Windows/GetMSBuildPath.bat index 8d8651719..6eaf3af4f 100644 --- a/Development/Scripts/Windows/GetMSBuildPath.bat +++ b/Development/Scripts/Windows/GetMSBuildPath.bat @@ -2,72 +2,57 @@ rem Copyright (c) 2012-2020 Wojciech Figat. All rights reserved. -set MSBUILD_EXE= +set MSBUILD_PATH= -rem Try to get the MSBuild 15 path using vswhere (see https://github.com/Microsoft/vswhere). -if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto no_vswhere +if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto VsWhereNotFound for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath') do ( if exist "%%i\MSBuild\15.0\Bin\MSBuild.exe" ( - set MSBUILD_EXE="%%i\MSBuild\15.0\Bin\MSBuild.exe" - goto Succeeded + set MSBUILD_PATH="%%i\MSBuild\15.0\Bin\MSBuild.exe" + goto End ) ) -:no_vswhere +:VsWhereNotFound -rem Check for MSBuild 15. This is installed alongside Visual Studio 2017, so we get the path relative to that. -call :ReadInstallPath Microsoft\VisualStudio\SxS\VS7 15.0 MSBuild\15.0\bin\MSBuild.exe -if not errorlevel 1 goto Succeeded - -rem Try to get the MSBuild 14.0 path directly (see https://msdn.microsoft.com/en-us/library/hh162058(v=vs.120).aspx). if exist "%ProgramFiles(x86)%\MSBuild\14.0\bin\MSBuild.exe" ( - set MSBUILD_EXE="%ProgramFiles(x86)%\MSBuild\14.0\bin\MSBuild.exe" - goto Succeeded + set MSBUILD_PATH="%ProgramFiles(x86)%\MSBuild\14.0\bin\MSBuild.exe" + goto End ) -rem Try to get the MSBuild 14.0 path from the registry. -call :ReadInstallPath Microsoft\MSBuild\ToolsVersions\14.0 MSBuildToolsPath MSBuild.exe -if not errorlevel 1 goto Succeeded +call :GetInstallPath Microsoft\VisualStudio\SxS\VS7 15.0 MSBuild\15.0\bin\MSBuild.exe +if not errorlevel 1 goto End +call :GetInstallPath Microsoft\MSBuild\ToolsVersions\14.0 MSBuildToolsPath MSBuild.exe +if not errorlevel 1 goto End +call :GetInstallPath Microsoft\MSBuild\ToolsVersions\12.0 MSBuildToolsPath MSBuild.exe +if not errorlevel 1 goto End +call :GetInstallPath Microsoft\MSBuild\ToolsVersions\4.0 MSBuildToolsPath MSBuild.exe +if not errorlevel 1 goto End -rem Check for older versions of MSBuild. These are registered as separate versions in the registry. -call :ReadInstallPath Microsoft\MSBuild\ToolsVersions\12.0 MSBuildToolsPath MSBuild.exe -if not errorlevel 1 goto Succeeded -call :ReadInstallPath Microsoft\MSBuild\ToolsVersions\4.0 MSBuildToolsPath MSBuild.exe -if not errorlevel 1 goto Succeeded - -rem Searching failed. exit /B 1 - -rem Searching done! -:Succeeded +:End exit /B 0 -rem Subroutine to query the registry under HKCU/HKLM Win32/Wow64 software registry keys for a certain install directory. -rem Arguments: -rem %1 = Registry path under the 'SOFTWARE' registry key -rem %2 = Value name -rem %3 = Relative path under this directory to look for an installed executable. -:ReadInstallPath +:GetInstallPath for /f "tokens=2,*" %%A in ('REG.exe query HKCU\SOFTWARE\%1 /v %2 2^>Nul') do ( if exist "%%B%%3" ( - set MSBUILD_EXE="%%B%3" + set MSBUILD_PATH="%%B%3" exit /B 0 ) ) for /f "tokens=2,*" %%A in ('REG.exe query HKLM\SOFTWARE\%1 /v %2 2^>Nul') do ( if exist "%%B%3" ( - set MSBUILD_EXE="%%B%3" + set MSBUILD_PATH="%%B%3" exit /B 0 ) ) for /f "tokens=2,*" %%A in ('REG.exe query HKCU\SOFTWARE\Wow6432Node\%1 /v %2 2^>Nul') do ( if exist "%%B%%3" ( - set MSBUILD_EXE="%%B%3" + set MSBUILD_PATH="%%B%3" exit /B 0 ) ) for /f "tokens=2,*" %%A in ('REG.exe query HKLM\SOFTWARE\Wow6432Node\%1 /v %2 2^>Nul') do ( if exist "%%B%3" ( - set MSBUILD_EXE="%%B%3" + set MSBUILD_PATH="%%B%3" exit /B 0 ) ) diff --git a/Flax.flaxproj b/Flax.flaxproj index 770de4001..eb99c004a 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -3,7 +3,7 @@ "Version": { "Major": 1, "Minor": 0, - "Build": 6213 + "Build": 6214 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.", diff --git a/RegisterEngineLocation.bat b/RegisterEngineLocation.bat index 56ccc496c..bb1a915a3 100644 --- a/RegisterEngineLocation.bat +++ b/RegisterEngineLocation.bat @@ -3,7 +3,7 @@ rem Copyright (c) 2012-2020 Wojciech Figat. All rights reserved. setlocal -pushd +pushd %~dp0 echo Registering Flax Engine project files... rem Check the current versions config @@ -20,7 +20,7 @@ goto Done rem Register the location (append to the end) :notfound -echo Location '%EngineLocation%' is not registered. Adding it to the lsit of engine versions. +echo Location '%EngineLocation%' is not registered. Adding it to the list of engine versions. echo %EngineLocation%>>"%appdata%\Flax\Versions.txt" goto Done diff --git a/Source/Editor/GUI/ContextMenu/ContextMenu.cs b/Source/Editor/GUI/ContextMenu/ContextMenu.cs index 493c9d14b..b48e3ca59 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenu.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenu.cs @@ -122,6 +122,25 @@ namespace FlaxEditor.GUI.ContextMenu /// public Panel ItemsContainer => _panel; + /// + /// The auto sort. + /// + private bool _autosort; + + /// + /// The auto sort property. + /// + public bool AutoSort + { + get => _autosort; + set + { + _autosort = value; + if (_autosort) + SortButtons(); + } + } + /// /// Initializes a new instance of the class. /// @@ -137,6 +156,24 @@ namespace FlaxEditor.GUI.ContextMenu }; } + /// + /// Sorts all alphabetically. + /// + /// Overrides property. + public void SortButtons(bool force = false) + { + if (!_autosort && !force) + return; + _panel.Children.Sort((control, control1) => + { + if (control is ContextMenuButton cmb && control1 is ContextMenuButton cmb1) + return string.Compare(cmb.Text, cmb1.Text, StringComparison.OrdinalIgnoreCase); + if (!(control is ContextMenuButton)) + return 1; + return -1; + }); + } + /// /// Removes all the added items (buttons, separators, etc.). /// @@ -158,6 +195,7 @@ namespace FlaxEditor.GUI.ContextMenu { var item = new ContextMenuButton(this, text); item.Parent = _panel; + SortButtons(); return item; } @@ -171,6 +209,7 @@ namespace FlaxEditor.GUI.ContextMenu { var item = new ContextMenuButton(this, text, shortKeys); item.Parent = _panel; + SortButtons(); return item; } @@ -185,6 +224,7 @@ namespace FlaxEditor.GUI.ContextMenu var item = new ContextMenuButton(this, text); item.Parent = _panel; item.Clicked += clicked; + SortButtons(); return item; } @@ -199,6 +239,7 @@ namespace FlaxEditor.GUI.ContextMenu var item = new ContextMenuButton(this, text); item.Parent = _panel; item.ButtonClicked += clicked; + SortButtons(); return item; } @@ -214,6 +255,7 @@ namespace FlaxEditor.GUI.ContextMenu var item = new ContextMenuButton(this, text, shortKeys); item.Parent = _panel; item.Clicked += clicked; + SortButtons(); return item; } diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs index ec9c0dfb8..7fb3fe38a 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs @@ -136,6 +136,10 @@ namespace FlaxEditor.GUI.ContextMenu // Direction: up isUp = true; locationSS.Y -= dpiSize.Y; + + // Offset to fix sub-menu location + if (parent is ContextMenu menu && menu._childCM != null) + locationSS.Y += 30.0f * dpiScale; } if (monitorBounds.Right < rightBottomLocationSS.X) { diff --git a/Source/Editor/GUI/MainMenu.cs b/Source/Editor/GUI/MainMenu.cs index fcc1e9811..d6e5886bb 100644 --- a/Source/Editor/GUI/MainMenu.cs +++ b/Source/Editor/GUI/MainMenu.cs @@ -193,41 +193,64 @@ namespace FlaxEditor.GUI if (!_window.IsMaximized) { var winSize = RootWindow.Size * Platform.DpiScale; - - if (pos.Y > winSize.Y - 5 && pos.X < 5) + /* + * Distance from which the mouse is considered to be on the border/corner + * You can change the distance by modifying the x value in : (int)(x * Platform.DpiScale) + */ + int distance = (int)(10 * Platform.DpiScale); + + if (pos.Y > winSize.Y - distance && pos.X < distance) return WindowHitCodes.BottomLeft; - if (pos.X > winSize.X - 5 && pos.Y > winSize.Y - 5) + if (pos.X > winSize.X - distance && pos.Y > winSize.Y - distance) return WindowHitCodes.BottomRight; - if (pos.Y < 5 && pos.X < 5) + if (pos.Y < distance && pos.X < distance) return WindowHitCodes.TopLeft; - if (pos.Y < 5 && pos.X > winSize.X - 5) + if (pos.Y < distance && pos.X > winSize.X - distance) return WindowHitCodes.TopRight; - if (pos.X > winSize.X - 5) + if (pos.X > winSize.X - distance) return WindowHitCodes.Right; - if (pos.X < 5) + if (pos.X < distance) return WindowHitCodes.Left; - if (pos.Y < 5) + if (pos.Y < distance) return WindowHitCodes.Top; - if (pos.Y > winSize.Y - 5) + if (pos.Y > winSize.Y - distance) return WindowHitCodes.Bottom; } var menuPos = PointFromWindow(pos); var controlUnderMouse = GetChildAt(menuPos); var isMouseOverSth = controlUnderMouse != null && controlUnderMouse != _title; - if (new Rectangle(Vector2.Zero, Size).Contains(ref menuPos) && !isMouseOverSth) + var rb = GetRightButton(); + if (rb != null && _minimizeButton != null && new Rectangle(rb.UpperRight * Platform.DpiScale, (_minimizeButton.BottomLeft - rb.UpperRight) * Platform.DpiScale).Contains(ref menuPos) && !isMouseOverSth) return WindowHitCodes.Caption; return WindowHitCodes.Client; } + /// + /// Return the rightmost button. + /// + /// Rightmost button, null if there is no + private MainMenuButton GetRightButton() + { + MainMenuButton b = null; + foreach (var control in Children) + { + if (b == null && control is MainMenuButton) + b = (MainMenuButton)control; + if (control is MainMenuButton && control.Right > b.Right) + b = (MainMenuButton)control; + } + return b; + } + /// /// Adds the button. /// diff --git a/Source/Editor/Managed/ManagedEditor.cpp b/Source/Editor/Managed/ManagedEditor.cpp index 8cc872dfc..5717787a2 100644 --- a/Source/Editor/Managed/ManagedEditor.cpp +++ b/Source/Editor/Managed/ManagedEditor.cpp @@ -98,7 +98,7 @@ void OnFinishBake(const ProbesRenderer::Entry& e) void OnBrushModified(CSG::Brush* brush) { - if (Editor::Managed->CanAutoBuildCSG()) + if (brush && Editor::Managed && Editor::Managed->CanAutoBuildCSG()) { CSG::Builder::Build(brush->GetBrushScene(), ManagedEditor::ManagedEditorOptions.AutoRebuildCSGTimeoutMs); } diff --git a/Source/Editor/Utilities/Constants.cs b/Source/Editor/Utilities/Constants.cs index 2a02f2858..aef76936d 100644 --- a/Source/Editor/Utilities/Constants.cs +++ b/Source/Editor/Utilities/Constants.cs @@ -9,7 +9,7 @@ namespace FlaxEditor.Utilities { public static readonly string DiscordUrl = "https://flaxengine.com/discord"; public static readonly string DocsUrl = "https://docs.flaxengine.com/"; - public static readonly string BugTrackerUrl = "https://github.com/FlaxEngine/FlaxAPI/issues"; + public static readonly string BugTrackerUrl = "https://github.com/FlaxEngine/FlaxEngine/issues"; public static readonly string WebsiteUrl = "https://flaxengine.com"; public static readonly string FacebookUrl = "https://facebook.com/FlaxEngine"; public static readonly string YoutubeUrl = "https://www.youtube.com/channel/UChdER2A3n19rJWIMOZJClhw"; diff --git a/Source/Editor/Viewport/Cameras/FPSCamera.cs b/Source/Editor/Viewport/Cameras/FPSCamera.cs index 95ae37ffb..5058bbc19 100644 --- a/Source/Editor/Viewport/Cameras/FPSCamera.cs +++ b/Source/Editor/Viewport/Cameras/FPSCamera.cs @@ -160,8 +160,8 @@ namespace FlaxEditor.Viewport.Cameras if (IsAnimatingMove) return; - EditorViewport.Input input; - Viewport.GetInput(out input); + Viewport.GetInput(out var input); + Viewport.GetPrevInput(out var prevInput); var mainViewport = Viewport as MainEditorGizmoViewport; bool isUsingGizmo = mainViewport != null && mainViewport.TransformGizmo.ActiveAxis != TransformGizmo.Axis.None; @@ -202,7 +202,7 @@ namespace FlaxEditor.Viewport.Cameras } // Rotate or orbit - if (input.IsRotating || (input.IsOrbiting && !isUsingGizmo)) + if (input.IsRotating || (input.IsOrbiting && !isUsingGizmo && prevInput.IsOrbiting)) { yaw += mouseDelta.X; pitch += mouseDelta.Y; diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index 5b120f33f..42385fd5e 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -699,6 +699,15 @@ namespace FlaxEditor.Viewport input = _input; } + /// + /// Gets the input state data (from the previous update). + /// + /// The input. + public void GetPrevInput(out Input input) + { + input = _prevInput; + } + /// /// Creates the projection matrix. /// diff --git a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs index 55892b461..d11e39d95 100644 --- a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs +++ b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs @@ -377,13 +377,21 @@ namespace FlaxEditor.Windows.Assets { MarkAsEdited(); UpdateToolstrip(); - _propertiesEditor1.BuildLayoutOnUpdate(); - _propertiesEditor2.BuildLayoutOnUpdate(); + + if (!_isEditingInstancedParameterValue) + { + _propertiesEditor1.BuildLayoutOnUpdate(); + _propertiesEditor2.BuildLayoutOnUpdate(); + } } private void OnTimelineModified() { - _tmpParticleSystemIsDirty = true; + if (!_isEditingInstancedParameterValue) + { + _tmpParticleSystemIsDirty = true; + } + MarkAsEdited(); } diff --git a/Source/Editor/Windows/ContentWindow.ContextMenu.cs b/Source/Editor/Windows/ContentWindow.ContextMenu.cs index 2dd5ec3d7..d273ead49 100644 --- a/Source/Editor/Windows/ContentWindow.ContextMenu.cs +++ b/Source/Editor/Windows/ContentWindow.ContextMenu.cs @@ -139,6 +139,7 @@ namespace FlaxEditor.Windows c = cm.AddChildMenu("New"); c.ContextMenu.Tag = item; + c.ContextMenu.AutoSort = true; int newItems = 0; for (int i = 0; i < Editor.ContentDatabase.Proxy.Count; i++) { diff --git a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp index ecdc1f258..a2dbb7733 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp @@ -7,15 +7,13 @@ #include "QueueVulkan.h" #include "GPUContextVulkan.h" #include "GPUTimerQueryVulkan.h" -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER #include "DescriptorSetVulkan.h" -#endif void CmdBufferVulkan::AddWaitSemaphore(VkPipelineStageFlags waitFlags, SemaphoreVulkan* waitSemaphore) { - WaitFlags.Add(waitFlags); - ASSERT(!WaitSemaphores.Contains(waitSemaphore)); - WaitSemaphores.Add(waitSemaphore); + _waitFlags.Add(waitFlags); + ASSERT(!_waitSemaphores.Contains(waitSemaphore)); + _waitSemaphores.Add(waitSemaphore); } void CmdBufferVulkan::Begin() @@ -25,11 +23,11 @@ void CmdBufferVulkan::Begin() VkCommandBufferBeginInfo beginInfo; RenderToolsVulkan::ZeroStruct(beginInfo, VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO); beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - VALIDATE_VULKAN_RESULT(vkBeginCommandBuffer(CommandBufferHandle, &beginInfo)); + VALIDATE_VULKAN_RESULT(vkBeginCommandBuffer(_commandBufferHandle, &beginInfo)); #if VULKAN_USE_DESCRIPTOR_POOL_MANAGER // Acquire a descriptor pool set on - if (CurrentDescriptorPoolSetContainer == nullptr) + if (_descriptorPoolSetContainer == nullptr) { AcquirePoolSet(); } @@ -72,27 +70,23 @@ void CmdBufferVulkan::BeginRenderPass(RenderPassVulkan* renderPass, FramebufferV info.clearValueCount = clearValueCount; info.pClearValues = clearValues; - vkCmdBeginRenderPass(CommandBufferHandle, &info, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBeginRenderPass(_commandBufferHandle, &info, VK_SUBPASS_CONTENTS_INLINE); _state = State::IsInsideRenderPass; } void CmdBufferVulkan::EndRenderPass() { ASSERT(IsInsideRenderPass()); - vkCmdEndRenderPass(CommandBufferHandle); + vkCmdEndRenderPass(_commandBufferHandle); _state = State::IsInsideBegin; } -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - void CmdBufferVulkan::AcquirePoolSet() { - ASSERT(!CurrentDescriptorPoolSetContainer); - CurrentDescriptorPoolSetContainer = &_device->DescriptorPoolsManager->AcquirePoolSetContainer(); + ASSERT(!_descriptorPoolSetContainer); + _descriptorPoolSetContainer = &_device->DescriptorPoolsManager->AcquirePoolSetContainer(); } -#endif - #if GPU_ALLOW_PROFILE_EVENTS void CmdBufferVulkan::BeginEvent(const Char* name) @@ -138,19 +132,17 @@ void CmdBufferVulkan::RefreshFenceStatus() { _state = State::ReadyForBegin; - SubmittedWaitSemaphores.Clear(); + _submittedWaitSemaphores.Clear(); - vkResetCommandBuffer(CommandBufferHandle, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + vkResetCommandBuffer(_commandBufferHandle, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); _fence->GetOwner()->ResetFence(_fence); - FenceSignaledCounter++; + _fenceSignaledCounter++; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - if (CurrentDescriptorPoolSetContainer) + if (_descriptorPoolSetContainer) { - _device->DescriptorPoolsManager->ReleasePoolSet(*CurrentDescriptorPoolSetContainer); - CurrentDescriptorPoolSetContainer = nullptr; + _device->DescriptorPoolsManager->ReleasePoolSet(*_descriptorPoolSetContainer); + _descriptorPoolSetContainer = nullptr; } -#endif } } else @@ -161,20 +153,20 @@ void CmdBufferVulkan::RefreshFenceStatus() CmdBufferVulkan::CmdBufferVulkan(GPUDeviceVulkan* device, CmdBufferPoolVulkan* pool) : _device(device) - , CommandBufferHandle(VK_NULL_HANDLE) + , _commandBufferHandle(VK_NULL_HANDLE) , _state(State::ReadyForBegin) , _fence(nullptr) - , FenceSignaledCounter(0) - , SubmittedFenceCounter(0) - , CommandBufferPool(pool) + , _fenceSignaledCounter(0) + , _submittedFenceCounter(0) + , _commandBufferPool(pool) { VkCommandBufferAllocateInfo createCmdBufInfo; RenderToolsVulkan::ZeroStruct(createCmdBufInfo, VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO); createCmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; createCmdBufInfo.commandBufferCount = 1; - createCmdBufInfo.commandPool = CommandBufferPool->GetHandle(); + createCmdBufInfo.commandPool = _commandBufferPool->GetHandle(); - VALIDATE_VULKAN_RESULT(vkAllocateCommandBuffers(_device->Device, &createCmdBufInfo, &CommandBufferHandle)); + VALIDATE_VULKAN_RESULT(vkAllocateCommandBuffers(_device->Device, &createCmdBufInfo, &_commandBufferHandle)); _fence = _device->FenceManager.AllocateFence(); } @@ -193,7 +185,7 @@ CmdBufferVulkan::~CmdBufferVulkan() fenceManager.ReleaseFence(_fence); } - vkFreeCommandBuffers(_device->Device, CommandBufferPool->GetHandle(), 1, &CommandBufferHandle); + vkFreeCommandBuffers(_device->Device, _commandBufferPool->GetHandle(), 1, &_commandBufferHandle); } CmdBufferVulkan* CmdBufferPoolVulkan::Create() diff --git a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.h index 85893d89f..553e844e7 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.h @@ -11,9 +11,7 @@ class GPUDeviceVulkan; class CmdBufferPoolVulkan; class QueueVulkan; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER class DescriptorPoolSetContainerVulkan; -#endif /// /// Implementation of the command buffer for the Vulkan backend. @@ -36,20 +34,20 @@ public: private: GPUDeviceVulkan* _device; - VkCommandBuffer CommandBufferHandle; + VkCommandBuffer _commandBufferHandle; State _state; - Array WaitFlags; - Array WaitSemaphores; - Array SubmittedWaitSemaphores; + Array _waitFlags; + Array _waitSemaphores; + Array _submittedWaitSemaphores; void MarkSemaphoresAsSubmitted() { - WaitFlags.Clear(); + _waitFlags.Clear(); // Move to pending delete list - SubmittedWaitSemaphores = WaitSemaphores; - WaitSemaphores.Clear(); + _submittedWaitSemaphores = _waitSemaphores; + _waitSemaphores.Clear(); } FenceVulkan* _fence; @@ -58,12 +56,14 @@ private: #endif // Last value passed after the fence got signaled - volatile uint64 FenceSignaledCounter; + volatile uint64 _fenceSignaledCounter; // Last value when we submitted the cmd buffer; useful to track down if something waiting for the fence has actually been submitted - volatile uint64 SubmittedFenceCounter; + volatile uint64 _submittedFenceCounter; - CmdBufferPoolVulkan* CommandBufferPool; + CmdBufferPoolVulkan* _commandBufferPool; + + DescriptorPoolSetContainerVulkan* _descriptorPoolSetContainer = nullptr; public: @@ -75,7 +75,7 @@ public: CmdBufferPoolVulkan* GetOwner() { - return CommandBufferPool; + return _commandBufferPool; } State GetState() @@ -115,17 +115,17 @@ public: inline VkCommandBuffer GetHandle() const { - return CommandBufferHandle; + return _commandBufferHandle; } inline volatile uint64 GetFenceSignaledCounter() const { - return FenceSignaledCounter; + return _fenceSignaledCounter; } inline volatile uint64 GetSubmittedFenceCounter() const { - return SubmittedFenceCounter; + return _submittedFenceCounter; } public: @@ -138,11 +138,12 @@ public: void BeginRenderPass(RenderPassVulkan* renderPass, FramebufferVulkan* framebuffer, uint32 clearValueCount, VkClearValue* clearValues); void EndRenderPass(); -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - DescriptorPoolSetContainerVulkan* CurrentDescriptorPoolSetContainer = nullptr; + DescriptorPoolSetContainerVulkan* GetDescriptorPoolSet() const + { + return _descriptorPoolSetContainer; + } void AcquirePoolSet(); -#endif #if GPU_ALLOW_PROFILE_EVENTS void BeginEvent(const Char* name); diff --git a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.cpp index e204c3750..1a60dbbae 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.cpp @@ -11,11 +11,7 @@ #include "GPUAdapterVulkan.h" #include "CmdBufferVulkan.h" #include "Engine/Threading/Threading.h" -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER #include "Engine/Engine/Engine.h" -#endif - -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER void DescriptorSetLayoutInfoVulkan::CacheTypesUsageID() { @@ -23,7 +19,7 @@ void DescriptorSetLayoutInfoVulkan::CacheTypesUsageID() static uint32 uniqueID = 1; static Dictionary typesUsageHashMap; - const uint32 typesUsageHash = Crc::MemCrc32(LayoutTypes, sizeof(LayoutTypes)); + const uint32 typesUsageHash = Crc::MemCrc32(_layoutTypes, sizeof(_layoutTypes)); ScopeLock lock(locker); uint32 id; if (!typesUsageHashMap.TryGet(typesUsageHash, id)) @@ -34,19 +30,17 @@ void DescriptorSetLayoutInfoVulkan::CacheTypesUsageID() _typesUsageID = id; } -#endif - void DescriptorSetLayoutInfoVulkan::AddDescriptor(int32 descriptorSetIndex, const VkDescriptorSetLayoutBinding& descriptor) { // Increment type usage - LayoutTypes[descriptor.descriptorType]++; + _layoutTypes[descriptor.descriptorType]++; - if (descriptorSetIndex >= SetLayouts.Count()) + if (descriptorSetIndex >= _setLayouts.Count()) { - SetLayouts.Resize(descriptorSetIndex + 1); + _setLayouts.Resize(descriptorSetIndex + 1); } - SetLayout& descSetLayout = SetLayouts[descriptorSetIndex]; + SetLayout& descSetLayout = _setLayouts[descriptorSetIndex]; descSetLayout.LayoutBindings.Add(descriptor); // TODO: manual hash update method? @@ -92,51 +86,51 @@ void DescriptorSetLayoutVulkan::Compile() const VkPhysicalDeviceLimits& limits = _device->PhysicalDeviceLimits; // Check for maxDescriptorSetSamplers - ASSERT(LayoutTypes[VK_DESCRIPTOR_TYPE_SAMPLER] - + LayoutTypes[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_SAMPLER] + + _layoutTypes[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] < limits.maxDescriptorSetSamplers); // Check for maxDescriptorSetUniformBuffers - ASSERT(LayoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] - + LayoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER] + + _layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] < limits.maxDescriptorSetUniformBuffers); // Check for maxDescriptorSetUniformBuffersDynamic if (!_device->Adapter->IsAMD()) { - ASSERT(LayoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] < limits.maxDescriptorSetUniformBuffersDynamic); } // Check for maxDescriptorSetStorageBuffers - ASSERT(LayoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] - + LayoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER] + + _layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] < limits.maxDescriptorSetStorageBuffers); // Check for maxDescriptorSetStorageBuffersDynamic - if (LayoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] > limits.maxDescriptorSetUniformBuffersDynamic) + if (_layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC] > limits.maxDescriptorSetUniformBuffersDynamic) { // TODO: Downgrade to non-dynamic? } - ASSERT(LayoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC] < limits.maxDescriptorSetStorageBuffersDynamic); // Check for maxDescriptorSetSampledImages - ASSERT(LayoutTypes[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] - + LayoutTypes[VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] - + LayoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER] + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER] + + _layoutTypes[VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE] + + _layoutTypes[VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER] < limits.maxDescriptorSetSampledImages); // Check for maxDescriptorSetStorageImages - ASSERT(LayoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] - + LayoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER] + ASSERT(_layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_IMAGE] + + _layoutTypes[VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER] < limits.maxDescriptorSetStorageImages); - _handles.Resize(SetLayouts.Count()); + _handles.Resize(_setLayouts.Count()); - for (int32 i = 0; i < SetLayouts.Count(); i++) + for (int32 i = 0; i < _setLayouts.Count(); i++) { - auto& layout = SetLayouts[i]; + auto& layout = _setLayouts[i]; VkDescriptorSetLayoutCreateInfo layoutInfo; RenderToolsVulkan::ZeroStruct(layoutInfo, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO); @@ -146,7 +140,6 @@ void DescriptorSetLayoutVulkan::Compile() VALIDATE_VULKAN_RESULT(vkCreateDescriptorSetLayout(_device->Device, &layoutInfo, nullptr, &_handles[i])); } -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER if (_typesUsageID == ~0) { CacheTypesUsageID(); @@ -155,35 +148,27 @@ void DescriptorSetLayoutVulkan::Compile() RenderToolsVulkan::ZeroStruct(_allocateInfo, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO); _allocateInfo.descriptorSetCount = _handles.Count(); _allocateInfo.pSetLayouts = _handles.Get(); -#endif } -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER DescriptorPoolVulkan::DescriptorPoolVulkan(GPUDeviceVulkan* device, const DescriptorSetLayoutVulkan& layout) -#else -DescriptorPoolVulkan::DescriptorPoolVulkan(GPUDeviceVulkan* device) -#endif : _device(device) , _handle(VK_NULL_HANDLE) - , MaxDescriptorSets(0) - , NumAllocatedDescriptorSets(0) - , PeakAllocatedDescriptorSets(0) -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER + , DescriptorSetsMax(0) + , AllocatedDescriptorSetsCount(0) + , AllocatedDescriptorSetsCountMax(0) , Layout(layout) -#endif { - Array> types; + Array> types; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - // Max number of descriptor sets layout allocations + // The maximum amount of descriptor sets layout allocations to hold const uint32 MaxSetsAllocations = 256; // Descriptor sets number required to allocate the max number of descriptor sets layout. // When we're hashing pools with types usage ID the descriptor pool can be used for different layouts so the initial layout does not make much sense. - // In the latter case we'll be probably overallocating the descriptor types but given the relatively small number of max allocations this should not have + // In the latter case we'll be probably over-allocating the descriptor types but given the relatively small number of max allocations this should not have // a serious impact. - MaxDescriptorSets = MaxSetsAllocations * (VULKAN_HASH_POOLS_WITH_TYPES_USAGE_ID ? 1 : Layout.GetLayouts().Count()); - for (uint32 typeIndex = VK_DESCRIPTOR_TYPE_BEGIN_RANGE; typeIndex < VK_DESCRIPTOR_TYPE_END_RANGE; ++typeIndex) + DescriptorSetsMax = MaxSetsAllocations * (VULKAN_HASH_POOLS_WITH_TYPES_USAGE_ID ? 1 : Layout.GetLayouts().Count()); + for (uint32 typeIndex = VULKAN_DESCRIPTOR_TYPE_BEGIN; typeIndex <= VULKAN_DESCRIPTOR_TYPE_END; typeIndex++) { const VkDescriptorType descriptorType = (VkDescriptorType)typeIndex; const uint32 typesUsed = Layout.GetTypesUsed(descriptorType); @@ -195,55 +180,13 @@ DescriptorPoolVulkan::DescriptorPoolVulkan(GPUDeviceVulkan* device) type.descriptorCount = typesUsed * MaxSetsAllocations; } } -#else - MaxDescriptorSets = 16384; - - Platform::MemoryClear(MaxAllocatedTypes, sizeof(MaxAllocatedTypes)); - Platform::MemoryClear(NumAllocatedTypes, sizeof(NumAllocatedTypes)); - Platform::MemoryClear(PeakAllocatedTypes, sizeof(PeakAllocatedTypes)); - - VkDescriptorPoolSize type; - - type.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - type.descriptorCount = 2048; - types.Add(type); - - type.type = VK_DESCRIPTOR_TYPE_SAMPLER; - type.descriptorCount = 1024; - types.Add(type); - - type.type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - type.descriptorCount = 512; - types.Add(type); - - type.type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - type.descriptorCount = 512; - types.Add(type); - - type.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - type.descriptorCount = 512; - types.Add(type); - - type.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - type.descriptorCount = 512; - types.Add(type); - - type.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - type.descriptorCount = 2048; - types.Add(type); - - for (const VkDescriptorPoolSize& poolSize : types) - { - MaxAllocatedTypes[poolSize.type] = poolSize.descriptorCount; - } -#endif VkDescriptorPoolCreateInfo createInfo; RenderToolsVulkan::ZeroStruct(createInfo, VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO); createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; createInfo.poolSizeCount = types.Count(); createInfo.pPoolSizes = types.Get(); - createInfo.maxSets = MaxDescriptorSets; + createInfo.maxSets = DescriptorSetsMax; VALIDATE_VULKAN_RESULT(vkCreateDescriptorPool(_device->Device, &createInfo, nullptr, &_handle)); } @@ -258,45 +201,33 @@ DescriptorPoolVulkan::~DescriptorPoolVulkan() void DescriptorPoolVulkan::TrackAddUsage(const DescriptorSetLayoutVulkan& layout) { // Check and increment our current type usage - for (uint32 typeIndex = VK_DESCRIPTOR_TYPE_BEGIN_RANGE; typeIndex < VK_DESCRIPTOR_TYPE_END_RANGE; typeIndex++) + for (uint32 typeIndex = VULKAN_DESCRIPTOR_TYPE_BEGIN; typeIndex <= VULKAN_DESCRIPTOR_TYPE_END; typeIndex++) { -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER ASSERT(Layout.GetTypesUsed((VkDescriptorType)typeIndex) == layout.GetTypesUsed((VkDescriptorType)typeIndex)); -#else - NumAllocatedTypes[typeIndex] += (int32)layout.GetTypesUsed((VkDescriptorType)typeIndex); - PeakAllocatedTypes[typeIndex] = Math::Max(PeakAllocatedTypes[typeIndex], NumAllocatedTypes[typeIndex]); -#endif } - NumAllocatedDescriptorSets += layout.GetLayouts().Count(); - PeakAllocatedDescriptorSets = Math::Max(NumAllocatedDescriptorSets, PeakAllocatedDescriptorSets); + AllocatedDescriptorSetsCount += layout.GetLayouts().Count(); + AllocatedDescriptorSetsCountMax = Math::Max(AllocatedDescriptorSetsCount, AllocatedDescriptorSetsCountMax); } void DescriptorPoolVulkan::TrackRemoveUsage(const DescriptorSetLayoutVulkan& layout) { // Check and increment our current type usage - for (uint32 typeIndex = VK_DESCRIPTOR_TYPE_BEGIN_RANGE; typeIndex < VK_DESCRIPTOR_TYPE_END_RANGE; typeIndex++) + for (uint32 typeIndex = VULKAN_DESCRIPTOR_TYPE_BEGIN; typeIndex <= VULKAN_DESCRIPTOR_TYPE_END; typeIndex++) { -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER ASSERT(Layout.GetTypesUsed((VkDescriptorType)typeIndex) == layout.GetTypesUsed((VkDescriptorType)typeIndex)); -#else - NumAllocatedTypes[typeIndex] -= (int32)layout.GetTypesUsed((VkDescriptorType)typeIndex); - ASSERT(NumAllocatedTypes[typeIndex] >= 0); -#endif } - NumAllocatedDescriptorSets -= layout.GetLayouts().Count(); + AllocatedDescriptorSetsCount -= layout.GetLayouts().Count(); } -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - void DescriptorPoolVulkan::Reset() { if (_handle != VK_NULL_HANDLE) { VALIDATE_VULKAN_RESULT(vkResetDescriptorPool(_device->Device, _handle, 0)); } - NumAllocatedDescriptorSets = 0; + AllocatedDescriptorSetsCount = 0; } bool DescriptorPoolVulkan::AllocateDescriptorSets(const VkDescriptorSetAllocateInfo& descriptorSetAllocateInfo, VkDescriptorSet* result) @@ -370,10 +301,6 @@ void TypedDescriptorPoolSetVulkan::Reset() _poolListCurrent = _poolListHead; } -#endif - -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - DescriptorPoolSetContainerVulkan::DescriptorPoolSetContainerVulkan(GPUDeviceVulkan* device) : _device(device) , _lastFrameUsed(Engine::FrameCount) @@ -464,8 +391,6 @@ void DescriptorPoolsManagerVulkan::GC() } } -#endif - PipelineLayoutVulkan::PipelineLayoutVulkan(GPUDeviceVulkan* device, const DescriptorSetLayoutInfoVulkan& layout) : _device(device) , _handle(VK_NULL_HANDLE) @@ -491,84 +416,10 @@ PipelineLayoutVulkan::~PipelineLayoutVulkan() } } -#if !VULKAN_USE_DESCRIPTOR_POOL_MANAGER - -DescriptorSetsVulkan::DescriptorSetsVulkan(GPUDeviceVulkan* device, const DescriptorSetLayoutVulkan& layout, GPUContextVulkan* context) - : _device(device) - , _pool(nullptr) - , _layout(&layout) -{ - const auto& layoutHandles = layout.GetHandles(); - if (layoutHandles.HasItems()) - { - VkDescriptorSetAllocateInfo allocateInfo; - RenderToolsVulkan::ZeroStruct(allocateInfo, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO); - allocateInfo.descriptorSetCount = layoutHandles.Count(); - allocateInfo.pSetLayouts = layoutHandles.Get(); - - _sets.AddZeroed(layoutHandles.Count()); - - _pool = context->AllocateDescriptorSets(allocateInfo, layout, _sets.Get()); - _pool->TrackAddUsage(layout); - } -} - -DescriptorSetsVulkan::~DescriptorSetsVulkan() -{ -} - -DescriptorSetRingBufferVulkan::DescriptorSetRingBufferVulkan(GPUDeviceVulkan* device) - : _device(device) - , _currDescriptorSets(nullptr) -{ -} - -DescriptorSetsVulkan* DescriptorSetRingBufferVulkan::RequestDescriptorSets(GPUContextVulkan* context, CmdBufferVulkan* cmdBuffer, const PipelineLayoutVulkan* layout) -{ - DescriptorSetsEntry* foundEntry = nullptr; - for (DescriptorSetsEntry* descriptorSetsEntry : DescriptorSetsEntries) - { - if (descriptorSetsEntry->CmdBuffer == cmdBuffer) - { - foundEntry = descriptorSetsEntry; - } - } - - if (!foundEntry) - { - if (!layout->HasDescriptors()) - { - return nullptr; - } - - foundEntry = New(cmdBuffer); - DescriptorSetsEntries.Add(foundEntry); - } - - const uint64 cmdBufferFenceSignaledCounter = cmdBuffer->GetFenceSignaledCounter(); - for (int32 i = 0; i < foundEntry->Pairs.Count(); i++) - { - DescriptorSetsPair& entry = foundEntry->Pairs[i]; - if (entry.FenceCounter < cmdBufferFenceSignaledCounter) - { - entry.FenceCounter = cmdBufferFenceSignaledCounter; - return entry.DescriptorSets; - } - } - - DescriptorSetsPair newEntry; - newEntry.DescriptorSets = New(_device, layout->GetDescriptorSetLayout(), context); - newEntry.FenceCounter = cmdBufferFenceSignaledCounter; - foundEntry->Pairs.Add(newEntry); - return newEntry.DescriptorSets; -} - -#endif - uint32 DescriptorSetWriterVulkan::SetupDescriptorWrites(const SpirvShaderDescriptorInfo& info, VkWriteDescriptorSet* writeDescriptors, VkDescriptorImageInfo* imageInfo, VkDescriptorBufferInfo* bufferInfo, uint8* bindingToDynamicOffsetMap) { WriteDescriptors = writeDescriptors; - NumWrites = info.DescriptorTypesCount; + WritesCount = info.DescriptorTypesCount; ASSERT(info.DescriptorTypesCount <= 64 && TEXT("Out of bits for Dirty Mask! More than 64 resources in one descriptor set!")); BindingToDynamicOffsetMap = bindingToDynamicOffsetMap; diff --git a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h index cad7d87ee..78ea83eb2 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/DescriptorSetVulkan.h @@ -9,12 +9,13 @@ #include "IncludeVulkanHeaders.h" #include "Types.h" #include "Config.h" -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER #include "Engine/Platform/CriticalSection.h" -#endif #if GRAPHICS_API_VULKAN +#define VULKAN_DESCRIPTOR_TYPE_BEGIN VK_DESCRIPTOR_TYPE_SAMPLER +#define VULKAN_DESCRIPTOR_TYPE_END VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT + class GPUDeviceVulkan; class CmdBufferVulkan; class GPUContextVulkan; @@ -39,7 +40,7 @@ namespace DescriptorSet Domain = 4, // Graphics pipeline stages count - NumGfxStages = 5, + GraphicsStagesCount = 5, // Compute pipeline slot Compute = 0, @@ -110,48 +111,42 @@ public: protected: - uint32 LayoutTypes[VK_DESCRIPTOR_TYPE_RANGE_SIZE]; - Array SetLayouts; - + uint32 _layoutTypes[VULKAN_DESCRIPTOR_TYPE_END]; + Array _setLayouts; uint32 _hash = 0; - -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER uint32 _typesUsageID = ~0; void CacheTypesUsageID(); -#endif void AddDescriptor(int32 descriptorSetIndex, const VkDescriptorSetLayoutBinding& descriptor); public: DescriptorSetLayoutInfoVulkan() { - Platform::MemoryClear(LayoutTypes, sizeof(LayoutTypes)); + Platform::MemoryClear(_layoutTypes, sizeof(_layoutTypes)); } public: inline uint32 GetTypesUsed(VkDescriptorType type) const { - return LayoutTypes[type]; + return _layoutTypes[type]; } const Array& GetLayouts() const { - return SetLayouts; + return _setLayouts; } inline const uint32* GetLayoutTypes() const { - return LayoutTypes; + return _layoutTypes; } -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER inline uint32 GetTypesUsageID() const { return _typesUsageID; } -#endif public: @@ -159,40 +154,27 @@ public: void CopyFrom(const DescriptorSetLayoutInfoVulkan& info) { - Platform::MemoryCopy(LayoutTypes, info.LayoutTypes, sizeof(LayoutTypes)); + Platform::MemoryCopy(_layoutTypes, info._layoutTypes, sizeof(_layoutTypes)); _hash = info._hash; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER _typesUsageID = info._typesUsageID; -#endif - SetLayouts = info.SetLayouts; + _setLayouts = info._setLayouts; } inline bool operator ==(const DescriptorSetLayoutInfoVulkan& other) const { - if (other.SetLayouts.Count() != SetLayouts.Count()) - { + if (other._setLayouts.Count() != _setLayouts.Count()) return false; - } - -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER if (other._typesUsageID != _typesUsageID) - { return false; - } -#endif - for (int32 index = 0; index < other.SetLayouts.Count(); index++) + for (int32 index = 0; index < other._setLayouts.Count(); index++) { - const int32 numBindings = SetLayouts[index].LayoutBindings.Count(); - if (other.SetLayouts[index].LayoutBindings.Count() != numBindings) - { + const int32 bindingsCount = _setLayouts[index].LayoutBindings.Count(); + if (other._setLayouts[index].LayoutBindings.Count() != bindingsCount) return false; - } - if (numBindings != 0 && Platform::MemoryCompare(other.SetLayouts[index].LayoutBindings.Get(), SetLayouts[index].LayoutBindings.Get(), numBindings * sizeof(VkDescriptorSetLayoutBinding))) - { + if (bindingsCount != 0 && Platform::MemoryCompare(other._setLayouts[index].LayoutBindings.Get(), _setLayouts[index].LayoutBindings.Get(), bindingsCount * sizeof(VkDescriptorSetLayoutBinding))) return false; - } } return true; @@ -214,9 +196,7 @@ private: GPUDeviceVulkan* _device; DescriptorSetLayoutHandlesArray _handles; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER VkDescriptorSetAllocateInfo _allocateInfo; -#endif public: @@ -225,24 +205,22 @@ public: public: - void Compile(); - inline const DescriptorSetLayoutHandlesArray& GetHandles() const { return _handles; } -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER inline const VkDescriptorSetAllocateInfo& GetAllocateInfo() const { return _allocateInfo; } -#endif friend inline uint32 GetHash(const DescriptorSetLayoutVulkan& key) { return key._hash; } + + void Compile(); }; class DescriptorPoolVulkan @@ -252,25 +230,15 @@ private: GPUDeviceVulkan* _device; VkDescriptorPool _handle; - uint32 MaxDescriptorSets; - uint32 NumAllocatedDescriptorSets; - uint32 PeakAllocatedDescriptorSets; + uint32 DescriptorSetsMax; + uint32 AllocatedDescriptorSetsCount; + uint32 AllocatedDescriptorSetsCountMax; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER const DescriptorSetLayoutVulkan& Layout; -#else - int32 MaxAllocatedTypes[VK_DESCRIPTOR_TYPE_RANGE_SIZE]; - int32 NumAllocatedTypes[VK_DESCRIPTOR_TYPE_RANGE_SIZE]; - int32 PeakAllocatedTypes[VK_DESCRIPTOR_TYPE_RANGE_SIZE]; -#endif public: -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER DescriptorPoolVulkan(GPUDeviceVulkan* device, const DescriptorSetLayoutVulkan& layout); -#else - DescriptorPoolVulkan(GPUDeviceVulkan* device); -#endif ~DescriptorPoolVulkan(); @@ -283,43 +251,28 @@ public: inline bool IsEmpty() const { - return NumAllocatedDescriptorSets == 0; + return AllocatedDescriptorSetsCount == 0; } inline bool CanAllocate(const DescriptorSetLayoutVulkan& layout) const { -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - return MaxDescriptorSets > NumAllocatedDescriptorSets + layout.GetLayouts().Count(); -#else - for (uint32 typeIndex = VK_DESCRIPTOR_TYPE_BEGIN_RANGE; typeIndex < VK_DESCRIPTOR_TYPE_END_RANGE; typeIndex++) - { - if (NumAllocatedTypes[typeIndex] + (int32)layout.GetTypesUsed((VkDescriptorType)typeIndex) > MaxAllocatedTypes[typeIndex]) - { - return false; - } - } - return true; -#endif + return DescriptorSetsMax > AllocatedDescriptorSetsCount + layout.GetLayouts().Count(); + } + + inline uint32 GetAllocatedDescriptorSetsCount() const + { + return AllocatedDescriptorSetsCount; } void TrackAddUsage(const DescriptorSetLayoutVulkan& layout); void TrackRemoveUsage(const DescriptorSetLayoutVulkan& layout); -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER void Reset(); bool AllocateDescriptorSets(const VkDescriptorSetAllocateInfo& descriptorSetAllocateInfo, VkDescriptorSet* result); - - inline uint32 GetNumAllocatedDescriptorSets() const - { - return NumAllocatedDescriptorSets; - } -#endif }; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - class DescriptorPoolSetContainerVulkan; class TypedDescriptorPoolSetVulkan @@ -425,8 +378,6 @@ public: void GC(); }; -#endif - class PipelineLayoutVulkan { private: @@ -476,115 +427,6 @@ struct DescriptorSetWriteContainerVulkan } }; -#if !VULKAN_USE_DESCRIPTOR_POOL_MANAGER - -class DescriptorSetsVulkan -{ -public: - - typedef Array> DescriptorSetArray; - -private: - - GPUDeviceVulkan* _device; - DescriptorPoolVulkan* _pool; - const DescriptorSetLayoutVulkan* _layout; - DescriptorSetArray _sets; - -public: - - DescriptorSetsVulkan(GPUDeviceVulkan* device, const DescriptorSetLayoutVulkan& layout, GPUContextVulkan* context); - ~DescriptorSetsVulkan(); - -public: - - inline const DescriptorSetArray& GetHandles() const - { - return _sets; - } - - inline void Bind(VkCommandBuffer cmdBuffer, VkPipelineLayout pipelineLayout, VkPipelineBindPoint bindPoint, const Array& dynamicOffsets) const - { - vkCmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout, 0, _sets.Count(), _sets.Get(), dynamicOffsets.Count(), dynamicOffsets.Get()); - } -}; - -class DescriptorSetRingBufferVulkan -{ -private: - - GPUDeviceVulkan* _device; - DescriptorSetsVulkan* _currDescriptorSets; - - struct DescriptorSetsPair - { - uint64 FenceCounter; - DescriptorSetsVulkan* DescriptorSets; - - DescriptorSetsPair() - : FenceCounter(0) - , DescriptorSets(nullptr) - { - } - }; - - struct DescriptorSetsEntry - { - CmdBufferVulkan* CmdBuffer; - Array Pairs; - - DescriptorSetsEntry(CmdBufferVulkan* cmdBuffer) - : CmdBuffer(cmdBuffer) - { - } - - ~DescriptorSetsEntry() - { - for (auto& pair : Pairs) - { - Delete(pair.DescriptorSets); - } - } - }; - - Array DescriptorSetsEntries; - -public: - - DescriptorSetRingBufferVulkan(GPUDeviceVulkan* device); - - virtual ~DescriptorSetRingBufferVulkan() - { - } - -public: - - void Reset() - { - _currDescriptorSets = nullptr; - } - - void Release() - { - DescriptorSetsEntries.ClearDelete(); - } - - void Set(DescriptorSetsVulkan* newDescriptorSets) - { - _currDescriptorSets = newDescriptorSets; - } - - inline void Bind(VkCommandBuffer cmdBuffer, VkPipelineLayout pipelineLayout, VkPipelineBindPoint bindPoint, const Array& dynamicOffsets) - { - ASSERT(_currDescriptorSets); - _currDescriptorSets->Bind(cmdBuffer, pipelineLayout, bindPoint, dynamicOffsets); - } - - DescriptorSetsVulkan* RequestDescriptorSets(GPUContextVulkan* context, CmdBufferVulkan* cmdBuffer, const PipelineLayoutVulkan* layout); -}; - -#endif - class DescriptorSetWriterVulkan { public: @@ -592,7 +434,7 @@ public: VkWriteDescriptorSet* WriteDescriptors; uint8* BindingToDynamicOffsetMap; uint32* DynamicOffsets; - uint32 NumWrites; + uint32 WritesCount; public: @@ -600,7 +442,7 @@ public: : WriteDescriptors(nullptr) , BindingToDynamicOffsetMap(nullptr) , DynamicOffsets(nullptr) - , NumWrites(0) + , WritesCount(0) { } @@ -610,7 +452,7 @@ public: bool WriteUniformBuffer(uint32 descriptorIndex, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range) const { - ASSERT(descriptorIndex < NumWrites); + ASSERT(descriptorIndex < WritesCount); ASSERT(WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); VkDescriptorBufferInfo* bufferInfo = const_cast(WriteDescriptors[descriptorIndex].pBufferInfo); ASSERT(bufferInfo); @@ -622,7 +464,7 @@ public: bool WriteDynamicUniformBuffer(uint32 descriptorIndex, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, uint32 dynamicOffset) const { - ASSERT(descriptorIndex < NumWrites); + ASSERT(descriptorIndex < WritesCount); ASSERT(WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC); VkDescriptorBufferInfo* bufferInfo = const_cast(WriteDescriptors[descriptorIndex].pBufferInfo); ASSERT(bufferInfo); @@ -636,7 +478,7 @@ public: bool WriteSampler(uint32 descriptorIndex, VkSampler sampler) const { - ASSERT(descriptorIndex < NumWrites); + ASSERT(descriptorIndex < WritesCount); ASSERT(WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); VkDescriptorImageInfo* imageInfo = const_cast(WriteDescriptors[descriptorIndex].pImageInfo); ASSERT(imageInfo); @@ -646,7 +488,7 @@ public: bool WriteImage(uint32 descriptorIndex, VkImageView imageView, VkImageLayout layout) const { - ASSERT(descriptorIndex < NumWrites); + ASSERT(descriptorIndex < WritesCount); ASSERT(WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); VkDescriptorImageInfo* imageInfo = const_cast(WriteDescriptors[descriptorIndex].pImageInfo); ASSERT(imageInfo); @@ -657,7 +499,7 @@ public: bool WriteStorageImage(uint32 descriptorIndex, VkImageView imageView, VkImageLayout layout) const { - ASSERT(descriptorIndex < NumWrites); + ASSERT(descriptorIndex < WritesCount); ASSERT(WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); VkDescriptorImageInfo* imageInfo = const_cast(WriteDescriptors[descriptorIndex].pImageInfo); ASSERT(imageInfo); @@ -668,7 +510,7 @@ public: bool WriteStorageTexelBuffer(uint32 descriptorIndex, const VkBufferView* bufferView) const { - ASSERT(descriptorIndex < NumWrites); + ASSERT(descriptorIndex < WritesCount); ASSERT(WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER); WriteDescriptors[descriptorIndex].pTexelBufferView = bufferView; return true; @@ -676,7 +518,7 @@ public: bool WriteStorageBuffer(uint32 descriptorIndex, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range) const { - ASSERT(descriptorIndex < NumWrites); + ASSERT(descriptorIndex < WritesCount); ASSERT(WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC); VkDescriptorBufferInfo* bufferInfo = const_cast(WriteDescriptors[descriptorIndex].pBufferInfo); ASSERT(bufferInfo); @@ -688,14 +530,14 @@ public: bool WriteUniformTexelBuffer(uint32 descriptorIndex, const VkBufferView* view) const { - ASSERT(descriptorIndex < NumWrites); + ASSERT(descriptorIndex < WritesCount); ASSERT(WriteDescriptors[descriptorIndex].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER); return DescriptorSet::CopyAndReturnNotEqual(WriteDescriptors[descriptorIndex].pTexelBufferView, view); } void SetDescriptorSet(VkDescriptorSet descriptorSet) const { - for (uint32 i = 0; i < NumWrites; i++) + for (uint32 i = 0; i < WritesCount; i++) { WriteDescriptors[i].dstSet = descriptorSet; } diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp index de79ebf7d..881e575e7 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp @@ -102,15 +102,11 @@ GPUContextVulkan::GPUContextVulkan(GPUDeviceVulkan* device, QueueVulkan* queue) GPUContextVulkan::~GPUContextVulkan() { -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER for (int32 i = 0; i < _descriptorPools.Count(); i++) { _descriptorPools[i].ClearDelete(); } _descriptorPools.Clear(); -#else - _descriptorPools.ClearDelete(); -#endif Delete(_cmdBufferManager); } @@ -297,7 +293,6 @@ DescriptorPoolVulkan* GPUContextVulkan::AllocateDescriptorSets(const VkDescripto { VkResult result = VK_ERROR_OUT_OF_DEVICE_MEMORY; VkDescriptorSetAllocateInfo allocateInfo = descriptorSetAllocateInfo; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER DescriptorPoolVulkan* pool = nullptr; const uint32 hash = VULKAN_HASH_POOLS_WITH_TYPES_USAGE_ID ? layout.GetTypesUsageID() : GetHash(layout); @@ -317,15 +312,6 @@ DescriptorPoolVulkan* GPUContextVulkan::AllocateDescriptorSets(const VkDescripto { typedDescriptorPools = &_descriptorPools.Add(hash, DescriptorPoolArray())->Value; } -#else - DescriptorPoolVulkan* pool = _descriptorPools.HasItems() ? _descriptorPools.Last() : nullptr; - - if (pool && pool->CanAllocate(layout)) - { - allocateInfo.descriptorPool = pool->GetHandle(); - result = vkAllocateDescriptorSets(_device->Device, &allocateInfo, outSets); - } -#endif if (result < VK_SUCCESS) { @@ -336,13 +322,8 @@ DescriptorPoolVulkan* GPUContextVulkan::AllocateDescriptorSets(const VkDescripto else { // Spec says any negative value could be due to fragmentation, so create a new Pool. If it fails here then we really are out of memory! -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER pool = New(_device, layout); typedDescriptorPools->Add(pool); -#else - pool = New(_device); - _descriptorPools.Add(pool); -#endif allocateInfo.descriptorPool = pool->GetHandle(); VALIDATE_VULKAN_RESULT(vkAllocateDescriptorSets(_device->Device, &allocateInfo, outSets)); } @@ -540,23 +521,13 @@ void GPUContextVulkan::UpdateDescriptorSets(GPUPipelineStateVulkan* pipelineStat ASSERT(pipelineLayout); bool needsWrite = false; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER // No current descriptor pools set - acquire one and reset - bool newDescriptorPool = pipelineState->AcquirePoolSet(cmdBuffer); + const bool newDescriptorPool = pipelineState->AcquirePoolSet(cmdBuffer); needsWrite |= newDescriptorPool; -#else - const auto newDescriptorSets = pipelineState->DSRingBuffer.RequestDescriptorSets(this, cmdBuffer, pipelineLayout); - pipelineState->DSRingBuffer.Set(newDescriptorSets); - if (!newDescriptorSets) - { - return; - } - const auto& descriptorSetHandles = newDescriptorSets->GetHandles(); -#endif // Update descriptors for every used shader stage uint32 remainingHasDescriptorsPerStageMask = pipelineState->HasDescriptorsPerStageMask; - for (int32 stage = 0; stage < DescriptorSet::NumGfxStages && remainingHasDescriptorsPerStageMask; stage++) + for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount && remainingHasDescriptorsPerStageMask; stage++) { // Only process stages that exist in this pipeline and use descriptors if (remainingHasDescriptorsPerStageMask & 1) @@ -568,27 +539,19 @@ void GPUContextVulkan::UpdateDescriptorSets(GPUPipelineStateVulkan* pipelineStat } // Allocate sets based on what changed -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER //if (needsWrite) // TODO: write on change only? -#endif { -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER if (!pipelineState->AllocateDescriptorSets()) { return; } -#endif uint32 remainingStagesMask = pipelineState->HasDescriptorsPerStageMask; uint32 stage = 0; while (remainingStagesMask) { if (remainingStagesMask & 1) { -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER const VkDescriptorSet descriptorSet = pipelineState->DescriptorSetHandles[stage]; -#else - const VkDescriptorSet descriptorSet = descriptorSetHandles[stage]; -#endif pipelineState->DSWriter[stage].SetDescriptorSet(descriptorSet); } @@ -608,39 +571,21 @@ void GPUContextVulkan::UpdateDescriptorSets(ComputePipelineStateVulkan* pipeline bool needsWrite = false; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER // No current descriptor pools set - acquire one and reset - bool newDescriptorPool = pipelineState->AcquirePoolSet(cmdBuffer); + const bool newDescriptorPool = pipelineState->AcquirePoolSet(cmdBuffer); needsWrite |= newDescriptorPool; -#else - const auto newDescriptorSets = pipelineState->DSRingBuffer.RequestDescriptorSets(this, cmdBuffer, pipelineLayout); - pipelineState->DSRingBuffer.Set(newDescriptorSets); - if (!newDescriptorSets) - { - return; - } - const auto& descriptorSetHandles = newDescriptorSets->GetHandles(); -#endif // Update descriptors UpdateDescriptorSets(*pipelineState->DescriptorInfo, pipelineState->DSWriter, needsWrite); // Allocate sets based on what changed -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - //if (needsWrite) // TODO: write on change only? -#endif + //if (needsWrite) // TODO: write on change only?f { -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER if (!pipelineState->AllocateDescriptorSets()) { return; } -#endif -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER const VkDescriptorSet descriptorSet = pipelineState->DescriptorSetHandles[DescriptorSet::Compute]; -#else - const VkDescriptorSet descriptorSet = descriptorSetHandles[DescriptorSet::Compute]; -#endif pipelineState->DSWriter.SetDescriptorSet(descriptorSet); vkUpdateDescriptorSets(_device->Device, pipelineState->DSWriteContainer.DescriptorWrites.Count(), pipelineState->DSWriteContainer.DescriptorWrites.Get(), 0, nullptr); @@ -675,8 +620,6 @@ void GPUContextVulkan::OnDrawCall() if (_rtDirtyFlag && cmdBuffer->IsInsideRenderPass()) EndRenderPass(); - _currentState->Reset(); - if (pipelineState->HasDescriptorsPerStageMask) { UpdateDescriptorSets(pipelineState); diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h index 16649e91e..8fd884cf2 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h @@ -114,12 +114,8 @@ private: DescriptorOwnerResourceVulkan* _uaHandles[GPU_MAX_UA_BINDED]; DescriptorOwnerResourceVulkan** _handles[(int32)SpirvShaderResourceBindingType::MAX]; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER typedef Array DescriptorPoolArray; Dictionary _descriptorPools; -#else - Array _descriptorPools; -#endif public: diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index b489b56ca..2d0aeb512 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -1096,9 +1096,7 @@ GPUDeviceVulkan::GPUDeviceVulkan(ShaderProfile shaderProfile, GPUAdapterVulkan* , ValidationCache(VK_NULL_HANDLE) #endif , UniformBufferUploader(nullptr) -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER , DescriptorPoolsManager(nullptr) -#endif { } @@ -1871,9 +1869,7 @@ bool GPUDeviceVulkan::Init() // Prepare stuff FenceManager.Init(this); UniformBufferUploader = New(this); -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER DescriptorPoolsManager = New(this); -#endif MainContext = New(this, GraphicsQueue); // TODO: create and load PipelineCache #if VULKAN_SUPPORTS_VALIDATION_CACHE @@ -1895,9 +1891,7 @@ void GPUDeviceVulkan::DrawBegin() // Flush resources DeferredDeletionQueue.ReleaseResources(); StagingManager.ProcessPendingFree(); -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER DescriptorPoolsManager->GC(); -#endif } void GPUDeviceVulkan::Dispose() @@ -1925,9 +1919,7 @@ void GPUDeviceVulkan::Dispose() StagingManager.Dispose(); TimestampQueryPools.ClearDelete(); SAFE_DELETE_GPU_RESOURCE(UniformBufferUploader); -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER Delete(DescriptorPoolsManager); -#endif SAFE_DELETE(MainContext); SAFE_DELETE(GraphicsQueue); SAFE_DELETE(ComputeQueue); diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h index 905485f7d..8a1334450 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h @@ -26,9 +26,7 @@ class RenderPassVulkan; class FenceManagerVulkan; class GPUDeviceVulkan; class UniformBufferUploaderVulkan; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER class DescriptorPoolsManagerVulkan; -#endif class SemaphoreVulkan { @@ -637,9 +635,10 @@ public: /// UniformBufferUploaderVulkan* UniformBufferUploader; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER + /// + /// The descriptor pools manager. + /// DescriptorPoolsManagerVulkan* DescriptorPoolsManager; -#endif /// /// The physical device limits. diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp index e73778828..ee7305daf 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp @@ -47,11 +47,8 @@ ComputePipelineStateVulkan* GPUShaderProgramCSVulkan::GetOrCreateState() _pipelineState = New(_device, pipeline, layout); _pipelineState->DescriptorInfo = &DescriptorInfo; - -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER _pipelineState->DescriptorSetsLayout = &layout->GetDescriptorSetLayout(); _pipelineState->DescriptorSetHandles.AddZeroed(_pipelineState->DescriptorSetsLayout->GetHandles().Count()); -#endif uint32 totalNumDynamicOffsets = 0; @@ -89,13 +86,9 @@ ComputePipelineStateVulkan::ComputePipelineStateVulkan(GPUDeviceVulkan* device, ComputePipelineStateVulkan::~ComputePipelineStateVulkan() { DSWriteContainer.Release(); -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER CurrentTypedDescriptorPoolSet = nullptr; DescriptorSetsLayout = nullptr; DescriptorSetHandles.Resize(0); -#else - DSRingBuffer.Release(); -#endif DynamicOffsets.Resize(0); _device->DeferredDeletionQueue.EnqueueResource(DeferredDeletionQueueVulkan::Type::Pipeline, _handle); _layout = nullptr; @@ -105,9 +98,6 @@ GPUPipelineStateVulkan::GPUPipelineStateVulkan(GPUDeviceVulkan* device) : GPUResourceVulkan(device, StringView::Empty) , _pipelines(16) , _layout(nullptr) -#if !VULKAN_USE_DESCRIPTOR_POOL_MANAGER - , DSRingBuffer(device) -#endif { } @@ -132,10 +122,8 @@ PipelineLayoutVulkan* GPUPipelineStateVulkan::GetLayout() _layout = _device->GetOrCreateLayout(descriptorSetLayoutInfo); ASSERT(_layout); -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER DescriptorSetsLayout = &_layout->GetDescriptorSetLayout(); DescriptorSetHandles.AddZeroed(DescriptorSetsLayout->GetHandles().Count()); -#endif return _layout; } @@ -192,13 +180,9 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass) void GPUPipelineStateVulkan::OnReleaseGPU() { DSWriteContainer.Release(); -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER CurrentTypedDescriptorPoolSet = nullptr; DescriptorSetsLayout = nullptr; DescriptorSetHandles.Resize(0); -#else - DSRingBuffer.Release(); -#endif DynamicOffsets.Resize(0); for (auto i = _pipelines.Begin(); i.IsNotEnd(); ++i) { @@ -290,6 +274,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) _dynamicStates[_descDynamic.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT; _dynamicStates[_descDynamic.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR; _dynamicStates[_descDynamic.dynamicStateCount++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; + static_assert(ARRAY_COUNT(_dynamicStates) <= 3, "Invalid dynamic states array."); _desc.pDynamicState = &_descDynamic; // Multisample @@ -350,7 +335,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) _desc.pColorBlendState = &_descColorBlend; ASSERT(DSWriteContainer.DescriptorWrites.IsEmpty()); - for (int32 stage = 0; stage < DescriptorSet::NumGfxStages; stage++) + for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount; stage++) { const auto descriptor = DescriptorInfoPerStage[stage]; if (descriptor == nullptr || descriptor->DescriptorTypesCount == 0) @@ -369,9 +354,9 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) VkDescriptorImageInfo* currentImageInfo = DSWriteContainer.DescriptorImageInfo.Get(); VkDescriptorBufferInfo* currentBufferInfo = DSWriteContainer.DescriptorBufferInfo.Get(); uint8* currentBindingToDynamicOffsetMap = DSWriteContainer.BindingToDynamicOffsetMap.Get(); - uint32 dynamicOffsetsStart[DescriptorSet::NumGfxStages]; + uint32 dynamicOffsetsStart[DescriptorSet::GraphicsStagesCount]; uint32 totalNumDynamicOffsets = 0; - for (int32 stage = 0; stage < DescriptorSet::NumGfxStages; stage++) + for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount; stage++) { dynamicOffsetsStart[stage] = totalNumDynamicOffsets; @@ -389,7 +374,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc) } DynamicOffsets.AddZeroed(totalNumDynamicOffsets); - for (int32 stage = 0; stage < DescriptorSet::NumGfxStages; stage++) + for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount; stage++) { DSWriter[stage].DynamicOffsets = dynamicOffsetsStart[stage] + DynamicOffsets.Get(); } diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h index f1317898f..a51c105d2 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.h @@ -44,8 +44,6 @@ public: DescriptorSetWriteContainerVulkan DSWriteContainer; DescriptorSetWriterVulkan DSWriter; -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER - const DescriptorSetLayoutVulkan* DescriptorSetsLayout = nullptr; TypedDescriptorPoolSetVulkan* CurrentTypedDescriptorPoolSet = nullptr; Array DescriptorSetHandles; @@ -53,7 +51,7 @@ public: inline bool AcquirePoolSet(CmdBufferVulkan* cmdBuffer) { // Pipeline state has no current descriptor pools set or set owner is not current - acquire a new pool set - DescriptorPoolSetContainerVulkan* cmdBufferPoolSet = cmdBuffer->CurrentDescriptorPoolSetContainer; + DescriptorPoolSetContainerVulkan* cmdBufferPoolSet = cmdBuffer->GetDescriptorPoolSet(); if (CurrentTypedDescriptorPoolSet == nullptr || CurrentTypedDescriptorPoolSet->GetOwner() != cmdBufferPoolSet) { ASSERT(cmdBufferPoolSet); @@ -70,26 +68,12 @@ public: return CurrentTypedDescriptorPoolSet->AllocateDescriptorSets(*DescriptorSetsLayout, DescriptorSetHandles.Get()); } -#else - - DescriptorSetRingBufferVulkan DSRingBuffer; - -#endif - Array DynamicOffsets; public: - void Reset() - { -#if !VULKAN_USE_DESCRIPTOR_POOL_MANAGER - DSRingBuffer.Reset(); -#endif - } - void Bind(CmdBufferVulkan* cmdBuffer) { -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER vkCmdBindDescriptorSets( cmdBuffer->GetHandle(), VK_PIPELINE_BIND_POINT_COMPUTE, @@ -99,9 +83,6 @@ public: DescriptorSetHandles.Get(), DynamicOffsets.Count(), DynamicOffsets.Get()); -#else - DSRingBuffer.Bind(cmdBuffer->GetHandle(), GetLayout()->GetHandle(), VK_PIPELINE_BIND_POINT_COMPUTE, DynamicOffsets); -#endif } public: @@ -131,7 +112,7 @@ private: VkPipelineTessellationStateCreateInfo _descTessellation; VkPipelineViewportStateCreateInfo _descViewport; VkPipelineDynamicStateCreateInfo _descDynamic; - VkDynamicState _dynamicStates[VK_DYNAMIC_STATE_RANGE_SIZE]; + VkDynamicState _dynamicStates[3]; VkPipelineMultisampleStateCreateInfo _descMultisample; VkPipelineDepthStencilStateCreateInfo _descDepthStencil; VkPipelineRasterizationStateCreateInfo _descRasterization; @@ -162,17 +143,15 @@ public: /// /// The cached shader bindings per stage. /// - const ShaderBindings* ShaderBindingsPerStage[DescriptorSet::NumGfxStages]; + const ShaderBindings* ShaderBindingsPerStage[DescriptorSet::GraphicsStagesCount]; /// /// The cached shader descriptor infos per stage. /// - const SpirvShaderDescriptorInfo* DescriptorInfoPerStage[DescriptorSet::NumGfxStages]; + const SpirvShaderDescriptorInfo* DescriptorInfoPerStage[DescriptorSet::GraphicsStagesCount]; DescriptorSetWriteContainerVulkan DSWriteContainer; - DescriptorSetWriterVulkan DSWriter[DescriptorSet::NumGfxStages]; - -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER + DescriptorSetWriterVulkan DSWriter[DescriptorSet::GraphicsStagesCount]; const DescriptorSetLayoutVulkan* DescriptorSetsLayout = nullptr; TypedDescriptorPoolSetVulkan* CurrentTypedDescriptorPoolSet = nullptr; @@ -181,7 +160,7 @@ public: inline bool AcquirePoolSet(CmdBufferVulkan* cmdBuffer) { // Pipeline state has no current descriptor pools set or set owner is not current - acquire a new pool set - DescriptorPoolSetContainerVulkan* cmdBufferPoolSet = cmdBuffer->CurrentDescriptorPoolSetContainer; + DescriptorPoolSetContainerVulkan* cmdBufferPoolSet = cmdBuffer->GetDescriptorPoolSet(); if (CurrentTypedDescriptorPoolSet == nullptr || CurrentTypedDescriptorPoolSet->GetOwner() != cmdBufferPoolSet) { ASSERT(cmdBufferPoolSet); @@ -198,26 +177,12 @@ public: return CurrentTypedDescriptorPoolSet->AllocateDescriptorSets(*DescriptorSetsLayout, DescriptorSetHandles.Get()); } -#else - - DescriptorSetRingBufferVulkan DSRingBuffer; - -#endif - Array DynamicOffsets; public: - void Reset() - { -#if !VULKAN_USE_DESCRIPTOR_POOL_MANAGER - DSRingBuffer.Reset(); -#endif - } - void Bind(CmdBufferVulkan* cmdBuffer) { -#if VULKAN_USE_DESCRIPTOR_POOL_MANAGER vkCmdBindDescriptorSets( cmdBuffer->GetHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, @@ -227,9 +192,6 @@ public: DescriptorSetHandles.Get(), DynamicOffsets.Count(), DynamicOffsets.Get()); -#else - DSRingBuffer.Bind(cmdBuffer->GetHandle(), GetLayout()->GetHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, DynamicOffsets); -#endif } /// diff --git a/Source/Engine/GraphicsDevice/Vulkan/QueueVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/QueueVulkan.cpp index 1e021f4de..0fa456ed6 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/QueueVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/QueueVulkan.cpp @@ -36,23 +36,23 @@ void QueueVulkan::Submit(CmdBufferVulkan* cmdBuffer, uint32 numSignalSemaphores, submitInfo.pSignalSemaphores = signalSemaphores; Array waitSemaphores; - if (cmdBuffer->WaitSemaphores.HasItems()) + if (cmdBuffer->_waitSemaphores.HasItems()) { - waitSemaphores.EnsureCapacity((uint32)cmdBuffer->WaitSemaphores.Count()); - for (auto semaphore : cmdBuffer->WaitSemaphores) + waitSemaphores.EnsureCapacity((uint32)cmdBuffer->_waitSemaphores.Count()); + for (auto semaphore : cmdBuffer->_waitSemaphores) { waitSemaphores.Add(semaphore->GetHandle()); } - submitInfo.waitSemaphoreCount = (uint32)cmdBuffer->WaitSemaphores.Count(); + submitInfo.waitSemaphoreCount = (uint32)cmdBuffer->_waitSemaphores.Count(); submitInfo.pWaitSemaphores = waitSemaphores.Get(); - submitInfo.pWaitDstStageMask = cmdBuffer->WaitFlags.Get(); + submitInfo.pWaitDstStageMask = cmdBuffer->_waitFlags.Get(); } VALIDATE_VULKAN_RESULT(vkQueueSubmit(_queue, 1, &submitInfo, fence->GetHandle())); cmdBuffer->_state = CmdBufferVulkan::State::Submitted; cmdBuffer->MarkSemaphoresAsSubmitted(); - cmdBuffer->SubmittedFenceCounter = cmdBuffer->FenceSignaledCounter; + cmdBuffer->_submittedFenceCounter = cmdBuffer->_fenceSignaledCounter; #if 0 // Wait for the GPU to be idle on every submit (useful for tracking GPU hangs) diff --git a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp index f26cee5c6..8616260eb 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.cpp @@ -244,7 +244,9 @@ String RenderToolsVulkan::GetVkErrorString(VkResult result) VKERR(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT); VKERR(VK_ERROR_FRAGMENTATION_EXT); VKERR(VK_ERROR_NOT_PERMITTED_EXT); +#if VK_HEADER_VERSION < 140 VKERR(VK_RESULT_RANGE_SIZE); +#endif default: sb.AppendFormat(TEXT("0x{0:x}"), static_cast(result)); break; diff --git a/Source/Engine/Platform/Base/PlatformBase.cpp b/Source/Engine/Platform/Base/PlatformBase.cpp index cd91eb24d..2a0e23aea 100644 --- a/Source/Engine/Platform/Base/PlatformBase.cpp +++ b/Source/Engine/Platform/Base/PlatformBase.cpp @@ -443,6 +443,23 @@ void PlatformBase::TrackAllocation(uint64 size) #endif +void PlatformBase::GetEnvironmentVariables(Dictionary& result) +{ + // Not supported +} + +bool PlatformBase::GetEnvironmentVariable(const String& name, String& value) +{ + // Not supported + return true; +} + +bool PlatformBase::SetEnvironmentVariable(const String& name, const String& value) +{ + // Not supported + return true; +} + int32 PlatformBase::StartProcess(const StringView& filename, const StringView& args, const StringView& workingDir, bool hiddenWindow, bool waitForEnd) { // Not supported diff --git a/Source/Engine/Renderer/AtmospherePreCompute.cpp b/Source/Engine/Renderer/AtmospherePreCompute.cpp index 90eb0a0d1..833e3d0cf 100644 --- a/Source/Engine/Renderer/AtmospherePreCompute.cpp +++ b/Source/Engine/Renderer/AtmospherePreCompute.cpp @@ -61,11 +61,11 @@ protected: PACK_STRUCT(struct Data { - float FirstOrder; + float First; float AtmosphereR; int AtmosphereLayer; float Dummy0; - Vector4 DhdH; + Vector4 dhdh; }); namespace AtmospherePreComputeImpl @@ -367,17 +367,17 @@ void AtmospherePreComputeService::Dispose() release(); } -void GetLayerValue(int32 layer, float& atmosphereR, Vector4& DhdH) +void GetLayerValue(int32 layer, float& atmosphereR, Vector4& dhdh) { float r = layer / Math::Max(InscatterAltitudeSampleNum - 1.0f, 1.0f); r = r * r; r = Math::Sqrt(RadiusGround * RadiusGround + r * (RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround)) + (layer == 0 ? 0.01f : (layer == InscatterAltitudeSampleNum - 1 ? -0.001f : 0.0f)); - float dMin = RadiusAtmosphere - r; - float dMax = Math::Sqrt(r * r - RadiusGround * RadiusGround) + Math::Sqrt(RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround); - float dMinP = r - RadiusGround; - float dMaxP = Math::Sqrt(r * r - RadiusGround * RadiusGround); + const float dMin = RadiusAtmosphere - r; + const float dMax = Math::Sqrt(r * r - RadiusGround * RadiusGround) + Math::Sqrt(RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround); + const float dMinP = r - RadiusGround; + const float dMaxP = Math::Sqrt(r * r - RadiusGround * RadiusGround); atmosphereR = r; - DhdH = Vector4(dMin, dMax, dMinP, dMaxP); + dhdh = Vector4(dMin, dMax, dMinP, dMaxP); } void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context) @@ -390,8 +390,8 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context) } ASSERT(_isUpdatePending && _updateFrameNumber == 0); - auto shader = _shader->GetShader(); - auto cb = shader->GetCB(0); + const auto shader = _shader->GetShader(); + const auto cb = shader->GetCB(0); Data data; // Compute transmittance texture T (line 1 in algorithm 4.1) @@ -415,7 +415,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context) context->SetState(_psInscatter1_A); for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++) { - GetLayerValue(layer, data.AtmosphereR, data.DhdH); + GetLayerValue(layer, data.AtmosphereR, data.dhdh); data.AtmosphereLayer = layer; context->UpdateCB(cb, &data); context->BindCB(0, cb); @@ -426,7 +426,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context) context->SetState(_psInscatter1_B); for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++) { - GetLayerValue(layer, data.AtmosphereR, data.DhdH); + GetLayerValue(layer, data.AtmosphereR, data.dhdh); data.AtmosphereLayer = layer; context->UpdateCB(cb, &data); context->BindCB(0, cb); @@ -439,7 +439,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context) //// old way to render Inscatter1 to DeltaSR and DeltaSM at once but didn't work well :/ (no time to find out why) //for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++) //{ - // GetLayerValue(layer, data.AtmosphereR, data.DhdH); + // GetLayerValue(layer, data.AtmosphereR, data.dhdh); // data.AtmosphereLayer = layer; // cb->SetData(&data); // context->Bind(0, cb); @@ -472,7 +472,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context) context->BindSR(5, AtmosphereDeltaSM->ViewVolume()); for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++) { - GetLayerValue(layer, data.AtmosphereR, data.DhdH); + GetLayerValue(layer, data.AtmosphereR, data.dhdh); data.AtmosphereLayer = layer; context->UpdateCB(cb, &data); context->BindCB(0, cb); @@ -489,14 +489,14 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context) context->UnBindSR(6); context->SetViewportAndScissors((float)InscatterWidth, (float)InscatterHeight); context->SetState(_psInscatterS); - data.FirstOrder = order == 2 ? 1.0f : 0.0f; + data.First = order == 2 ? 1.0f : 0.0f; context->BindSR(0, AtmosphereTransmittance); context->BindSR(3, AtmosphereDeltaE); context->BindSR(4, AtmosphereDeltaSR->ViewVolume()); context->BindSR(5, AtmosphereDeltaSM->ViewVolume()); for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++) { - GetLayerValue(layer, data.AtmosphereR, data.DhdH); + GetLayerValue(layer, data.AtmosphereR, data.dhdh); data.AtmosphereLayer = layer; context->UpdateCB(cb, &data); context->BindCB(0, cb); @@ -523,7 +523,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context) context->BindSR(6, AtmosphereDeltaJ->ViewVolume()); for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++) { - GetLayerValue(layer, data.AtmosphereR, data.DhdH); + GetLayerValue(layer, data.AtmosphereR, data.dhdh); data.AtmosphereLayer = layer; context->UpdateCB(cb, &data); context->BindCB(0, cb); @@ -545,7 +545,7 @@ void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context) context->BindSR(4, AtmosphereDeltaSR->ViewVolume()); for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++) { - GetLayerValue(layer, data.AtmosphereR, data.DhdH); + GetLayerValue(layer, data.AtmosphereR, data.dhdh); data.AtmosphereLayer = layer; context->UpdateCB(cb, &data); context->BindCB(0, cb); diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp index 32fa1c788..f95c219c6 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp @@ -16,7 +16,6 @@ #include "Engine/ContentImporters/AssetsImportingManager.h" #include "Engine/ContentImporters/CreateMaterial.h" #include "ThirdParty/meshoptimizer/meshoptimizer.h" -#include void RemoveNamespace(String& name) { @@ -1193,27 +1192,15 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options opt int32 ModelTool::DetectLodIndex(const String& nodeName) { - // Try detect mesh lod index - int32 index; - String result; - std::match_results match; - String reversed = nodeName; - reversed.Reverse(); - - // Find 'LOD' case - const std::wregex regex2(TEXT("^(\\d+)DOL")); - if (regex_search(*reversed, match, regex2) && match.size() == 2) + const int32 index = nodeName.FindLast(TEXT("LOD")); + if (index != -1) { - // Get result - String num(match[1].str().c_str()); - num.Reverse(); - - // Parse value - if (!StringUtils::Parse(*num, num.Length(), &index)) + int32 num; + if (!StringUtils::Parse(nodeName.Get() + index + 3, &num)) { - if (index >= 0 && index < MODEL_MAX_LODS) + if (num >= 0 && num < MODEL_MAX_LODS) { - return index; + return num; } LOG(Warning, "Invalid mesh level of detail index at node \'{0}\'. Maximum supported amount of LODs is {1}.", nodeName, MODEL_MAX_LODS); diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp index 21aa6f1f5..618406f0b 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp @@ -635,7 +635,7 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path { sourceDxgiFormat = ToDxgiFormat(PixelFormatExtensions::ToNonsRGB(ToPixelFormat(sourceDxgiFormat))); ((DirectX::TexMetadata&)currentImage->GetMetadata()).format = sourceDxgiFormat; - for (int32 i = 0; i < currentImage->GetImageCount(); i++) + for (size_t i = 0; i < currentImage->GetImageCount(); i++) ((DirectX::Image*)currentImage->GetImages())[i].format = sourceDxgiFormat; } diff --git a/Source/Engine/UI/GUI/Tooltip.cs b/Source/Engine/UI/GUI/Tooltip.cs index 460fddb6f..d0f78227d 100644 --- a/Source/Engine/UI/GUI/Tooltip.cs +++ b/Source/Engine/UI/GUI/Tooltip.cs @@ -194,7 +194,7 @@ namespace FlaxEngine.GUI { // Auto hide if mouse leaves control area Vector2 mousePos = Input.MouseScreenPosition; - Vector2 location = _showTarget.ScreenToClient(mousePos / Platform.DpiScale); + Vector2 location = _showTarget.ScreenToClient(mousePos); if (!_showTarget.OnTestTooltipOverControl(ref location)) { // Mouse left or sth diff --git a/Source/Engine/UI/GUI/WindowRootControl.cs b/Source/Engine/UI/GUI/WindowRootControl.cs index 10e48baa5..eb4e1b85c 100644 --- a/Source/Engine/UI/GUI/WindowRootControl.cs +++ b/Source/Engine/UI/GUI/WindowRootControl.cs @@ -234,7 +234,7 @@ namespace FlaxEngine.GUI /// public override Vector2 ScreenToClient(Vector2 location) { - return _window.ScreenToClient(location); + return _window.ScreenToClient(location) / Platform.DpiScale; } /// diff --git a/Source/FlaxEngine.Gen.cs b/Source/FlaxEngine.Gen.cs index 662142e2f..045249d35 100644 --- a/Source/FlaxEngine.Gen.cs +++ b/Source/FlaxEngine.Gen.cs @@ -13,5 +13,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("095aaaed-cc57-6182-57cc-8261bcf06644")] -[assembly: AssemblyVersion("1.0.6213")] -[assembly: AssemblyFileVersion("1.0.6213")] +[assembly: AssemblyVersion("1.0.6214")] +[assembly: AssemblyFileVersion("1.0.6214")] diff --git a/Source/FlaxEngine.Gen.h b/Source/FlaxEngine.Gen.h index 283049ddb..de29aeebf 100644 --- a/Source/FlaxEngine.Gen.h +++ b/Source/FlaxEngine.Gen.h @@ -5,11 +5,11 @@ #include "Engine/Core/Compiler.h" #define FLAXENGINE_NAME "FlaxEngine" -#define FLAXENGINE_VERSION Version(1, 0, 6213) -#define FLAXENGINE_VERSION_TEXT "1.0.6213" +#define FLAXENGINE_VERSION Version(1, 0, 6214) +#define FLAXENGINE_VERSION_TEXT "1.0.6214" #define FLAXENGINE_VERSION_MAJOR 1 #define FLAXENGINE_VERSION_MINOR 0 -#define FLAXENGINE_VERSION_BUILD 6213 +#define FLAXENGINE_VERSION_BUILD 6214 #define FLAXENGINE_COMPANY "Flax" #define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2020 Wojciech Figat. All rights reserved." diff --git a/Source/Shaders/Atmosphere.hlsl b/Source/Shaders/Atmosphere.hlsl index 411586946..38029f81d 100644 --- a/Source/Shaders/Atmosphere.hlsl +++ b/Source/Shaders/Atmosphere.hlsl @@ -57,9 +57,8 @@ const static int InscatterNuNum = 8; const static int AtmosphericFogInscatterAltitudeSampleNum = 4; // Configuration -#define TRANSMITTANCE_NON_LINEAR 1 -#define INSCATTER_NON_LINEAR 1 -#define ATMOSPHERIC_TEXTURE_SAMPLE_FIX 1 +#define TRANSMITTANCE_NON_LINEAR 1 +#define INSCATTER_NON_LINEAR 1 #ifndef ATMOSPHERIC_NO_SUN_DISK #define ATMOSPHERIC_NO_SUN_DISK 0 @@ -90,15 +89,15 @@ Texture3D AtmosphereInscatterTexture : register(t2); float2 GetTransmittanceUV(float radius, float Mu) { - float U, V; + float u, v; #if TRANSMITTANCE_NON_LINEAR - V = sqrt((radius - RadiusGround) / (RadiusAtmosphere - RadiusGround)); - U = atan((Mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5; + v = sqrt((radius - RadiusGround) / (RadiusAtmosphere - RadiusGround)); + u = atan((Mu + 0.15) / (1.0 + 0.15) * tan(1.5)) / 1.5; #else - V = (radius - RadiusGround) / (RadiusAtmosphere - RadiusGround); - U = (Mu + 0.15) / (1.0 + 0.15); + v = (radius - RadiusGround) / (RadiusAtmosphere - RadiusGround); + u = (Mu + 0.15) / (1.0 + 0.15); #endif - return float2(U, V); + return float2(u, v); } void GetTransmittanceRMuS(float2 uv, out float radius, out float MuS) @@ -116,9 +115,9 @@ void GetTransmittanceRMuS(float2 uv, out float radius, out float MuS) float2 GetIrradianceUV(float radius, float MuS) { - float V = (radius - RadiusGround) / (RadiusAtmosphere - RadiusGround); - float U = (MuS + 0.2) / (1.0 + 0.2); - return float2(U, V); + float v = (radius - RadiusGround) / (RadiusAtmosphere - RadiusGround); + float u = (MuS + 0.2) / (1.0 + 0.2); + return float2(u, v); } void GetIrradianceRMuS(float2 uv, out float radius, out float MuS) @@ -137,9 +136,6 @@ float4 Texture4DSample(Texture3D tex, float radius, float Mu, float MuS, float N float4 TexOffset = RMu < 0.0 && Delta > 0.0 ? float4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(InscatterMuNum)) : float4(-1.0, H * H, H, 0.5 + 0.5 / float(InscatterMuNum)); float MuR = 0.5 / float(AtmosphericFogInscatterAltitudeSampleNum) + Rho / H * (1.0 - 1.0 / float(AtmosphericFogInscatterAltitudeSampleNum)); float MuMu = TexOffset.w + (RMu * TexOffset.x + sqrt(Delta + TexOffset.y)) / (Rho + TexOffset.z) * (0.5 - 1.0 / float(InscatterMuNum)); - // paper formula - //float MuMuS = 0.5 / float(InscatterMuSNum) + max((1.0 - exp(-3.0 * MuS - 0.6)) / (1.0 - exp(-3.6)), 0.0) * (1.0 - 1.0 / float(InscatterMuSNum)); - // better formula float MuMuS = 0.5 / float(InscatterMuSNum) + (atan(max(MuS, -0.1975) * tan(1.26 * 1.1)) / 1.1 + (1.0 - 0.26)) * 0.5 * (1.0 - 1.0 / float(InscatterMuSNum)); #else float MuR = 0.5 / float(AtmosphericFogInscatterAltitudeSampleNum) + Rho / H * (1.0 - 1.0 / float(AtmosphericFogInscatterAltitudeSampleNum)); @@ -154,35 +150,32 @@ float4 Texture4DSample(Texture3D tex, float radius, float Mu, float MuS, float N + tex.SampleLevel(SamplerLinearClamp, float3((MuNu + MuMuS + 1.0) / float(InscatterNuNum), MuMu, MuR), 0) * LerpValue; } -float Mod(float X, float Y) +float Mod(float x, float y) { - return X - Y * floor(X/Y); + return x - y * floor(x / y); } void GetMuMuSNu(float2 uv, float radius, float4 DhdH, out float Mu, out float MuS, out float Nu) { - float X = uv.x * float(InscatterMuSNum * InscatterNuNum) - 0.5; - float Y = uv.y * float(InscatterMuNum) - 0.5; + float x = uv.x * float(InscatterMuSNum * InscatterNuNum) - 0.5; + float y = uv.y * float(InscatterMuNum) - 0.5; #if INSCATTER_NON_LINEAR - if (Y < float(InscatterMuNum) * 0.5f) + if (y < float(InscatterMuNum) * 0.5f) { - float D = 1.0 - Y / (float(InscatterMuNum) * 0.5f - 1.0); - D = min(max(DhdH.z, D * DhdH.w), DhdH.w * 0.999); - Mu = (RadiusGround * RadiusGround - radius * radius - D * D) / (2.0 * radius * D); + float d = 1.0 - y / (float(InscatterMuNum) * 0.5f - 1.0); + d = min(max(DhdH.z, d * DhdH.w), DhdH.w * 0.999); + Mu = (RadiusGround * RadiusGround - radius * radius - d * d) / (2.0 * radius * d); Mu = min(Mu, -sqrt(1.0 - (RadiusGround / radius) * (RadiusGround / radius)) - 0.001); } else { - float D = (Y - float(InscatterMuNum) * 0.5f) / (float(InscatterMuNum) * 0.5f - 1.0); - D = min(max(DhdH.x, D * DhdH.y), DhdH.y * 0.999); - Mu = (RadiusAtmosphere * RadiusAtmosphere - radius * radius - D * D) / (2.0 * radius * D); + float d = (y - float(InscatterMuNum) * 0.5f) / (float(InscatterMuNum) * 0.5f - 1.0); + d = min(max(DhdH.x, d * DhdH.y), DhdH.y * 0.999); + Mu = (RadiusAtmosphere * RadiusAtmosphere - radius * radius - d * d) / (2.0 * radius * d); } - MuS = Mod(X, float(InscatterMuSNum)) / (float(InscatterMuSNum) - 1.0); - // paper formula - //MuS = -(0.6 + log(1.0 - MuS * (1.0 - exp(-3.6)))) / 3.0; - // better formula + MuS = Mod(x, float(InscatterMuSNum)) / (float(InscatterMuSNum) - 1.0); MuS = tan((2.0 * MuS - 1.0 + 0.26) * 1.1) / tan(1.26 * 1.1); - Nu = -1.0 + floor(X / float(InscatterMuSNum)) / (float(InscatterNuNum) - 1.0) * 2.0; + Nu = -1.0 + floor(x / float(InscatterMuSNum)) / (float(InscatterNuNum) - 1.0) * 2.0; #else Mu = -1.0 + 2.0 * Y / (float(InscatterMuNum) - 1.0); MuS = Mod(X, float(InscatterMuSNum)) / (float(InscatterMuSNum) - 1.0); @@ -191,10 +184,7 @@ void GetMuMuSNu(float2 uv, float radius, float4 DhdH, out float Mu, out float Mu #endif } -/** - * Nearest intersection of ray r,mu with ground or top atmosphere boundary - * mu=cos(ray zenith angle at ray origin) - */ +// Nearest intersection of ray r,mu with ground or top atmosphere boundary, mu=cos(ray zenith angle at ray origin) float Limit(float radius, float Mu) { float Dout = -radius * Mu + sqrt(radius * radius * (Mu * Mu - 1.0) + RadiusLimit * RadiusLimit); @@ -210,32 +200,20 @@ float Limit(float radius, float Mu) return Dout; } -/** - * Transmittance(=transparency) of atmosphere for infinite ray (r,mu) - * (mu=cos(view zenith angle)), intersections with ground ignored - */ +// Transmittance(=transparency) of atmosphere for infinite ray (r,mu) (mu=cos(view zenith angle)), intersections with ground ignored float3 Transmittance(float radius, float Mu) { float2 uv = GetTransmittanceUV(radius, Mu); return AtmosphereTransmittanceTexture.SampleLevel(SamplerLinearClamp, uv, 0).rgb; } -/** - * Transmittance(=transparency) of atmosphere for infinite ray (r,mu) - * (mu=cos(view zenith angle)), or zero if ray intersects ground - */ +// Transmittance(=transparency) of atmosphere for infinite ray (r,mu) (mu=cos(view zenith angle)), or zero if ray intersects ground float3 TransmittanceWithShadow(float radius, float Mu) { - // Need to correct calculation based on shadow feature, currently don't consider - //return Mu < -sqrt(1.0 - (RadiusGround / radius) * (RadiusGround / radius)) ? float3(0.f, 0.f, 0.f) : Transmittance(Radius, Mu); return Transmittance(radius, Mu); } -/** - * Transmittance(=transparency) of atmosphere between x and x0 - * Assume segment x,x0 not intersecting ground - * D = Distance between x and x0, mu=cos(zenith angle of [x,x0) ray at x) - */ +//Transmittance(=transparency) of atmosphere between x and x0. Assume segment x,x0 not intersecting ground. D = Distance between x and x0, mu=cos(zenith angle of [x,x0) ray at x) float3 TransmittanceWithDistance(float radius, float Mu, float D) { float3 result; @@ -252,42 +230,36 @@ float3 TransmittanceWithDistance(float radius, float Mu, float D) return result; } -/** - * Transmittance(=transparency) of atmosphere between x and x0 - * Assume segment x,x0 not intersecting ground - * radius=||x||, Mu=cos(zenith angle of [x,x0) ray at x), v=unit direction vector of [x,x0) ray - */ +// Transmittance(=transparency) of atmosphere between x and x0. Assume segment x,x0 not intersecting ground radius=||x||, Mu=cos(zenith angle of [x,x0) ray at x), v=unit direction vector of [x,x0) ray float3 TransmittanceWithDistance(float radius, float Mu, float3 V, float3 X0) { float3 result; - float R1 = length(X0); + float d1 = length(X0); float Mu1 = dot(X0, V) / radius; if (Mu > 0.0) - { - result = min(Transmittance(radius, Mu) / Transmittance(R1, Mu1), 1.0); - } + result = min(Transmittance(radius, Mu) / Transmittance(d1, Mu1), 1.0); else - { - result = min(Transmittance(R1, -Mu1) / Transmittance(radius, -Mu), 1.0); - } + result = min(Transmittance(d1, -Mu1) / Transmittance(radius, -Mu), 1.0); return result; } -/** - * Optical depth for ray (r,mu) of length d, using analytic formula - * (mu=cos(view zenith angle)), intersections with ground ignored - * H=height scale of exponential density function - */ +// Optical depth for ray (r,mu) of length d, using analytic formula (mu=cos(view zenith angle)), intersections with ground ignored H=height scale of exponential density function float OpticalDepthWithDistance(float H, float radius, float Mu, float D) { float particleDensity = 6.2831; // REK 04, Table 2 - float A = sqrt((0.5/H)*radius); - float2 A01 = A * float2(Mu, Mu + D / radius); + float a = sqrt(0.5 / H * radius); + float2 A01 = a * float2(Mu, Mu + D / radius); float2 A01Sign = sign(A01); float2 A01Squared = A01*A01; - float X = A01Sign.y > A01Sign.x ? exp(A01Squared.x) : 0.0; - float2 Y = A01Sign / (2.3193 * abs(A01) + sqrt(1.52 * A01Squared + 4.0)) * float2(1.0, exp(-D / H*(D / (2.0 * radius) + Mu))); - return sqrt((particleDensity * H)*radius) * exp((RadiusGround - radius) / H) * (X + dot(Y, float2(1.0, -1.0))); + float x = A01Sign.y > A01Sign.x ? exp(A01Squared.x) : 0.0; + float2 y = A01Sign / (2.3193 * abs(A01) + sqrt(1.52 * A01Squared + 4.0)) * float2(1.0, exp(-D / H*(D / (2.0 * radius) + Mu))); + return sqrt((particleDensity * H)*radius) * exp((RadiusGround - radius) / H) * (x + dot(y, float2(1.0, -1.0))); +} + +// Transmittance(=transparency) of atmosphere for ray (r,mu) of length d (mu=cos(view zenith angle)), intersections with ground ignored uses analytic formula instead of transmittance texture, REK 04, Atmospheric Transparency +float3 AnalyticTransmittance(float R, float Mu, float D) +{ + return exp(- BetaRayleighScattering * OpticalDepthWithDistance(HeightScaleRayleigh, R, Mu, D) - BetaMieExtinction * OpticalDepthWithDistance(HeightScaleMie, R, Mu, D)); } float3 Irradiance(Texture2D tex, float r, float muS) @@ -296,32 +268,23 @@ float3 Irradiance(Texture2D tex, float r, float muS) return tex.SampleLevel(SamplerLinearClamp, uv, 0).rgb; } -/** Rayleigh phase function */ +// Rayleigh phase function float PhaseFunctionR(float Mu) { return (3.0 / (16.0 * PI)) * (1.0 + Mu * Mu); } -/** Mie phase function */ +// Mie phase function float PhaseFunctionM(float Mu) { return 1.5 * 1.0 / (4.0 * PI) * (1.0 - MieG * MieG) * pow(1.0 + (MieG * MieG) - 2.0 * MieG * Mu, -3.0/2.0) * (1.0 + Mu * Mu) / (2.0 + MieG * MieG); } -/** Approximated single Mie scattering (cf. approximate Cm in paragraph "Angular precision") */ +// Approximated single Mie scattering (cf. approximate Cm in paragraph "Angular precision") float3 GetMie(float4 RayMie) { // RayMie.rgb=C*, RayMie.w=Cm,r return RayMie.rgb * RayMie.w / max(RayMie.r, 1e-4) * (BetaRayleighScattering.rrr / BetaRayleighScattering.rgb); } -/** Transmittance(=transparency) of atmosphere for ray (r,mu) of length d - * (mu=cos(view zenith angle)), intersections with ground ignored - * uses analytic formula instead of transmittance texture, REK 04, Atmospheric Transparency - */ -float3 AnalyticTransmittance(float R, float Mu, float D) -{ - return exp(- BetaRayleighScattering * OpticalDepthWithDistance(HeightScaleRayleigh, R, Mu, D) - BetaMieExtinction * OpticalDepthWithDistance(HeightScaleMie, R, Mu, D)); -} - #endif diff --git a/Source/Shaders/AtmosphereFog.hlsl b/Source/Shaders/AtmosphereFog.hlsl index 69bbaefc6..d4aab461a 100644 --- a/Source/Shaders/AtmosphereFog.hlsl +++ b/Source/Shaders/AtmosphereFog.hlsl @@ -24,39 +24,38 @@ static const float HeightOffset = 0.01f; -/** inscattered light along ray x+tv, when sun in direction s (=S[L]-T(x,x0)S[L]|x0) */ -float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S, float radius, float Mu, out float3 attenuation, bool isSceneGeometry) +// inscattered light along ray x+tv, when sun in direction s (=S[L]-T(x,x0)S[L]|x0) +float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S, float radius, float Mu, out float3 attenuation, bool isSceneGeometry) { - float3 result = float3(0.f, 0.f, 0.f); // X in space and ray looking in space, intialize - attenuation = float3(1.f, 1.f, 1.f); + float3 result = float3(0.0f, 0.0f, 0.0f); + attenuation = float3(1.0f, 1.0f, 1.0f); - float D = -radius * Mu - sqrt(radius * radius * (Mu * Mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere); - if (D > 0.0) - { - // if X in space and ray intersects atmosphere - // move X to nearest intersection of ray with top atmosphere boundary - X += D * V; - T -= D; - Mu = (radius * Mu + D) / RadiusAtmosphere; - radius = RadiusAtmosphere; - } - - float Epsilon = 0.005f;//maybe 0.004? - - if (radius < RadiusGround + HeightOffset + Epsilon) + float d = -radius * Mu - sqrt(radius * radius * (Mu * Mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere); + if (d > 0.0f) { - float Diff = (RadiusGround + HeightOffset + Epsilon) - radius; - X -= Diff * V; - T -= Diff; - radius = RadiusGround + HeightOffset + Epsilon; + // if X in space and ray intersects atmosphere + // move X to nearest intersection of ray with top atmosphere boundary + X += d * V; + T -= d; + Mu = (radius * Mu + d) / RadiusAtmosphere; + radius = RadiusAtmosphere; + } + + float epsilon = 0.005f; + + if (radius < RadiusGround + HeightOffset + epsilon) + { + float diff = (RadiusGround + HeightOffset + epsilon) - radius; + X -= diff * V; + T -= diff; + radius = RadiusGround + HeightOffset + epsilon; Mu = dot(X, V) / radius; } - if (radius <= RadiusAtmosphere && fogDepth > 0.f) - { + if (radius <= RadiusAtmosphere && fogDepth > 0.0f) + { float3 X0 = X + T * V; float R0 = length(X0); - // if ray intersects atmosphere float Nu = dot(V, S); float MuS = dot(X, S) / radius; @@ -64,11 +63,11 @@ float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S, if (isSceneGeometry) { - Mu = max(Mu, MuHorizon + Epsilon + 0.15); + Mu = max(Mu, MuHorizon + epsilon + 0.15f); } else - { - Mu = max(Mu, MuHorizon + Epsilon); + { + Mu = max(Mu, MuHorizon + epsilon); } float MuOriginal = Mu; @@ -81,9 +80,8 @@ float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S, { V.z = max(V.z, 0.15); V = normalize(V); - float3 X1 = X + T * V; - float R1 = length(X1); - Mu = dot(X1, V) / R1; + float3 x1 = X + T * V; + Mu = dot(x1, V) / length(x1); } } @@ -91,264 +89,186 @@ float3 GetInscatterColor(float fogDepth, float3 X, float T, float3 V, float3 S, float phaseM = PhaseFunctionM(Nu); float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu), 0.0); - if (T > 0.0) + if (T > 0.0) { -#if ATMOSPHERIC_TEXTURE_SAMPLE_FIX - // Avoids imprecision problems in transmittance computations based on textures attenuation = AnalyticTransmittance(radius, Mu, T); -#else - attenuation = TransmittanceWithDistance(radius, Mu, V, X0); -#endif - float Mu0 = dot(X0, V) / R0; float MuS0 = dot(X0, S) / R0; - if (isSceneGeometry) { R0 = max(R0, radius); } - + if (R0 > RadiusGround + HeightOffset) { if (blendRatio < 1.0) { inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu), 0.0); -#if ATMOSPHERIC_TEXTURE_SAMPLE_FIX - // avoids imprecision problems near horizon by interpolating between two points above and below horizon - if (!isSceneGeometry ) + if (!isSceneGeometry) { - if (abs(Mu - MuHorizon) < Epsilon) + if (abs(Mu - MuHorizon) < epsilon) { - float Alpha = ((Mu - MuHorizon) + Epsilon) * 0.5f / Epsilon; - - Mu = MuHorizon - Epsilon; + Mu = MuHorizon - epsilon; R0 = sqrt(radius * radius + T * T + 2.0 * radius * T * Mu); Mu0 = (radius * Mu + T) / R0; - Mu0 = max(MuHorizon + Epsilon, Mu0); - float4 Inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu); - float4 Inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu); - float4 InscatterA = max(Inscatter0 - attenuation.rgbr * Inscatter1, 0.0); + Mu0 = max(MuHorizon + epsilon, Mu0); + float4 inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu); + float4 inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu); + float4 inscatterA = max(inscatter0 - attenuation.rgbr * inscatter1, 0.0); - Mu = MuHorizon + Epsilon; + Mu = MuHorizon + epsilon; R0 = sqrt(radius * radius + T * T + 2.0 * radius * T * Mu); Mu0 = (radius * Mu + T) / R0; - Mu0 = max(MuHorizon + Epsilon, Mu0); - Inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu); - Inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu); - float4 InscatterB = max(Inscatter0 - attenuation.rgbr * Inscatter1, 0.0); + Mu0 = max(MuHorizon + epsilon, Mu0); + inscatter0 = Texture4DSample(AtmosphereInscatterTexture, radius, Mu, MuS, Nu); + inscatter1 = Texture4DSample(AtmosphereInscatterTexture, R0, Mu0, MuS0, Nu); + float4 inscatterB = max(inscatter1 - attenuation.rgbr * inscatter1, 0.0); - inscatter = lerp(InscatterA, InscatterB, Alpha); + float alpha = ((Mu - MuHorizon) + epsilon) * 0.5f / epsilon; + inscatter = lerp(inscatterA, inscatterB, alpha); } } else if (blendRatio > 0.0) { - inscatter = lerp(inscatter, (1.0 - attenuation.rgbr) * max(Texture4DSample(AtmosphereInscatterTexture, radius, MuOriginal, MuS, Nu), 0.0), blendRatio); + inscatter = lerp(inscatter, (1.0 - attenuation.rgbr) * max(Texture4DSample(AtmosphereInscatterTexture, radius, MuOriginal, MuS, Nu), 0.0), blendRatio); } -#endif } else { - inscatter = (1.0 - attenuation.rgbr) * inscatter; + inscatter = (1.0 - attenuation.rgbr) * inscatter; } } } -#if ATMOSPHERIC_TEXTURE_SAMPLE_FIX - // Avoids imprecision problems in Mie scattering when sun is below horizon - inscatter.w *= smoothstep(0.00, 0.02, MuS); -#endif - result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0); - } - + + inscatter.w *= smoothstep(0.00, 0.02, MuS); + result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0); + } + return result; } -// Ground radiance at end of ray x+tv, when sun in direction s attenuated bewteen ground and viewer (=R[L0]+R[L*]) +// Ground radiance at end of ray x+tv, when sun in direction s attenuated between ground and viewer (=R[L0]+R[L*]) float3 GetGroundColor(float4 sceneColor, float3 X, float T, float3 V, float3 S, float radius, float3 attenuation, bool isSceneGeometry) { - float3 result = float3(0.f, 0.f, 0.f); // ray looking at the sky (for intial value) - if (T > 0.0) - { + float3 result = float3(0.0f, 0.0f, 0.0f); + if (T > 0.0f) + { // if ray hits ground surface - // ground Reflectance at end of ray, X0 - float3 X0 = X + T * V; - float R0 = length(X0); - float3 N = X0 / R0; - N = X0 / R0; + // ground Reflectance at end of ray, X0 + float3 X0 = X + T * V; + float R0 = length(X0); + float3 N = X0 / R0; sceneColor.xyz = saturate(sceneColor.xyz + 0.05); - float4 reflectance = sceneColor * float4(0.2, 0.2, 0.2, 1.0); + float4 reflectance = sceneColor * float4(0.2, 0.2, 0.2, 1.0); - // direct sun light (radiance) reaching X0 - float MuS = dot(N, S); - float3 SunLight = isSceneGeometry ? float3(0.f, 0.f, 0.f) : TransmittanceWithShadow(R0, MuS); + // direct sun light (radiance) reaching X0 + float MuS = dot(N, S); + float3 sunLight = isSceneGeometry ? float3(0.f, 0.f, 0.f) : TransmittanceWithShadow(R0, MuS); - // precomputed sky light (irradiance) (=E[L*]) at X0 - float3 GroundSkyLight = Irradiance(AtmosphereIrradianceTexture, R0, MuS); + // precomputed sky light (irradiance) (=E[L*]) at X0 + float3 groundSkyLight = Irradiance(AtmosphereIrradianceTexture, R0, MuS); - // light reflected at X0 (=(R[L0]+R[L*])/T(X,X0)) - float3 groundColor = (reflectance.rgb * (max(MuS, 0.0) * SunLight + GroundSkyLight)) / PI; + // light reflected at X0 (=(R[L0]+R[L*])/T(X,X0)) + float3 groundColor = reflectance.rgb * ((max(MuS, 0.0) * sunLight + groundSkyLight) / PI); - // water specular color due to SunLight - if (!isSceneGeometry && reflectance.w > 0.0) + // water specular color due to SunLight + if (!isSceneGeometry && reflectance.w > 0.0) { - float3 H = normalize(S - V); - float fresnel = 0.02 + 0.98 * pow(1.0 - dot(-V, H), 5.0); - float waterBrdf = fresnel * pow(max(dot(H, N), 0.0), 150.0); - groundColor += reflectance.w * max(waterBrdf, 0.0) * SunLight; - } + float3 H = normalize(S - V); + float fresnel = 0.02 + 0.98 * pow(1.0 - dot(-V, H), 5.0); + float waterBrdf = fresnel * pow(max(dot(H, N), 0.0), 150.0); + groundColor += reflectance.w * max(waterBrdf, 0.0) * sunLight; + } result = attenuation * groundColor; //=R[L0]+R[L*] - } - return result; + } + return result; } // Direct sun light for ray x+tv, when sun in direction s (=L0) -float3 GetSunColor(AtmosphericFogData atmosphericFog, float3 X, float T, float3 V, float3 S, float radius, float Mu) +float3 GetSunColor(AtmosphericFogData atmosphericFog, float3 X, float T, float3 V, float3 S, float radius, float Mu) { if (T > 0.0) - { return float3(0.0f, 0.0f, 0.0f); - } - else - { - float3 transmittance = radius <= RadiusAtmosphere ? TransmittanceWithShadow(radius, Mu) : float3(1.0, 1.0, 1.0); // T(X,xo) - float sunIntensity = step(cos(PI * atmosphericFog.AtmosphericFogSunDiscScale / 180.0), dot(V, S)); // Lsun - return transmittance * sunIntensity; // Eq (9) - } + + float3 transmittance = radius <= RadiusAtmosphere ? TransmittanceWithShadow(radius, Mu) : float3(1.0, 1.0, 1.0); // T(X,xo) + float sunIntensity = step(cos(PI * atmosphericFog.AtmosphericFogSunDiscScale / 180.0), dot(V, S)); // Lsun + return transmittance * sunIntensity; // Eq (9) } float3 inscatter(inout float3 x, inout float t, float3 v, float3 s, out float r, out float mu, out float3 attenuation) { - float3 result = 0; - r = length(x); - mu = dot(x, v) / r; - float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere); + float3 result = 0; + r = length(x); + mu = dot(x, v) / r; + float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere); // if x in space and ray intersects atmosphere - if (d > 0.0) + if (d > 0.0) { - // move x to nearest intersection of ray with top atmosphere boundary - x += d * v; - t -= d; - mu = (r * mu + d) / RadiusAtmosphere; - r = RadiusAtmosphere; - } + // move x to nearest intersection of ray with top atmosphere boundary + x += d * v; + t -= d; + mu = (r * mu + d) / RadiusAtmosphere; + r = RadiusAtmosphere; + } + + float epsilon = 0.0045f; // if ray intersects atmosphere - if (r <= RadiusAtmosphere) + if (r <= RadiusAtmosphere) { - float nu = dot(v, s); - float muS = dot(x, s) / r; - float phaseR = PhaseFunctionR(nu); - float phaseM = PhaseFunctionM(nu); - float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu), 0.0); + float nu = dot(v, s); + float muS = dot(x, s) / r; + float phaseR = PhaseFunctionR(nu); + float phaseM = PhaseFunctionM(nu); + float4 inscatter = max(Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu), 0.0); - if (t > 0.0) + if (t > 0.0) { - float3 x0 = x + t * v; - float r0 = length(x0); - float rMu0 = dot(x0, v); - float mu0 = rMu0 / r0; - float muS0 = dot(x0, s) / r0; -#ifdef ATMOSPHERIC_TEXTURE_SAMPLE_FIX - // avoids imprecision problems in transmittance computations based on textures + float3 x0 = x + t * v; + float r0 = length(x0); + float rMu0 = dot(x0, v); + float mu0 = rMu0 / r0; + float muS0 = dot(x0, s) / r0; attenuation = AnalyticTransmittance(r, mu, t); -#else - attenuation = TransmittanceWithDistance(r, mu, v, x0); -#endif - if (r0 > RadiusGround + 0.01) + if (r0 > RadiusGround + 0.01) { - // computes S[L]-T(x,x0)S[L]|x0 - inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu), 0.0); -#ifdef ATMOSPHERIC_TEXTURE_SAMPLE_FIX - // avoids imprecision problems near horizon by interpolating between two points above and below horizon - const float EPS = 0.004; + // computes S[L]-T(x,x0)S[L]|x0 + inscatter = max(inscatter - attenuation.rgbr * Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu), 0.0); float muHoriz = -sqrt(1.0 - (RadiusGround / r) * (RadiusGround / r)); - if (abs(mu - muHoriz) < EPS) + if (abs(mu - muHoriz) < epsilon) { - float a = ((mu - muHoriz) + EPS) / (2.0 * EPS); - mu = muHoriz - EPS; + mu = muHoriz - epsilon; r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); mu0 = (r * mu + t) / r0; float4 inScatter0 = Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu); float4 inScatter1 = Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu); float4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); - mu = muHoriz + EPS; + mu = muHoriz + epsilon; r0 = sqrt(r * r + t * t + 2.0 * r * t * mu); mu0 = (r * mu + t) / r0; inScatter0 = Texture4DSample(AtmosphereInscatterTexture, r, mu, muS, nu); inScatter1 = Texture4DSample(AtmosphereInscatterTexture, r0, mu0, muS0, nu); float4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0); - - inscatter = lerp(inScatterA, inScatterB, a); + + float alpha = ((mu - muHoriz) + epsilon) / (2.0 * epsilon); + inscatter = lerp(inScatterA, inScatterB, alpha); } -#endif - } - } -#ifdef ATMOSPHERIC_TEXTURE_SAMPLE_FIX - // avoids imprecision problems in Mie scattering when sun is below horizon + } + } + inscatter.w *= smoothstep(0.00, 0.02, muS); -#endif - result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0); - } + result = max(inscatter.rgb * phaseR + GetMie(inscatter) * phaseM, 0.0); + } - return result; + return result; } -/* -//ground radiance at end of ray x+tv, when sun in direction s -//attenuated bewteen ground and viewer (=R[L0]+R[L*]) -float3 groundColor(float3 x, float t, float3 v, float3 s, float r, float mu, float3 attenuation) -{ - float3 result; - if (t > 0.0) - { - // if ray hits ground surface - // ground reflectance at end of ray, x0 - float3 x0 = x + t * v; - float r0 = length(x0); - float3 n = x0 / r0; - - float4 SceneColor = 0; - - SceneColor.xyz = saturate(SceneColor.xyz + 0.05); - - float4 Reflectance = SceneColor * float4(0.2, 0.2, 0.2, 1.0); - - if (r0 > RadiusGround + 0.01) - { - reflectance = float4(0.4, 0.4, 0.4, 0.0); - } - - // direct sun light (radiance) reaching x0 - float muS = dot(n, s); - float3 sunLight = transmittanceWithShadow(r0, muS); - - // precomputed sky light (irradiance) (=E[L*]) at x0 - float3 groundSkyLight = Irradiance(AtmosphereIrradianceTexture, r0, muS); - - // light reflected at x0 (=(R[L0]+R[L*])/T(x,x0)) - float3 groundColor = reflectance.rgb * (max(muS, 0.0) * sunLight + groundSkyLight) * ISun / M_PI; - - // water specular color due to sunLight - if (reflectance.w > 0.0) - { - float3 h = normalize(s - v); - float fresnel = 0.02 + 0.98 * pow(1.0 - dot(-v, h), 5.0); - float waterBrdf = fresnel * pow(max(dot(h, n), 0.0), 150.0); - groundColor += reflectance.w * max(waterBrdf, 0.0) * sunLight * ISun; - } - - result = attenuation * groundColor; //=R[L0]+R[L*] - } else { // ray looking at the sky - result = 0.0; - } -return result; -} -*/ static const float EPSILON_ATMOSPHERE = 0.002f; static const float EPSILON_INSCATTER = 0.004f; @@ -359,19 +279,19 @@ static const float EPSILON_INSCATTER = 0.004f; // output - maxPathLength: distance traversed within atmosphere // output - return value: intersection occurred true/false bool intersectAtmosphere(in float3 viewPosition, in float3 d, out float offset, out float maxPathLength) -{ +{ offset = 0.0f; maxPathLength = 0.0f; - + // vector from ray origin to center of the sphere float3 l = -viewPosition; - float l2 = dot(l,l); - float s = dot(l,d); - + float l2 = dot(l, l); + float s = dot(l, d); + // adjust top atmosphere boundary by small epsilon to prevent artifacts float r = Rt - EPSILON_ATMOSPHERE; - float r2 = r*r; - if(l2 <= r2) + float r2 = r * r; + if (l2 <= r2) { // ray origin inside sphere, hit is ensured float m2 = l2 - (s * s); @@ -379,11 +299,11 @@ bool intersectAtmosphere(in float3 viewPosition, in float3 d, out float offset, maxPathLength = s + q; return true; } - else if(s >= 0) + else if (s >= 0) { // ray starts outside in front of sphere, hit is possible float m2 = l2 - (s * s); - if(m2 <= r2) + if (m2 <= r2) { // ray hits atmosphere definitely float q = sqrt(r2 - m2); @@ -392,7 +312,7 @@ bool intersectAtmosphere(in float3 viewPosition, in float3 d, out float offset, return true; } } - + return false; } @@ -409,7 +329,7 @@ float3 GetInscatteredLight(AtmosphericFogData atmosphericFog, in float3 viewPosi if (intersectAtmosphere(viewPosition, viewDir, offset, maxPathLength)) { - return float3(offset / 10,0,0); + return float3(offset / 10, 0, 0); float pathLength = distance(viewPosition, surfacePos); //return pathLength.xxx; @@ -418,10 +338,11 @@ float3 GetInscatteredLight(AtmosphericFogData atmosphericFog, in float3 viewPosi if (pathLength > offset) { //return float3(1,0,0); - + // offsetting camera float3 startPos = viewPosition + offset * viewDir; - float startPosHeight = length(startPos); pathLength -= offset; + float startPosHeight = length(startPos); + pathLength -= offset; // starting position of path is now ensured to be inside atmosphere // was either originally there or has been moved to top boundary @@ -508,9 +429,9 @@ float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float viewPosition.y = (viewPosition.y - atmosphericFog.AtmosphericFogGroundOffset) * atmosphericFog.AtmosphericFogAltitudeScale; //viewPosition *= atmosphericFog.AtmosphericFogDistanceScale; //viewPosition *= scale; - + //viewPosition *= scale; - + //if(length(worldPosition) > Rg) // return float4(0, 0,0 ,0); @@ -531,27 +452,27 @@ float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float return float4(0, 0, 0, 1); #endif - + #if 1 - // TODO: scale viewPosition from cm to km !!!!!!! - + // TODO: scale viewPosition from cm to km + float scale = 0.0001f * atmosphericFog.AtmosphericFogDistanceScale; viewPosition.y = (viewPosition.y - atmosphericFog.AtmosphericFogGroundOffset) * atmosphericFog.AtmosphericFogAltitudeScale; //viewPosition *= atmosphericFog.AtmosphericFogDistanceScale; viewPosition *= scale; //viewPosition.xz *= 0.00001f; - + //viewPosition *= scale; viewPosition.y += RadiusGround + HeightOffset; - + //viewPosition.y -= atmosphericFog.AtmosphericFogGroundOffset; //worldPosition float Radius = length(viewPosition); float3 V = normalize(viewVector); float Mu = dot(viewPosition, V) / Radius; float T = -Radius * Mu - sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround); - + //-Radius * Mu > sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround) /* float3 g = viewPosition - float3(0.0, 0.0, RadiusGround + 10.0); diff --git a/Source/Shaders/AtmospherePreCompute.shader b/Source/Shaders/AtmospherePreCompute.shader index 76e2309d0..372b97306 100644 --- a/Source/Shaders/AtmospherePreCompute.shader +++ b/Source/Shaders/AtmospherePreCompute.shader @@ -3,6 +3,23 @@ #include "./Flax/Common.hlsl" #include "./Flax/Atmosphere.hlsl" +// Provides functions for atmospheric scattering and aerial perspective. +// +// Explanations: +// Scale Height = the altitude (height above ground) at which the average +// atmospheric density is found. +// Optical Depth = also called optical length, airmass, etc. +// +// References: +// [GPUGems2] GPU Gems 2: Accurate Atmospheric Scattering by Sean O'Neil. +// [GPUPro3] An Approximation to the Chapman Grazing-Incidence Function for +// Atmospheric Scattering, GPU Pro3, pp. 105. +// Papers bei Bruneton, Nishita, etc. +// +// This code contains embedded portions of free sample source code from +// http://www-evasion.imag.fr/Membres/Eric.Bruneton/PrecomputedAtmosphericScattering2.zip, Author: Eric Bruneton, +// 08/16/2011, Copyright (c) 2008 INRIA, All Rights Reserved, which have been altered from their original version. + const static int TransmittanceIntegralSamples = 500; const static int InscatterIntegralSamples = 50; const static int IrradianceIntegralSamples = 32; @@ -14,11 +31,11 @@ const static float InscatterDeltaPhi = PI / float(InscatterSphericalIntegralSamp const static float InscatterDeltaTheta = PI / float(InscatterSphericalIntegralSamples); META_CB_BEGIN(0, Data) -float FirstOrder; +float First; float AtmosphereR; int AtmosphereLayer; float Dummy0; -float4 DhdH; +float4 dhdh; META_CB_END Texture2D AtmosphereDeltaETexture : register(t3); @@ -26,117 +43,72 @@ Texture3D AtmosphereDeltaSRTexture : register(t4); Texture3D AtmosphereDeltaSMTexture : register(t5); Texture3D AtmosphereDeltaJTexture : register(t6); -struct AtmosphereGSOutput +float GetOpticalDepth(float h, float radius, float mu) { - float4 Position : SV_Position; - float2 TexCoord : TEXCOORD0; - //uint LayerIndex : SV_RenderTargetArrayIndex; -}; - -/* -META_VS(true, FEATURE_LEVEL_ES2) -META_VS_IN_ELEMENT(POSITION, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true) -Quad_VS2PS VS(float2 Position : POSITION0, float2 TexCoord : TEXCOORD0) -{ - Quad_VS2PS output; - - output.Position = float4(Position, 0, 1); - output.TexCoord = TexCoord; - - return output; -} - -META_GS(true, FEATURE_LEVEL_SM4) -[maxvertexcount(3)] -void GS_Atmosphere(triangle Quad_VS2PS input[3], inout TriangleStream output) -{ - AtmosphereGSOutput vertex; - - for(int i = 0; i < 3; i++) - { - vertex.Position = input[i].Position; - vertex.TexCoord = input[i].TexCoord; - vertex.LayerIndex = AtmosphereLayer; - - output.Append(vertex); - } -} -*/ -float OpticalDepth(float H, float radius, float Mu) -{ - float result = 0.0; - float Dx = Limit(radius, Mu) / float(TransmittanceIntegralSamples); - float Xi = 0.0; - float Yi = exp(-(radius - RadiusGround) / H); - + float result = 0.0f; + float ti = Limit(radius, mu) / float(TransmittanceIntegralSamples); + float xi = 0.0f; + float yi = exp(-(radius - RadiusGround) / h); LOOP for (int i = 1; i <= TransmittanceIntegralSamples; i++) { - float Xj = float(i) * Dx; - float Yj = exp(-(sqrt(radius * radius + Xj * Xj + 2.0 * Xj * radius * Mu) - RadiusGround) / H); - result += (Yi + Yj) / 2.0 * Dx; - Xi = Xj; - Yi = Yj; + float xj = float(i) * ti; + float yj = exp(-(sqrt(radius * radius + xj * xj + 2.0f * xj * radius * mu) - RadiusGround) / h); + result += (yi + yj) * 0.5f * ti; + xi = xj; + yi = yj; } - - return Mu < -sqrt(1.0 - (RadiusGround / radius) * (RadiusGround / radius)) ? 1e9 : result; + return mu < -sqrt(1.0f - (RadiusGround / radius) * (RadiusGround / radius)) ? 1e9 : result; } META_PS(true, FEATURE_LEVEL_ES2) float4 PS_Transmittance(Quad_VS2PS input) : SV_Target0 { - float radius, MuS; - GetTransmittanceRMuS(input.TexCoord, radius, MuS); - float3 depth = BetaRayleighScattering * OpticalDepth(HeightScaleRayleigh, radius, MuS) + BetaMieExtinction * OpticalDepth(HeightScaleMie, radius, MuS); - return float4(exp(-depth), 0.0f); // Eq (5) + float radius, mus; + GetTransmittanceRMuS(input.TexCoord, radius, mus); + float3 depth = BetaRayleighScattering * GetOpticalDepth(HeightScaleRayleigh, radius, mus) + BetaMieExtinction * GetOpticalDepth(HeightScaleMie, radius, mus); + return float4(exp(-depth), 0.0f); } META_PS(true, FEATURE_LEVEL_ES2) float4 PS_Irradiance1(Quad_VS2PS input) : SV_Target0 { - float radius, MuS; - GetIrradianceRMuS(input.TexCoord, radius, MuS); - return float4(Transmittance(radius, MuS) * max(MuS, 0.0), 0.0); + float radius, mus; + GetIrradianceRMuS(input.TexCoord, radius, mus); + return float4(Transmittance(radius, mus) * max(mus, 0.0f), 0.0f); } META_PS(true, FEATURE_LEVEL_ES2) float4 PS_IrradianceN(Quad_VS2PS input) : SV_Target0 { - float radius, MuS; - GetIrradianceRMuS(input.TexCoord, radius, MuS); - float3 S = float3(sqrt(max(1.0 - MuS * MuS, 0.0)), 0.0, MuS); - float3 result = float3(0.0f, 0.0f, 0.0f); - - // Integral over 2.PI around x with two nested loops over W directions (theta, phi) -- Eq (15) + float radius, mus; + GetIrradianceRMuS(input.TexCoord, radius, mus); + float3 s = float3(sqrt(max(1.0f - mus * mus, 0.0f)), 0.0f, mus); + float3 result = float3(0, 0, 0); for (int iPhi = 0; iPhi < 4 * IrradianceIntegralSamplesHalf; iPhi++) { - float phi = (float(iPhi) + 0.5) * IrradianceDeltaPhi; + float phi = (float(iPhi) + 0.5f) * IrradianceDeltaPhi; for (int iTheta = 0; iTheta < IrradianceIntegralSamplesHalf; iTheta++) { - float theta = (float(iTheta) + 0.5) * IrradianceDeltaTheta; - float Dw = IrradianceDeltaTheta * IrradianceDeltaPhi * sin(theta); - float3 W = float3(cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta)); - float Nu = dot(S, W); + float theta = (float(iTheta) + 0.5f) * IrradianceDeltaTheta; + float dw = IrradianceDeltaTheta * IrradianceDeltaPhi * sin(theta); + float3 w = float3(cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta)); + float nu = dot(s, w); - if (FirstOrder == 1.0) + if (First == 1.0f) { - // First iteration is special because Rayleigh and Mie were stored separately, - // without the phase functions factors; they must be reintroduced here - float Pr1 = PhaseFunctionR(Nu); - float Pm1 = PhaseFunctionM(Nu); - float3 Ray1 = Texture4DSample(AtmosphereDeltaSRTexture, radius, W.z, MuS, Nu).rgb; - float3 Mie1 = Texture4DSample(AtmosphereDeltaSMTexture, radius, W.z, MuS, Nu).rgb; - - result += (Ray1 * Pr1 + Mie1 * Pm1) * W.z * Dw; + float pr1 = PhaseFunctionR(nu); + float pm1 = PhaseFunctionM(nu); + float3 ray1 = Texture4DSample(AtmosphereDeltaSRTexture, radius, w.z, mus, nu).xyz; + float3 mie1 = Texture4DSample(AtmosphereDeltaSMTexture, radius, w.z, mus, nu).xyz; + result += (ray1 * pr1 + mie1 * pm1) * w.z * dw; } else { - result += Texture4DSample(AtmosphereDeltaSRTexture, radius, W.z, MuS, Nu).rgb * W.z * Dw; + result += Texture4DSample(AtmosphereDeltaSRTexture, radius, w.z, mus, nu).xyz * w.z * dw; } } } - return float4(result, 0.0); } @@ -146,219 +118,185 @@ float4 PS_CopyIrradiance1(Quad_VS2PS input) : SV_Target0 return AtmosphereDeltaETexture.Sample(SamplerLinearClamp, input.TexCoord); } -void Integrand(float radius, float Mu, float MuS, float Nu, float T, out float3 Ray, out float3 Mie) +void Integrand(float radius, float mu, float mus, float nu, float t, out float3 ray, out float3 mie) { - Ray = float3(0, 0, 0); - Mie = float3(0, 0, 0); - float Ri = sqrt(radius * radius + T * T + 2.0 * radius * Mu * T); - float MuSi = (Nu * T + MuS * radius) / Ri; - Ri = max(RadiusGround, Ri); - if (MuSi >= -sqrt(1.0 - RadiusGround * RadiusGround / (Ri * Ri)) ) + ray = float3(0, 0, 0); + mie = float3(0, 0, 0); + float ri = sqrt(radius * radius + t * t + 2.0f * radius * mu * t); + float musi = (nu * t + mus * radius) / ri; + ri = max(RadiusGround, ri); + if (musi >= -sqrt(1.0 - RadiusGround * RadiusGround / (ri * ri)) ) { - float3 Ti = TransmittanceWithDistance(radius, Mu, T) * Transmittance(Ri, MuSi); - Ray = exp(-(Ri - RadiusGround) / HeightScaleRayleigh) * Ti; - Mie = exp(-(Ri - RadiusGround) / HeightScaleMie) * Ti; + float3 ti = TransmittanceWithDistance(radius, mu, t) * Transmittance(ri, musi); + ray = exp(-(ri - RadiusGround) / HeightScaleRayleigh) * ti; + mie = exp(-(ri - RadiusGround) / HeightScaleMie) * ti; } } -// For Inscatter 1 -void Inscatter(float radius, float Mu, float MuS, float Nu, out float3 Ray, out float3 Mie) +void Inscatter(float radius, float mu, float mus, float nu, out float3 ray, out float3 mie) { - Ray = float3(0, 0, 0); - Mie = float3(0, 0, 0); - float Dx = Limit(radius, Mu) / float(InscatterIntegralSamples); - float Xi = 0.0; - float3 Rayi; - float3 Miei; - Integrand(radius, Mu, MuS, Nu, 0.0, Rayi, Miei); + ray = float3(0, 0, 0); + mie = float3(0, 0, 0); + float dx = Limit(radius, mu) / float(InscatterIntegralSamples); + float xi = 0.0f; + float3 rayi; + float3 miei; + Integrand(radius, mu, mus, nu, 0.0f, rayi, miei); for (int i = 1; i <= InscatterIntegralSamples; i++) { - float Xj = float(i) * Dx; + float xj = float(i) * dx; float3 Rayj; float3 Miej; - Integrand(radius, Mu, MuS, Nu, Xj, Rayj, Miej); - Ray += (Rayi + Rayj) / 2.0 * Dx; - Mie += (Miei + Miej) / 2.0 * Dx; - Xi = Xj; - Rayi = Rayj; - Miei = Miej; + Integrand(radius, mu, mus, nu, xj, Rayj, Miej); + ray += (rayi + Rayj) * 0.5f * dx; + mie += (miei + Miej) * 0.5f * dx; + xi = xj; + rayi = Rayj; + miei = Miej; } - Ray *= BetaRayleighScattering; - Mie *= BetaMieScattering; -} - -struct Inscatter1Output -{ - float4 DeltaSR : SV_Target0; - float4 DeltaSM : SV_Target1; -}; - -META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_Inscatter1_A(AtmosphereGSOutput input) : SV_Target -{ - float3 Ray; - float3 Mie; - float Mu, MuS, Nu; - GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu); - Inscatter(AtmosphereR, Mu, MuS, Nu, Ray, Mie); - - // Store separately Rayleigh and Mie contributions, WITHOUT the phase function factor (cf "Angular precision") - return float4(Ray, 1); + ray *= BetaRayleighScattering; + mie *= BetaMieScattering; } META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_CopyInscatter1(AtmosphereGSOutput input) : SV_Target0 +float4 PS_Inscatter1_A(Quad_VS2PS input) : SV_Target { - float3 UVW = float3(input.TexCoord, (float(AtmosphereLayer) + 0.5f) / float(AtmosphericFogInscatterAltitudeSampleNum)); - float4 Ray = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, UVW); - float4 Mie = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, UVW); - return float4(Ray.rgb, Mie.r); + float3 ray; + float3 mie; + float mu, mus, nu; + GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu); + Inscatter(AtmosphereR, mu, mus, nu, ray, mie); + return float4(ray, 1); } -// For Inscatter S -void Inscatter(float Radius, float Mu, float MuS, float Nu, out float3 RayMie) +META_PS(true, FEATURE_LEVEL_ES2) +float4 PS_CopyInscatter1(Quad_VS2PS input) : SV_Target0 { - Radius = clamp(Radius, RadiusGround, RadiusAtmosphere); - Mu = clamp(Mu, -1.0, 1.0); - MuS = clamp(MuS, -1.0, 1.0); - float Variation = sqrt(1.0 - Mu * Mu) * sqrt(1.0 - MuS * MuS); - Nu = clamp(Nu, MuS * Mu - Variation, MuS * Mu + Variation); + float3 uvw = float3(input.TexCoord, (float(AtmosphereLayer) + 0.5f) / float(AtmosphericFogInscatterAltitudeSampleNum)); + float4 ray = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, uvw); + float4 mie = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, uvw); + return float4(ray.xyz, mie.x); +} - float cThetaMin = -sqrt(1.0 - (RadiusGround / Radius) * (RadiusGround / Radius)); +void Inscatter(float radius, float mu, float mus, float nu, out float3 rayMie) +{ + radius = clamp(radius, RadiusGround, RadiusAtmosphere); + mu = clamp(mu, -1.0f, 1.0f); + mus = clamp(mus, -1.0f, 1.0f); + float variation = sqrt(1.0f - mu * mu) * sqrt(1.0f - mus * mus); + nu = clamp(nu, mus * mu - variation, mus * mu + variation); + float cThetaMin = -sqrt(1.0f - (RadiusGround / radius) * (RadiusGround / radius)); + float3 v = float3(sqrt(1.0f - mu * mu), 0.0f, mu); + float sx = v.x == 0.0f ? 0.0f : (nu - mus * mu) / v.x; + float3 s = float3(sx, sqrt(max(0.0f, 1.0f - sx * sx - mus * mus)), mus); + rayMie = float3(0, 0, 0); - float3 V = float3(sqrt(1.0 - Mu * Mu), 0.0, Mu); - float Sx = V.x == 0.0 ? 0.0 : (Nu - MuS * Mu) / V.x; - float3 S = float3(Sx, sqrt(max(0.0, 1.0 - Sx * Sx - MuS * MuS)), MuS); - - RayMie = float3(0.f, 0.f, 0.f); - - // Integral over 4.PI around x with two nested loops over W directions (theta, phi) - Eq (7) for (int iTheta = 0; iTheta < InscatterSphericalIntegralSamples; iTheta++) { - float theta = (float(iTheta) + 0.5) * InscatterDeltaTheta; + float theta = (float(iTheta) + 0.5f) * InscatterDeltaTheta; float cTheta = cos(theta); - - float GReflectance = 0.0; - float DGround = 0.0; - float3 GTransmittance = float3(0.f, 0.f, 0.f); + + float ground = 0.0f; + float3 transmittance = float3(0, 0, 0); + float reflectance = 0.0f; if (cTheta < cThetaMin) - { - // If ground visible in direction W, Compute transparency GTransmittance between x and ground - GReflectance = AverageGroundRelectance / PI; - DGround = -Radius * cTheta - sqrt(Radius * Radius * (cTheta * cTheta - 1.0) + RadiusGround * RadiusGround); - GTransmittance = TransmittanceWithDistance(RadiusGround, -(Radius * cTheta + DGround) / RadiusGround, DGround); + { + ground = -radius * cTheta - sqrt(radius * radius * (cTheta * cTheta - 1.0f) + RadiusGround * RadiusGround); + transmittance = TransmittanceWithDistance(RadiusGround, -(radius * cTheta + ground) / RadiusGround, ground); + reflectance = AverageGroundRelectance / PI; } for (int iPhi = 0; iPhi < 2 * InscatterSphericalIntegralSamples; iPhi++) { float phi = (float(iPhi) + 0.5) * InscatterDeltaPhi; - float Dw = InscatterDeltaTheta * InscatterDeltaPhi * sin(theta); - float3 W = float3(cos(phi) * sin(theta), sin(phi) * sin(theta), cTheta); + float dw = InscatterDeltaTheta * InscatterDeltaPhi * sin(theta); + float3 w = float3(cos(phi) * sin(theta), sin(phi) * sin(theta), cTheta); + float nu1 = dot(s, w); + float nu2 = dot(v, w); + float pr2 = PhaseFunctionR(nu2); + float pm2 = PhaseFunctionM(nu2); + float3 normal = (float3(0.0f, 0.0f, radius) + ground * w) / RadiusGround; + float3 irradiance = Irradiance(AtmosphereDeltaETexture, RadiusGround, dot(normal, s)); + float3 rayMie1 = reflectance * irradiance * transmittance; - float Nu1 = dot(S, W); - float Nu2 = dot(V, W); - float Pr2 = PhaseFunctionR(Nu2); - float Pm2 = PhaseFunctionM(Nu2); - - // Compute irradiance received at ground in direction W (if ground visible) =deltaE - float3 GNormal = (float3(0.0, 0.0, Radius) + DGround * W) / RadiusGround; - float3 GIrradiance = Irradiance(AtmosphereDeltaETexture, RadiusGround, dot(GNormal, S)); - - float3 RayMie1; // light arriving at x from direction W - - // First term = light reflected from the ground and attenuated before reaching x, =T.alpha/PI.deltaE - RayMie1 = GReflectance * GIrradiance * GTransmittance; - - // Second term = inscattered light, =deltaS - if (FirstOrder == 1.0) + if (First == 1.0f) { - // First iteration is special because Rayleigh and Mie were stored separately, - // without the phase functions factors; they must be reintroduced here - float Pr1 = PhaseFunctionR(Nu1); - float Pm1 = PhaseFunctionM(Nu1); - float3 Ray1 = Texture4DSample(AtmosphereDeltaSRTexture, Radius, W.z, MuS, Nu1).rgb; - float3 Mie1 = Texture4DSample(AtmosphereDeltaSMTexture, Radius, W.z, MuS, Nu1).rgb; - RayMie1 += Ray1 * Pr1 + Mie1 * Pm1; - } - else + float pr1 = PhaseFunctionR(nu1); + float pm1 = PhaseFunctionM(nu1); + float3 ray1 = Texture4DSample(AtmosphereDeltaSRTexture, radius, w.z, mus, nu1).xyz; + float3 mie1 = Texture4DSample(AtmosphereDeltaSMTexture, radius, w.z, mus, nu1).xyz; + rayMie1 += ray1 * pr1 + mie1 * pm1; + } + else { - RayMie1 += Texture4DSample(AtmosphereDeltaSRTexture, Radius, W.z, MuS, Nu1).rgb; + rayMie1 += Texture4DSample(AtmosphereDeltaSRTexture, radius, w.z, mus, nu1).xyz; } - // Light coming from direction W and scattered in direction V - // = light arriving at x from direction W (RayMie1) * SUM(scattering coefficient * phaseFunction) - Eq (7) - RayMie += RayMie1 * (BetaRayleighScattering * exp(-(Radius - RadiusGround) / HeightScaleRayleigh) * Pr2 + BetaMieScattering * exp(-(Radius - RadiusGround) / HeightScaleMie) * Pm2) * Dw; + rayMie += rayMie1 * (BetaRayleighScattering * exp(-(radius - RadiusGround) / HeightScaleRayleigh) * pr2 + BetaMieScattering * exp(-(radius - RadiusGround) / HeightScaleMie) * pm2) * dw; } } - - // output RayMie = J[T.alpha/PI.deltaE + deltaS] (line 7 in algorithm 4.1) } META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_InscatterS(AtmosphereGSOutput input) : SV_Target0 +float4 PS_InscatterS(Quad_VS2PS input) : SV_Target0 { - float3 RayMie; - float Mu, MuS, Nu; - GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu); - Inscatter(AtmosphereR, Mu, MuS, Nu, RayMie); - return float4(RayMie, 0); + float3 rayMie; + float mu, mus, nu; + GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu); + Inscatter(AtmosphereR, mu, mus, nu, rayMie); + return float4(rayMie, 0); } -float3 Integrand(float Radius, float Mu, float MuS, float Nu, float T) +float3 Integrand(float radius, float mu, float mus, float nu, float t) { - float Ri = sqrt(Radius * Radius + T * T + 2.0 * Radius * Mu * T); - float Mui = (Radius * Mu + T) / Ri; - float MuSi = (Nu * T + MuS * Radius) / Ri; - return Texture4DSample(AtmosphereDeltaJTexture, Ri, Mui, MuSi, Nu).rgb * TransmittanceWithDistance(Radius, Mu, T); + float ri = sqrt(radius * radius + t * t + 2.0 * radius * mu * t); + float mui = (radius * mu + t) / ri; + float musi = (nu * t + mus * radius) / ri; + return Texture4DSample(AtmosphereDeltaJTexture, ri, mui, musi, nu).xyz * TransmittanceWithDistance(radius, mu, t); } -// InscatterN -float3 Inscatter(float Radius, float Mu, float MuS, float Nu) +float3 Inscatter(float radius, float mu, float mus, float nu) { - float3 RayMie = float3(0.f, 0.f, 0.f); - float Dx = Limit(Radius, Mu) / float(InscatterIntegralSamples); - float Xi = 0.0; - float3 RayMiei = Integrand(Radius, Mu, MuS, Nu, 0.0); - + float3 rayMie = float3(0, 0, 0); + float dx = Limit(radius, mu) / float(InscatterIntegralSamples); + float xi = 0.0f; + float3 raymiei = Integrand(radius, mu, mus, nu, 0.0f); for (int i = 1; i <= InscatterIntegralSamples; i++) { - float Xj = float(i) * Dx; - float3 RayMiej = Integrand(Radius, Mu, MuS, Nu, Xj); - RayMie += (RayMiei + RayMiej) / 2.0 * Dx; - Xi = Xj; - RayMiei = RayMiej; + float xj = float(i) * dx; + float3 RayMiej = Integrand(radius, mu, mus, nu, xj); + rayMie += (raymiei + RayMiej) * 0.5f * dx; + xi = xj; + raymiei = RayMiej; } - - return RayMie; + return rayMie; } META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_InscatterN(AtmosphereGSOutput input) : SV_Target0 +float4 PS_InscatterN(Quad_VS2PS input) : SV_Target0 { - float Mu, MuS, Nu; - GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu); - return float4(Inscatter(AtmosphereR, Mu, MuS, Nu), 0); + float mu, mus, nu; + GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu); + return float4(Inscatter(AtmosphereR, mu, mus, nu), 0); } META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_CopyInscatterN(AtmosphereGSOutput input) : SV_Target0 +float4 PS_CopyInscatterN(Quad_VS2PS input) : SV_Target0 { - float Mu, MuS, Nu; - GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu); - float3 UVW = float3(input.TexCoord, (float(AtmosphereLayer) + 0.5f) / float(AtmosphericFogInscatterAltitudeSampleNum)); - float4 Ray = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, UVW) / PhaseFunctionR(Nu); - return float4(Ray.rgb, 0); + float mu, mus, nu; + GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu); + float3 uvw = float3(input.TexCoord, (float(AtmosphereLayer) + 0.5f) / float(AtmosphericFogInscatterAltitudeSampleNum)); + float4 ray = AtmosphereDeltaSRTexture.Sample(SamplerLinearClamp, uvw) / PhaseFunctionR(nu); + return float4(ray.xyz, 0); } META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_Inscatter1_B(AtmosphereGSOutput input) : SV_Target +float4 PS_Inscatter1_B(Quad_VS2PS input) : SV_Target { - float3 Ray; - float3 Mie; - float Mu, MuS, Nu; - GetMuMuSNu(input.TexCoord, AtmosphereR, DhdH, Mu, MuS, Nu); - Inscatter(AtmosphereR, Mu, MuS, Nu, Ray, Mie); - - // Store separately Rayleigh and Mie contributions, WITHOUT the phase function factor (cf "Angular precision") - return float4(Mie, 1); + float3 ray; + float3 mie; + float mu, mus, nu; + GetMuMuSNu(input.TexCoord, AtmosphereR, dhdh, mu, mus, nu); + Inscatter(AtmosphereR, mu, mus, nu, ray, mie); + return float4(mie, 1); } diff --git a/Source/Shaders/BRDF.hlsl b/Source/Shaders/BRDF.hlsl index 24f87b7a5..4b1f0389a 100644 --- a/Source/Shaders/BRDF.hlsl +++ b/Source/Shaders/BRDF.hlsl @@ -5,61 +5,11 @@ #include "./Flax/Math.hlsl" -// Bidirectional reflectance distribution functions -// Physically based shading model: -// Microfacet specular = D*G*F / (4*NoL*NoV) = D*Vis*F -// Vis = G / (4*NoL*NoV) - float3 Diffuse_Lambert(float3 diffuseColor) { return diffuseColor * (1 / PI); } -// [Burley 2012, "Physically-Based Shading at Disney"] -float3 Diffuse_Burley(float3 diffuseColor, float roughness, float NoV, float NoL, float VoH) -{ - float FD90 = 0.5 + 2 * VoH * VoH * roughness; - float FdV = 1 + (FD90 - 1) * Pow5(1 - NoV); - float FdL = 1 + (FD90 - 1) * Pow5(1 - NoL); - return diffuseColor * ((1 / PI) * FdV * FdL); -} - -// [Gotanda 2012, "Beyond a Simple Physically Based Blinn-Phong Model in Real-Time"] -float3 Diffuse_OrenNayar(float3 diffuseColor, float roughness, float NoV, float NoL, float VoH) -{ - float a = roughness * roughness; - float s = a; - float s2 = s * s; - float VoL = 2 * VoH * VoH - 1; - float Cosri = VoL - NoV * NoL; - float C1 = 1 - 0.5 * s2 / (s2 + 0.33); - float C2 = 0.45 * s2 / (s2 + 0.09) * Cosri * (Cosri >= 0 ? rcp( max(NoL, NoV)) : 1); - return diffuseColor / PI * (C1 + C2) * (1 + roughness * 0.5); -} - -float PhongShadingPow(float x, float y) -{ - return ClampedPow(x, y); -} - -// [Blinn 1977, "Models of light reflection for computer synthesized pictures"] -float D_Blinn(float roughness, float NoH) -{ - float a = roughness * roughness; - float a2 = a * a; - float n = 2 / a2 - 2; - return (n + 2) / (2 * PI) * PhongShadingPow(NoH, n); -} - -// [Beckmann 1963, "The scattering of electromagnetic waves from rough surfaces"] -float D_Beckmann(float roughness, float NoH) -{ - float a = roughness * roughness; - float a2 = a * a; - float NoH2 = NoH * NoH; - return exp((NoH2 - 1) / (a2 * NoH2)) / (PI * a2 * NoH2 * NoH2); -} - // GGX / Trowbridge-Reitz // [Walter et al. 2007, "Microfacet models for refraction through rough surfaces"] float D_GGX(float roughness, float NoH) @@ -70,36 +20,6 @@ float D_GGX(float roughness, float NoH) return a2 / (PI * d * d); } -// Anisotropic GGX -// [Burley 2012, "Physically-Based Shading at Disney"] -float D_GGXaniso(float roughnessX, float roughnessY, float NoH, float3 H, float3 X, float3 Y) -{ - float ax = roughnessX * roughnessX; - float ay = roughnessY * roughnessY; - float XoH = dot(X, H); - float YoH = dot(Y, H); - float d = XoH * XoH / (ax * ax) + YoH * YoH / (ay * ay) + NoH * NoH; - return 1 / (PI * ax * ay * d * d); -} - -float Vis_Implicit() -{ - return 0.25; -} - -// [Neumann et al. 1999, "Compact metallic reflectance models"] -float Vis_Neumann(float NoV, float NoL) -{ - return 1 / (4 * max(NoL, NoV)); -} - -// [Kelemen 2001, "A microfacet based coupled specular-matte brdf model with importance sampling"] -float Vis_Kelemen(float VoH) -{ - // constant to prevent NaN - return rcp(4 * VoH * VoH + 1e-5); -} - // Tuned to match behavior of Vis_Smith // [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"] float Vis_Schlick(float roughness, float NoV, float NoL) @@ -116,8 +36,8 @@ float Vis_Smith(float roughness, float NoV, float NoL) { float a = Square(roughness); float a2 = a * a; - float vis_SmithV = NoV + sqrt( NoV * (NoV - NoV * a2) + a2); - float vis_SmithL = NoL + sqrt( NoL * (NoL - NoL * a2) + a2); + float vis_SmithV = NoV + sqrt(NoV * (NoV - NoV * a2) + a2); + float vis_SmithL = NoL + sqrt(NoL * (NoL - NoL * a2) + a2); return rcp(vis_SmithV * vis_SmithL); } @@ -126,14 +46,9 @@ float Vis_Smith(float roughness, float NoV, float NoL) float Vis_SmithJointApprox(float roughness, float NoV, float NoL) { float a = Square(roughness); - float vis_SmithV = NoL * (NoV * (1 - a) + a); - float vis_SmithL = NoV * (NoL * (1 - a) + a); - return 0.5 * rcp(vis_SmithV + vis_SmithL); -} - -float3 F_None(float3 specularColor) -{ - return specularColor; + float visSmithV = NoL * (NoV * (1 - a) + a); + float visSmithL = NoV * (NoL * (1 - a) + a); + return 0.5 * rcp(visSmithV + visSmithL); } // [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"] @@ -143,86 +58,43 @@ float3 F_Schlick(float3 specularColor, float VoH) return saturate(50.0 * specularColor.g) * fc + (1 - fc) * specularColor; } -float3 F_Fresnel(float3 specularColor, float VoH) -{ - float3 specularColorSqrt = sqrt(clamp(float3(0, 0, 0), float3(0.99, 0.99, 0.99), specularColor)); - float3 n = (1 + specularColorSqrt ) / (1 - specularColorSqrt); - float3 g = sqrt(n * n + VoH * VoH - 1); - return 0.5 * Square((g - VoH) / (g + VoH)) * (1 + Square(((g + VoH) * VoH - 1) / ((g - VoH) * VoH + 1))); -} - -float D_InvBlinn(float roughness, float NoH) -{ - float m = roughness * roughness; - float m2 = m * m; - float A = 4; - float cos2h = NoH * NoH; - return rcp( PI * (1 + A * m2)) * (1 + A * exp(-cos2h / m2)); -} - -float D_InvBeckmann(float roughness, float NoH) -{ - float m = roughness * roughness; - float m2 = m * m; - float A = 4; - float cos2h = NoH * NoH; - float sin2h = 1 - cos2h; - float sin4h = sin2h * sin2h; - return rcp(PI * (1 + A * m2) * sin4h) * (sin4h + A * exp(-cos2h / (m2 * sin2h))); -} - -float D_InvGGX(float roughness, float NoH) -{ - float a = roughness * roughness; - float a2 = a * a; - float A = 4; - float d = (NoH - a2 * NoH) * NoH + a2; - return rcp(PI * (1 + A * a2)) * (1 + 4 * a2 * a2 / (d * d)); -} - -float Vis_Cloth(float NoV, float NoL) -{ - return rcp(4 * (NoL + NoV - NoL * NoV)); -} - #define REFLECTION_CAPTURE_NUM_MIPS 7 #define REFLECTION_CAPTURE_ROUGHEST_MIP 1 #define REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE 1.2 half ProbeMipFromRoughness(half roughness) { - half levelFrom1x1 = REFLECTION_CAPTURE_ROUGHEST_MIP - REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE * log2(roughness); - return REFLECTION_CAPTURE_NUM_MIPS - 1 - levelFrom1x1; + half mip1px = REFLECTION_CAPTURE_ROUGHEST_MIP - REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE * log2(roughness); + return REFLECTION_CAPTURE_NUM_MIPS - 1 - mip1px; } half SSRMipFromRoughness(half roughness) { - half levelFrom1x1 = 4 - REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE * log2(roughness); - return max(1, 10 - levelFrom1x1); + half mip1px = 4 - REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE * log2(roughness); + return max(1, 10 - mip1px); } float ComputeReflectionCaptureRoughnessFromMip(float mip) { - float levelFrom1x1 = REFLECTION_CAPTURE_NUM_MIPS - 1 - mip; - return exp2((REFLECTION_CAPTURE_ROUGHEST_MIP - levelFrom1x1) / REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE); + float mip1px = REFLECTION_CAPTURE_NUM_MIPS - 1 - mip; + return exp2((REFLECTION_CAPTURE_ROUGHEST_MIP - mip1px) / REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE); } // [Lazarov 2013, "Getting More Physical in Call of Duty: Black Ops II"] float3 EnvBRDFApprox(float3 specularColor, float roughness, float NoV) { // Approximate version, base for pre integrated version - const half4 c0 = {-1, -0.0275, -0.572, 0.022}; - const half4 c1 = {1, 0.0425, 1.04, -0.04}; + const half4 c0 = { -1, -0.0275, -0.572, 0.022 }; + const half4 c1 = { 1, 0.0425, 1.04, -0.04 }; half4 r = roughness * c0 + c1; half a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; half2 ab = half2(-1.04, 1.04) * a004 + r.zw; return specularColor * ab.x + saturate(50.0 * specularColor.g) * ab.y; } -// Pre integrated environment GF +// Importance sampled preintegrated G * F float3 EnvBRDF(Texture2D preIntegratedGF, float3 specularColor, float roughness, float NoV) { - // Importance sampled preintegrated G * F float2 ab = preIntegratedGF.SampleLevel(SamplerLinearClamp, float2(NoV, roughness), 0).rg; return specularColor * ab.x + saturate(50.0 * specularColor.g) * ab.y; } @@ -231,29 +103,7 @@ float3 EnvBRDF(Texture2D preIntegratedGF, float3 specularColor, float roughness, float RoughnessToSpecularPower(float roughness) { - // TODO: use path tracer as a reference and calculate valid params for this conversion - return pow(2, 13 * (1 - roughness)); - -#if 0 - - float coeff = pow(4, roughness); - coeff = max(coeff, 2.0f / (MAX_SPECULAR_POWER + 2.0f)); - return 2.0f / coeff - 2.0f; - - //const float Log2Of1OnLn2_Plus1 = 1.52876637294; // log2(1 / ln(2)) + 1 - //return exp2(10 * roughness + Log2Of1OnLn2_Plus1); - - //return pow(2, 2 * (1 - roughness)); - return pow(2, 13 * (1 - roughness)); - - //return exp2(10 * roughness + 1); -#endif } -/* -float SpecularPowerToRoughness(float specularPower) -{ - return pow(-0.25f, specularPower * 0.5f + 1.0f); -} -*/ + #endif diff --git a/Source/Shaders/Collisions.hlsl b/Source/Shaders/Collisions.hlsl index a372d649b..7d5a36a52 100644 --- a/Source/Shaders/Collisions.hlsl +++ b/Source/Shaders/Collisions.hlsl @@ -18,67 +18,4 @@ bool RayHitRect(float3 r, float3 rectCenter, float3 rectX, float3 rectY, float3 return inExtentX && inExtentY; } -// Computes where a ray hits a sphere (which is centered at the origin). -// \param[in] rayOrigin The start position of the ray. -// \param[in] rayDirection The normalized direction of the ray. -// \param[in] radius The radius of the sphere. -// \param[out] enter The ray parameter where the ray enters the sphere. -// 0 if the ray is already in the sphere. -// \param[out] exit The ray parameter where the ray exits the sphere. -// \return 0 or a positive value if the ray hits the sphere. A negative value -// if the ray does not touch the sphere. -float HitSphere(float3 rayOrigin, float3 rayDirection, float radius, out float enter, out float exit) -{ - // Solve the equation: ||rayOrigin + distance * rayDirection|| = r - // - // This is a straight-forward quadratic equation: - // ||O + d * D|| = r - // => (O + d * D)2 = r2 where V2 means V.V - // => d2 * D2 + 2 * d * (O.D) + O2 - r2 = 0 - // D2 is 1 because the rayDirection is normalized. - // => d = -O.D + sqrt((O.D)2 - O2 + r2) - - float OD = dot(rayOrigin, rayDirection); - float OO = dot(rayOrigin, rayOrigin); - float radicand = OD * OD - OO + radius * radius; - enter = max(0, -OD - sqrt(radicand)); - exit = -OD + sqrt(radicand); - - // If radicand is negative then we do not have a result - no hit. - return radicand; -} - -// Clips a ray to an AABB. Does not handle rays parallel to any of the planes. -// -// @param rayOrigin - The origin of the ray in world space. -// @param rayEnd - The end of the ray in world space. -// @param boxMin - The minimum extrema of the box. -// @param boxMax - The maximum extrema of the box. -// @return - Returns the closest intersection along the ray in x, and furthest in y. -// If the ray did not intersect the box, then the furthest intersection <= the closest intersection. -// The intersections will always be in the range [0,1], which corresponds to [rayOrigin, rayEnd] in worldspace. -// To find the world space position of either intersection, simply plug it back into the ray equation: -// WorldPos = RayOrigin + (rayEnd - RayOrigin) * Intersection; -float2 LineBoxIntersect(float3 rayOrigin, float3 rayEnd, float3 boxMin, float3 boxMax) -{ - float3 invRayDir = 1.0f / (rayEnd - rayOrigin); - - //find the ray intersection with each of the 3 planes defined by the minimum extrema. - float3 planeIntersections1 = (boxMin - rayOrigin) * invRayDir; - //find the ray intersection with each of the 3 planes defined by the maximum extrema. - float3 planeIntersections2 = (boxMax - rayOrigin) * invRayDir; - //get the closest of these intersections along the ray - float3 closestPlaneIntersections = min(planeIntersections1, planeIntersections2); - //get the furthest of these intersections along the ray - float3 furthestPlaneIntersections = max(planeIntersections1, planeIntersections2); - - float2 boxIntersections; - //find the furthest near intersection - boxIntersections.x = max(closestPlaneIntersections.x, max(closestPlaneIntersections.y, closestPlaneIntersections.z)); - //find the closest far intersection - boxIntersections.y = min(furthestPlaneIntersections.x, min(furthestPlaneIntersections.y, furthestPlaneIntersections.z)); - //clamp the intersections to be between rayOrigin and RayEnd on the ray - return saturate(boxIntersections); -} - #endif diff --git a/Source/Shaders/ColorGrading.shader b/Source/Shaders/ColorGrading.shader index d86004a31..51015658c 100644 --- a/Source/Shaders/ColorGrading.shader +++ b/Source/Shaders/ColorGrading.shader @@ -45,31 +45,20 @@ Texture2D LutTexture : register(t0); // [Krystek 1985, "An algorithm to calculate correlated colour temperature"] float2 PlanckianLocusChromaticity(float temp) { - float u = ( 0.860117757f + 1.54118254e-4f * temp + 1.28641212e-7f * temp*temp ) / ( 1.0f + 8.42420235e-4f * temp + 7.08145163e-7f * temp*temp ); - float v = ( 0.317398726f + 4.22806245e-5f * temp + 4.20481691e-8f * temp*temp ) / ( 1.0f - 2.89741816e-5f * temp + 1.61456053e-7f * temp*temp ); - - float x = 3*u / ( 2*u - 8*v + 4 ); - float y = 2*v / ( 2*u - 8*v + 4 ); - - return float2(x,y); + float u = (0.860117757f + 1.54118254e-4f * temp + 1.28641212e-7f * temp * temp) / (1.0f + 8.42420235e-4f * temp + 7.08145163e-7f * temp * temp); + float v = (0.317398726f + 4.22806245e-5f * temp + 4.20481691e-8f * temp * temp) / (1.0f - 2.89741816e-5f * temp + 1.61456053e-7f * temp * temp); + float x = 3 * u / (2 * u - 8 * v + 4); + float y = 2 * v / (2 * u - 8 * v + 4); + return float2(x, y); } -// Accurate for 4000K < temp < 25000K -// in: correlated color temperature -// out: CIE 1931 chromaticity -float2 D_IlluminantChromaticity(float temp) +// Calculates chromaticity from temperature +float2 IlluminantChromaticity(float temp) { - // Correct for revision of Plank's law - // This makes 6500 == D65 temp *= 1.4388 / 1.438; - - float x = temp <= 7000 ? - 0.244063 + ( 0.09911e3 + ( 2.9678e6 - 4.6070e9 / temp ) / temp ) / temp : - 0.237040 + ( 0.24748e3 + ( 1.9018e6 - 2.0064e9 / temp ) / temp ) / temp; - - float y = -3 * x*x + 2.87 * x - 0.275; - - return float2(x,y); + float x = temp <= 7000 ? 0.244063 + (0.09911e3 + (2.9678e6 - 4.6070e9 / temp) / temp) / temp : 0.237040 + (0.24748e3 + (1.9018e6 - 2.0064e9 / temp) / temp) / temp; + float y = -3 * x * x + 2.87 * x - 0.275; + return float2(x, y); } // Find closest color temperature to chromaticity @@ -77,38 +66,31 @@ float2 D_IlluminantChromaticity(float temp) float CorrelatedColortemperature(float x, float y) { float n = (x - 0.3320) / (0.1858 - y); - return -449 * n*n*n + 3525 * n*n - 6823.3 * n + 5520.33; + return -449 * n * n * n + 3525 * n * n - 6823.3 * n + 5520.33; } +// [McCamy 1992, "Correlated color temperature as an explicit function of chromaticity coordinates"] float2 PlanckianIsothermal(float temp, float tint) { - float u = ( 0.860117757f + 1.54118254e-4f * temp + 1.28641212e-7f * temp*temp ) / ( 1.0f + 8.42420235e-4f * temp + 7.08145163e-7f * temp*temp ); - float v = ( 0.317398726f + 4.22806245e-5f * temp + 4.20481691e-8f * temp*temp ) / ( 1.0f - 2.89741816e-5f * temp + 1.61456053e-7f * temp*temp ); - - float ud = ( -1.13758118e9f - 1.91615621e6f * temp - 1.53177f * temp*temp ) / Square( 1.41213984e6f + 1189.62f * temp + temp*temp ); - float vd = ( 1.97471536e9f - 705674.0f * temp - 308.607f * temp*temp ) / Square( 6.19363586e6f - 179.456f * temp + temp*temp ); - - float2 uvd = normalize( float2( u, v ) ); - - // Correlated color temperature is meaningful within +/- 0.05 + float u = (0.860117757f + 1.54118254e-4f * temp + 1.28641212e-7f * temp * temp) / (1.0f + 8.42420235e-4f * temp + 7.08145163e-7f * temp * temp); + float v = (0.317398726f + 4.22806245e-5f * temp + 4.20481691e-8f * temp * temp) / (1.0f - 2.89741816e-5f * temp + 1.61456053e-7f * temp * temp); + float ud = (-1.13758118e9f - 1.91615621e6f * temp - 1.53177f * temp * temp) / Square(1.41213984e6f + 1189.62f * temp + temp * temp); + float vd = (1.97471536e9f - 705674.0f * temp - 308.607f * temp * temp) / Square(6.19363586e6f - 179.456f * temp + temp * temp); + float2 uvd = normalize(float2(u, v)); u += -uvd.y * tint * 0.05; v += uvd.x * tint * 0.05; - - float x = 3*u / ( 2*u - 8*v + 4 ); - float y = 2*v / ( 2*u - 8*v + 4 ); - + float x = 3 * u / (2 * u - 8 * v + 4); + float y = 2 * v / (2 * u - 8 * v + 4); return float2(x,y); } float3 WhiteBalance(float3 linearColor) { - float2 srcWhiteDaylight = D_IlluminantChromaticity(WhiteTemp); + float2 srcWhiteDaylight = IlluminantChromaticity(WhiteTemp); float2 srcWhitePlankian = PlanckianLocusChromaticity(WhiteTemp); float2 srcWhite = WhiteTemp < 4000 ? srcWhitePlankian : srcWhiteDaylight; - float2 d65White = float2(0.31270, 0.32900); - - // Offset along isotherm + float2 d65White = float2(0.31270f, 0.32900f); float2 isothermal = PlanckianIsothermal(WhiteTemp, WhiteTint) - srcWhitePlankian; srcWhite += isothermal; @@ -121,8 +103,8 @@ float3 WhiteBalance(float3 linearColor) float3 ColorCorrect(float3 color, float luma, float4 saturation, float4 contrast, float4 gamma, float4 gain, float4 offset) { color = max(0, lerp(luma.xxx, color, saturation.xyz * saturation.w)); - color = pow(color * (1.0 / 0.18), contrast.xyz * contrast.w) * 0.18; - color = pow(color, 1.0 / (gamma.xyz * gamma.w)); + color = pow(color * (1.0f / 0.18f), contrast.xyz * contrast.w) * 0.18f; + color = pow(color, 1.0f / (gamma.xyz * gamma.w)); color = color * (gain.xyz * gain.w) + (offset.xyz + offset.w); return color; } @@ -130,35 +112,12 @@ float3 ColorCorrect(float3 color, float luma, float4 saturation, float4 contrast float3 ColorCorrectAll(float3 color) { float luma = dot(color, AP1_RGB2Y); - - // Shadow CC - float3 ccColorShadows = ColorCorrect(color, luma, - ColorSaturationShadows, - ColorContrastShadows, - ColorGammaShadows, - ColorGainShadows, - ColorOffsetShadows); + float3 ccColorShadows = ColorCorrect(color, luma, ColorSaturationShadows, ColorContrastShadows, ColorGammaShadows, ColorGainShadows, ColorOffsetShadows); float ccWeightShadows = 1 - smoothstep(0, ColorCorrectionShadowsMax, luma); - - // Highlight CC - float3 ccColorHighlights = ColorCorrect(color, luma, - ColorSaturationHighlights, - ColorContrastHighlights, - ColorGammaHighlights, - ColorGainHighlights, - ColorOffsetHighlights); + float3 ccColorHighlights = ColorCorrect(color, luma,ColorSaturationHighlights, ColorContrastHighlights, ColorGammaHighlights, ColorGainHighlights, ColorOffsetHighlights); float ccWeightHighlights = smoothstep(ColorCorrectionHighlightsMin, 1, luma); - - // Midtone CC - float3 ccColorMidtones = ColorCorrect(color, luma, - ColorSaturationMidtones, - ColorContrastMidtones, - ColorGammaMidtones, - ColorGainMidtones, - ColorOffsetMidtones); + float3 ccColorMidtones = ColorCorrect(color, luma, ColorSaturationMidtones, ColorContrastMidtones, ColorGammaMidtones, ColorGainMidtones, ColorOffsetMidtones); float ccWeightMidtones = 1 - ccWeightShadows - ccWeightHighlights; - - // Blend shadow, midtone and highlight CCs return ccColorShadows * ccWeightShadows + ccColorMidtones * ccWeightMidtones + ccColorHighlights * ccWeightHighlights; } @@ -207,8 +166,7 @@ float3 TonemapNeutral(float3 linearColor) float3 TonemapACES(float3 linearColor) { - // The code in this file was originally written by Stephen Hill (@self_shadow), who deserves all - // credit for coming up with this fit and implementing it. Buy him a beer next time you see him. :) + // The code was originally written by Stephen Hill (@self_shadow). // sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT static const float3x3 ACESInputMat = @@ -280,7 +238,6 @@ float4 CombineLUTs(float2 uv, uint layerIndex) // Move from encoded LUT color space to linear color //float3 linearColor = encodedColor.rgb; // Default - //float3 linearColor = LogCToLinear(encodedColor.rgb); // LogC float3 linearColor = LogToLinear(encodedColor.rgb) - LogToLinear(0); // Log // Apply white balance diff --git a/Source/Shaders/Common.hlsl b/Source/Shaders/Common.hlsl index 79692d1ac..9d0365e98 100644 --- a/Source/Shaders/Common.hlsl +++ b/Source/Shaders/Common.hlsl @@ -196,25 +196,6 @@ struct Quad_GS2PS uint LayerIndex : SV_RenderTargetArrayIndex; }; -float VisualizeTextureGrid(float2 texCoord, float2 textureSize, float gridSize) -{ - if (gridSize > 0) - { - float2 t = frac(texCoord * textureSize); - return (t.x < gridSize || t.x > 1 - gridSize) || (t.y < gridSize || t.y > 1 - gridSize); - } - else - { - int2 t = int2(texCoord * textureSize); - return (t.x % 2 == 0 && t.y % 2 == 0) || (t.x % 2 == 1 && t.y % 2 == 1); - } -} - -float BiasedNDotL(float NoL) -{ - return saturate(NoL * 1.08f - 0.08f); -} - float Luminance(float3 color) { return dot(color, float3(0.299f, 0.587f, 0.114f)); diff --git a/Source/Shaders/Fog.shader b/Source/Shaders/Fog.shader index 254fa9c69..7ddfe88ae 100644 --- a/Source/Shaders/Fog.shader +++ b/Source/Shaders/Fog.shader @@ -38,22 +38,14 @@ float4 CalculateCombinedFog(float3 worldPosition, float sceneDepth, float3 volum float excludeDistance = 0; #if VOLUMETRIC_FOG - - // Volumetric fog covers up to MaxDistance along ViewZ, exclude analytical fog from this range excludeDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0); - #endif float4 fog = GetExponentialHeightFog(ExponentialHeightFog, worldPosition, GBuffer.ViewPos, excludeDistance); #if VOLUMETRIC_FOG - - // Sample volumetric fog lookup table float4 volumetricFog = IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0); - - // Mix volumetric and analytical fog fog = float4(volumetricFog.rgb + fog.rgb * volumetricFog.a, volumetricFog.a * fog.a); - #endif return fog; diff --git a/Source/Shaders/GammaCorrectionCommon.hlsl b/Source/Shaders/GammaCorrectionCommon.hlsl index e08e902a1..7a1d1f6cf 100644 --- a/Source/Shaders/GammaCorrectionCommon.hlsl +++ b/Source/Shaders/GammaCorrectionCommon.hlsl @@ -9,73 +9,50 @@ // http://gpuopen.com/optimized-reversible-tonemapper-for-resolve/ float3 FastTonemap(float3 c) { - return c * rcp(max(max(c.r, c.g), c.b) + 1.0); + return c * rcp(max(max(c.r, c.g), c.b) + 1.0); } float4 FastTonemap(float4 c) { - return float4(FastTonemap(c.rgb), c.a); + return float4(FastTonemap(c.rgb), c.a); } float3 FastTonemap(float3 c, float w) { - return c * (w * rcp(max(max(c.r, c.g), c.b) + 1.0)); + return c * (w * rcp(max(max(c.r, c.g), c.b) + 1.0)); } float4 FastTonemap(float4 c, float w) { - return float4(FastTonemap(c.rgb, w), c.a); + return float4(FastTonemap(c.rgb, w), c.a); } float3 FastTonemapInvert(float3 c) { - return c * rcp(1.0 - max(max(c.r, c.g), c.b)); + return c * rcp(1.0 - max(max(c.r, c.g), c.b)); } float4 FastTonemapInvert(float4 c) { - return float4(FastTonemapInvert(c.rgb), c.a); + return float4(FastTonemapInvert(c.rgb), c.a); } -half3 LinearTo709Branchless(half3 linearColor) -{ - linearColor = max(6.10352e-5, linearColor); - return min(linearColor * 4.5, pow(max(linearColor, 0.018), 0.45) * 1.099 - 0.099); -} - -half3 LinearToSrgbBranchless(half3 linearColor) -{ - linearColor = max(6.10352e-5, linearColor); - return min(linearColor * 12.92, pow(max(linearColor, 0.00313067), 1.0/2.4) * 1.055 - 0.055); -} - -half LinearToSrgbBranchingChannel(half linearColor) +half LinearToSrgbChannel(half linearColor) { if (linearColor < 0.00313067) return linearColor * 12.92; - return pow(linearColor, (1.0/2.4)) * 1.055 - 0.055; + return pow(linearColor, (1.0 / 2.4)) * 1.055 - 0.055; } -half3 LinearToSrgbBranching(half3 linearColor) +half3 LinearToSrgb(half3 linearColor) { return half3( - LinearToSrgbBranchingChannel(linearColor.r), - LinearToSrgbBranchingChannel(linearColor.g), - LinearToSrgbBranchingChannel(linearColor.b)); + LinearToSrgbChannel(linearColor.r), + LinearToSrgbChannel(linearColor.g), + LinearToSrgbChannel(linearColor.b)); } -half3 LinearToSrgb(half3 linearColor) -{ -#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 - // Branching is faster than branchless on PC - return LinearToSrgbBranching(linearColor); -#else - // Use branchless on mobile - return LinearToSrgbBranchless(linearColor); -#endif -} - -half3 sRGBToLinear(half3 color) +half3 sRGBToLinear(half3 color) { color = max(6.10352e-5, color); return color > 0.04045 ? pow(color * (1.0 / 1.055) + 0.0521327, 2.4) : color * (1.0 / 12.92); @@ -103,7 +80,7 @@ float3 LinearToLog(float3 linearColor) const float exposureGrey = 444; // Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered. - float3 logColor = log2(linearColor) / linearRange - log2(linearGrey) / linearRange + exposureGrey / 1023.0; // scalar: 3log2 3mad + float3 logColor = log2(linearColor) / linearRange - log2(linearGrey) / linearRange + exposureGrey / 1023.0; // scalar: 3log2 3mad //float3 logColor = (log2(linearColor) - log2(linearGrey)) / linearRange + exposureGrey / 1023.0; //float3 logColor = log2(linearColor / linearGrey) / linearRange + exposureGrey / 1023.0; //float3 logColor = (0.432699 * log10(0.5 * linearColor + 0.037584) + 0.616596) + 0.03; // SLog @@ -113,74 +90,4 @@ float3 LinearToLog(float3 linearColor) return logColor; } -// Alexa LogC converters (El 1000) -// See http://www.vocas.nl/webfm_send/964 -// Max range is ~58.85666 - -struct ParamsLogC -{ - float cut; - float a, b, c, d, e, f; -}; - -static const ParamsLogC LogC = -{ - 0.011361, // cut - 5.555556, // a - 0.047996, // b - 0.244161, // c - 0.386036, // d - 5.301883, // e - 0.092819 // f -}; - -float3 LinearToLogC(float3 linearColor) -{ - return LogC.c * log10(LogC.a * linearColor + LogC.b) + LogC.d; -} - -float3 LogCToLinear(float3 logcColor) -{ - return (pow(10.0, (logcColor - LogC.d) / LogC.c) - LogC.b) / LogC.a; -} - -// Dolby PQ transforms -float3 ST2084ToLinear(float3 pq) -{ - const float m1 = 0.1593017578125; // = 2610. / 4096. * .25; - const float m2 = 78.84375; // = 2523. / 4096. * 128; - const float c1 = 0.8359375; // = 2392. / 4096. * 32 - 2413./4096.*32 + 1; - const float c2 = 18.8515625; // = 2413. / 4096. * 32; - const float c3 = 18.6875; // = 2392. / 4096. * 32; - const float C = 10000.; - - float3 Np = pow(pq, 1.0 / m2); - float3 L = Np - c1; - L = max(0.0, L); - L = L / (c2 - c3 * Np); - L = pow(L, 1.0 / m1); - float3 P = L * C; - - return P; -} - -float3 LinearToST2084(float3 lin) -{ - const float m1 = 0.1593017578125; // = 2610. / 4096. * .25; - const float m2 = 78.84375; // = 2523. / 4096. * 128; - const float c1 = 0.8359375; // = 2392. / 4096. * 32 - 2413./4096.*32 + 1; - const float c2 = 18.8515625; // = 2413. / 4096. * 32; - const float c3 = 18.6875; // = 2392. / 4096. * 32; - const float C = 10000.0; - - float3 L = lin / C; - float3 Lm = pow(L, m1); - float3 N1 = (c1 + c2 * Lm); - float3 N2 = (1.0 + c3 * Lm); - float3 N = N1 * rcp(N2); - float3 P = pow(N, m2); - - return P; -} - #endif diff --git a/Source/Shaders/Histogram.shader b/Source/Shaders/Histogram.shader index 32fb8eb1a..233983eb8 100644 --- a/Source/Shaders/Histogram.shader +++ b/Source/Shaders/Histogram.shader @@ -60,18 +60,6 @@ void CS_GenerateHistogram(uint3 groupId : SV_GroupID, uint3 dispatchThreadId : S if (dispatchThreadId.x < InputSize.x && dispatchThreadId.y < InputSize.y) { uint weight = 1u; - - // Vignette weighting to add more focus on the center of the screen -#if 0 - { - float2 uv = float2(dispatchThreadId.xy) / float2(InputSize.x, InputSize.y); - float2 d = abs(uv - (0.5).xx); - float factor = saturate(1.0 - dot(d, d)); - factor *= factor; - weight = (uint)(64.0 * factor); - } -#endif - float3 color = Input[dispatchThreadId.xy].xyz; float luminance = Luminance(color); float logLuminance = ComputeHistogramPositionFromLuminance(luminance); diff --git a/Source/Shaders/IESProfile.hlsl b/Source/Shaders/IESProfile.hlsl index f01be6aca..f1641a17e 100644 --- a/Source/Shaders/IESProfile.hlsl +++ b/Source/Shaders/IESProfile.hlsl @@ -3,19 +3,13 @@ #ifndef __IES_PROFILE__ #define __IES_PROFILE__ -// Apply 1D IES light profile texture +// Calculate IES light profile from 1D texture float ComputeLightProfileMultiplier(Texture2D tex, float3 worldPosition, float3 lightPosition, float3 lightDirection) { - float3 negLightDirection = normalize(worldPosition - lightPosition); - - // -1..1 - float dotProd = dot(negLightDirection, lightDirection); - // -PI..PI (this distortion could be put into the texture but not without quality loss or more memory) - float angle = asin(dotProd); - // 0..1 - float normAngle = angle / PI + 0.5f; - - return tex.SampleLevel(SamplerLinearClamp, float2(normAngle, 0), 0).r; + float3 l = normalize(worldPosition - lightPosition); + float d = dot(lightPosition, lightDirection); + float angle = asin(d) / PI + 0.5f; + return tex.SampleLevel(SamplerLinearClamp, float2(angle, 0), 0).r; } #endif diff --git a/Source/Shaders/Lighting.hlsl b/Source/Shaders/Lighting.hlsl index bee5b3606..f626afa0b 100644 --- a/Source/Shaders/Lighting.hlsl +++ b/Source/Shaders/Lighting.hlsl @@ -28,7 +28,6 @@ LightingData StandardShading(GBufferSample gBuffer, float energy, float3 L, floa float NoH = saturate(dot(N, H)); float VoH = saturate(dot(V, H)); - // Generalized microfacet specular float D = D_GGX(gBuffer.Roughness, NoH) * energy; float Vis = Vis_SmithJointApprox(gBuffer.Roughness, NoV, NoL); float3 F = F_Schlick(specularColor, VoH); @@ -113,7 +112,6 @@ float4 GetLighting(float3 viewPos, LightData lightData, GBufferSample gBuffer, f { float4 result = 0; float3 V = normalize(viewPos - gBuffer.WorldPos); - float3 ToLight = lightData.Direction; float3 N = gBuffer.Normal; float3 L = lightData.Direction; // no need to normalize float NoL = saturate(dot(N, L)); @@ -124,7 +122,7 @@ float4 GetLighting(float3 viewPos, LightData lightData, GBufferSample gBuffer, f // Calculate attenuation if (isRadial) { - GetRadialLightAttenuation(lightData, isSpotLight, gBuffer.WorldPos, N, 1, ToLight, L, NoL, distanceAttenuation, lightRadiusMask, spotAttenuation); + GetRadialLightAttenuation(lightData, isSpotLight, gBuffer.WorldPos, N, 1, lightData.Direction, L, NoL, distanceAttenuation, lightRadiusMask, spotAttenuation); } float attenuation = distanceAttenuation * lightRadiusMask * spotAttenuation; @@ -132,13 +130,13 @@ float4 GetLighting(float3 viewPos, LightData lightData, GBufferSample gBuffer, f ShadowData shadow = GetShadow(lightData, gBuffer, shadowMask); // Reduce shadow mapping artifacts - shadow.SurfaceShadow *= saturate(NoL * 6 - 0.2); + shadow.SurfaceShadow *= saturate(NoL * 6.0f - 0.2f); BRANCH if (shadow.SurfaceShadow + shadow.TransmissionShadow > 0) { gBuffer.Roughness = max(gBuffer.Roughness, lightData.MinRoughness); - float energy = AreaLightSpecular(lightData, gBuffer.Roughness, ToLight, L, V, N); + float energy = AreaLightSpecular(lightData, gBuffer.Roughness, lightData.Direction, L, V, N); // Calculate direct lighting LightingData lighting = SurfaceShading(gBuffer, energy, L, V, N); diff --git a/Source/Shaders/LightingCommon.hlsl b/Source/Shaders/LightingCommon.hlsl index 43303d316..ac98ef360 100644 --- a/Source/Shaders/LightingCommon.hlsl +++ b/Source/Shaders/LightingCommon.hlsl @@ -47,8 +47,8 @@ struct LightingData // WorldLightVector is the vector from the position being shaded to the light, divided by the radius of the light. float RadialAttenuation(float3 worldLightVector, half falloffExponent) { - float normalizeDistanceSquared = dot(worldLightVector, worldLightVector); - return pow(1.0f - saturate(normalizeDistanceSquared), falloffExponent); + float t = dot(worldLightVector, worldLightVector); + return pow(1.0f - saturate(t), falloffExponent); } // Calculates attenuation for a spot light. Where L normalize vector to light. @@ -127,30 +127,21 @@ float AreaLightSpecular(LightData lightData, float roughness, inout float3 toLig BRANCH if (lightData.SourceLength > 0) { - // Energy conservation float lineAngle = saturate(lightData.SourceLength * invDistToLight); energy *= m / saturate(m + 0.5 * lineAngle); - - // Closest point on line segment to ray float3 l01 = lightData.Direction * lightData.SourceLength; float3 l0 = toLight - 0.5 * l01; - float3 l1 = toLight + 0.5 * l01; - float a = Square(lightData.SourceLength); float b = dot(r, l01); float t = saturate(dot(l0, b * r - l01) / (a - b * b)); - toLight = l0 + t * l01; } BRANCH if (lightData.SourceRadius > 0) { - // Energy conservation float sphereAngle = saturate(lightData.SourceRadius * invDistToLight); energy *= Square(m / saturate(m + 0.5 * sphereAngle)); - - // Closest point on sphere to ray float3 closestPointOnRay = dot(toLight, r) * r; float3 centerToRay = closestPointOnRay - toLight; float3 closestPointOnSphere = toLight + centerToRay * saturate(lightData.SourceRadius * rsqrt(dot(centerToRay, centerToRay))); diff --git a/Source/Shaders/Math.hlsl b/Source/Shaders/Math.hlsl index 1287cc4af..a4bec9788 100644 --- a/Source/Shaders/Math.hlsl +++ b/Source/Shaders/Math.hlsl @@ -5,8 +5,8 @@ uint NextPow2(uint value) { - uint mask = (1 << firstbithigh(value)) - 1; - return (value + mask) & ~mask; + uint mask = (1 << firstbithigh(value)) - 1; + return (value + mask) & ~mask; } float3 SafeNormalize(float3 v) @@ -17,7 +17,6 @@ float3 SafeNormalize(float3 v) float3 ExtractLargestComponent(float3 v) { float3 a = abs(v); - if (a.x > a.y) { if (a.x > a.z) @@ -32,161 +31,160 @@ float3 ExtractLargestComponent(float3 v) return float3(0, v.y > 0 ? 1 : -1, 0); } } - return float3(0, 0, v.z > 0 ? 1 : -1); } float Square(float x) { - return x*x; + return x * x; } float2 Square(float2 x) { - return x*x; + return x * x; } float3 Square(float3 x) { - return x*x; + return x * x; } float4 Square(float4 x) { - return x*x; + return x * x; } float Pow2(float x) { - return x*x; + return x * x; } float2 Pow2(float2 x) { - return x*x; + return x * x; } float3 Pow2(float3 x) { - return x*x; + return x * x; } float4 Pow2(float4 x) { - return x*x; + return x * x; } float Pow3(float x) { - return x*x*x; + return x * x * x; } float2 Pow3(float2 x) { - return x*x*x; + return x * x * x; } float3 Pow3(float3 x) { - return x*x*x; + return x * x * x; } float4 Pow3(float4 x) { - return x*x*x; + return x * x * x; } float Pow4(float x) { - float xx = x*x; + float xx = x * x; return xx * xx; } float2 Pow4(float2 x) { - float2 xx = x*x; + float2 xx = x * x; return xx * xx; } float3 Pow4(float3 x) { - float3 xx = x*x; + float3 xx = x * x; return xx * xx; } float4 Pow4(float4 x) { - float4 xx = x*x; + float4 xx = x * x; return xx * xx; } float Pow5(float x) { - float xx = x*x; + float xx = x * x; return xx * xx * x; } float2 Pow5(float2 x) { - float2 xx = x*x; + float2 xx = x * x; return xx * xx * x; } float3 Pow5(float3 x) { - float3 xx = x*x; + float3 xx = x * x; return xx * xx * x; } float4 Pow5(float4 x) { - float4 xx = x*x; + float4 xx = x * x; return xx * xx * x; } float Pow6(float x) { - float xx = x*x; + float xx = x * x; return xx * xx * xx; } float2 Pow6(float2 x) { - float2 xx = x*x; + float2 xx = x * x; return xx * xx * xx; } float3 Pow6(float3 x) { - float3 xx = x*x; + float3 xx = x * x; return xx * xx * xx; } float4 Pow6(float4 x) { - float4 xx = x*x; + float4 xx = x * x; return xx * xx * xx; } -float ClampedPow(float x,float y) +float ClampedPow(float x, float y) { - return pow(max(abs(x), 0.000001f),y); + return pow(max(abs(x), 0.000001f), y); } -float2 ClampedPow(float2 x,float2 y) +float2 ClampedPow(float2 x, float2 y) { return pow(max(abs(x), float2(0.000001f, 0.000001f)), y); } -float3 ClampedPow(float3 x,float3 y) +float3 ClampedPow(float3 x, float3 y) { return pow(max(abs(x), float3(0.000001f, 0.000001f, 0.000001f)), y); -} +} -float4 ClampedPow(float4 x,float4 y) +float4 ClampedPow(float4 x, float4 y) { return pow(max(abs(x), float4(0.000001f, 0.000001f, 0.000001f, 0.000001f)), y); -} +} float4 FindQuatBetween(float3 from, float3 to) { @@ -208,8 +206,8 @@ float4 FindQuatBetween(float3 from, float3 to) { w = 0.f; result = abs(from.x) > abs(from.y) - ? float4(-from.z, 0.f, from.x, w) - : float4(0.f, -from.z, from.y, w); + ? float4(-from.z, 0.f, from.x, w) + : float4(0.f, -from.z, from.y, w); } return normalize(result); @@ -218,23 +216,13 @@ float4 FindQuatBetween(float3 from, float3 to) // Rotates Position about the given axis by the given angle, in radians, and returns the offset to position float3 RotateAboutAxis(float4 normalizedRotationAxisAndAngle, float3 positionOnAxis, float3 position) { - // Project position onto the rotation axis and find the closest point on the axis to Position - float3 closestPointOnAxis = positionOnAxis + normalizedRotationAxisAndAngle.xyz * dot(normalizedRotationAxisAndAngle.xyz, position - positionOnAxis); - - // Construct orthogonal axes in the plane of the rotation - float3 axisU = position - closestPointOnAxis; - float3 axisV = cross(normalizedRotationAxisAndAngle.xyz, axisU); - float cosAngle, sinAngle; - sincos(normalizedRotationAxisAndAngle.w, sinAngle, cosAngle); - - // Rotate using the orthogonal axes - float3 rotation = axisU * cosAngle + axisV * sinAngle; - - // Reconstruct the rotated world space position - float3 rotatedPosition = closestPointOnAxis + rotation; - - // Convert from position to a position offset - return rotatedPosition - position; + float3 pointOnAxis = positionOnAxis + normalizedRotationAxisAndAngle.xyz * dot(normalizedRotationAxisAndAngle.xyz, position - positionOnAxis); + float3 axisU = position - pointOnAxis; + float3 axisV = cross(normalizedRotationAxisAndAngle.xyz, axisU); + float cosAngle, sinAngle; + sincos(normalizedRotationAxisAndAngle.w, sinAngle, cosAngle); + float3 rotation = axisU * cosAngle + axisV * sinAngle; + return pointOnAxis + rotation - position; } #endif diff --git a/Source/Shaders/MonteCarlo.hlsl b/Source/Shaders/MonteCarlo.hlsl index 1faf7742b..e89f7770c 100644 --- a/Source/Shaders/MonteCarlo.hlsl +++ b/Source/Shaders/MonteCarlo.hlsl @@ -133,10 +133,10 @@ float4 ImportanceSampleGGX(float2 e, float roughness) // Multiple importance sampling power heuristic of two functions with a power of two. // [Veach 1997, "Robust Monte Carlo Methods for Light Transport Simulation"] -float MISWeight(uint number, float pdf, uint otherNumber, float otherpdf) +float MISWeight(uint number, float PDF, uint otherNumber, float otherPDF) { - float weight = number * pdf; - float otherWeight = otherNumber * otherpdf; + float weight = number * PDF; + float otherWeight = otherNumber * otherPDF; return weight * weight / (weight * weight + otherWeight * otherWeight); } diff --git a/Source/Shaders/MotionBlur.shader b/Source/Shaders/MotionBlur.shader index ef37cb15d..e4199d4a3 100644 --- a/Source/Shaders/MotionBlur.shader +++ b/Source/Shaders/MotionBlur.shader @@ -43,16 +43,16 @@ Texture2D Input0 : register(t0); Texture2D Input1 : register(t1); Texture2D Input2 : register(t2); -// Converts a motion vector into RGBA color. -float4 VectorToColor(float2 mv) +// Calculates the color for the a motion vector debugging +float4 VectorToColor(float2 motionVector) { - float phi = atan2(mv.x, mv.y); + float phi = atan2(motionVector.x, motionVector.y); float hue = (phi / PI + 1) * 0.5; float r = abs(hue * 6 - 3) - 1; float g = 2 - abs(hue * 6 - 2); float b = 2 - abs(hue * 6 - 4); - float a = length(mv); + float a = length(motionVector); return saturate(float4(r, g, b, a)); } @@ -61,18 +61,15 @@ float4 VectorToColor(float2 mv) META_PS(true, FEATURE_LEVEL_ES2) float4 PS_MotionVectorsDebug(Quad_VS2PS input) : SV_Target { - float4 src = SAMPLE_RT(Input0, input.TexCoord); + float4 color = SAMPLE_RT(Input0, input.TexCoord); + float2 motionVector = SAMPLE_RT(Input1, input.TexCoord).rg * (DebugAmplitude * 5.0f); + float4 motionColor = VectorToColor(motionVector); - float2 mv = SAMPLE_RT(Input1, input.TexCoord).rg * (DebugAmplitude * 5.0f); - float4 mc = VectorToColor(mv); + float colorRation = saturate(2 - DebugBlend * 2); + float motionColorRatio = saturate(DebugBlend * 2); + color.rgb = lerp(color.rgb * colorRation, motionColor.rgb, motionColor.a * motionColorRatio); - float3 rgb = mc.rgb; - - float src_ratio = saturate(2 - DebugBlend * 2); - float mc_ratio = saturate(DebugBlend * 2); - rgb = lerp(src.rgb * src_ratio, rgb, mc.a * mc_ratio); - - return float4(rgb, src.a); + return color; } // Motion vector arrow data from VS to PS @@ -88,60 +85,51 @@ ArrowVaryings VS_DebugArrow(uint VertexId : SV_VertexID) { // Screen aspect ratio float aspect = GBuffer.ScreenSize.x * GBuffer.ScreenSize.w; - float inv_aspect = GBuffer.ScreenSize.y * GBuffer.ScreenSize.z; + float aspectInv = GBuffer.ScreenSize.y * GBuffer.ScreenSize.z; // Vertex IDs - uint arrow_id = VertexId / 6; - uint point_id = VertexId - arrow_id * 6; + uint arrowId = VertexId / 6; + uint pointId = VertexId - arrowId * 6; - // Column/Row number of the arrow - uint row = arrow_id / DebugColumnCount; - uint col = arrow_id - row * DebugColumnCount; + // Column and row number of the arrow + uint row = arrowId / DebugColumnCount; + uint col = arrowId - row * DebugColumnCount; - // Texture coordinate of the reference point + // Get the motion vector float2 uv = float2((col + 0.5) / DebugColumnCount, (row + 0.5) / DebugRowCount); - - // Retrieve the motion vector - float2 mv = SAMPLE_RT(Input1, uv).rg * DebugAmplitude; + float2 motionVector = SAMPLE_RT(Input1, uv).rg * DebugAmplitude; // Arrow color - float4 color = VectorToColor(mv); + float4 color = VectorToColor(motionVector); - // Arrow vertex position parameter (0 = origin, 1 = head) - float arrow_l = point_id > 0; - - // Rotation matrix for the arrow head - float2 head_dir = normalize(mv * float2(aspect, 1)); - float2x2 head_rot = float2x2(head_dir.y, head_dir.x, -head_dir.x, head_dir.y); - - // Offset for arrow head vertices - float head_x = point_id == 3 ? -1 : (point_id == 5 ? 1 : 0); - head_x *= arrow_l * 0.3 * saturate(length(mv) * DebugRowCount); - - float2 head_offs = float2(head_x, -abs(head_x)); - head_offs = mul(head_rot, head_offs) * float2(inv_aspect, 1); + // Arrow transformation + float isEnd = pointId > 0; + float2 direction = normalize(motionVector * float2(aspect, 1)); + float2x2 rotation = float2x2(direction.y, direction.x, -direction.x, direction.y); + float offsetStart = pointId == 3 ? -1 : (pointId == 5 ? 1 : 0); + offsetStart *= isEnd * 0.3f * saturate(length(motionVector) * DebugRowCount); + float2 offset = float2(offsetStart, -abs(offsetStart)); + offset = mul(rotation, offset) * float2(aspectInv, 1); // Vertex position in the clip space - float2 vp = mv * arrow_l + head_offs * 2 / DebugRowCount + uv * 2 - 1; + float2 pos = motionVector * isEnd + offset * 2 / DebugRowCount + uv * 2.0f - 1.0f; // Convert to the screen coordinates - float2 scoord = (vp + 1) * 0.5 * GBuffer.ScreenSize.xy; - - // Snap to a pixel-perfect position. - scoord = round(scoord); + float2 posSS = (pos + 1) * 0.5f * GBuffer.ScreenSize.xy; + posSS = round(posSS); // Bring back to the clip space - vp = (scoord + 0.5) * GBuffer.ScreenSize.zw * 2 - 1; - vp.y *= -1; + pos = (posSS + 0.5f) * GBuffer.ScreenSize.zw * 2.0f - 1.0f; + pos.y *= -1; // Color tweaks - color.rgb = lerp(color.rgb, 1, 0.5); + color.rgb = lerp(color.rgb, 1, 0.5f); color.a = DebugBlend; // Output ArrowVaryings output; - output.Position = float4(vp, 0, 1); - output.ScreenUV = scoord; + output.Position = float4(pos, 0, 1); + output.ScreenUV = posSS; output.Color = color; return output; } @@ -150,8 +138,8 @@ META_PS(true, FEATURE_LEVEL_ES2) float4 PS_DebugArrow(ArrowVaryings input) : SV_Target { // Pseudo anti-aliasing - float aa = length(frac(input.ScreenUV) - 0.5) / 0.707; - aa *= (aa * (aa * 0.305306011 + 0.682171111) + 0.012522878); // gamma + float aa = length(frac(input.ScreenUV) - 0.5f) / 0.707f; + aa *= (aa * (aa * 0.305306011f + 0.682171111f) + 0.012522878f); return float4(input.Color.rgb, input.Color.a * aa); } @@ -190,10 +178,10 @@ float4 PS_VelocitySetup(Quad_VS2PS input) : SV_Target float2 v = SAMPLE_RT(Input0, input.TexCoord).rg; // Apply the exposure time and convert to the pixel space - v *= (VelocityScale * 0.5) * GBuffer.ScreenSize.xy; + v *= (VelocityScale * 0.5f) * GBuffer.ScreenSize.xy; // Clamp the vector with the maximum blur radius - v /= max(1.0, length(v) * RcpMaxBlurRadius); + v /= max(1.0f, length(v) * RcpMaxBlurRadius); // Sample the depth of the pixel float depth = SAMPLE_RT(Input1, input.TexCoord).r; @@ -201,7 +189,7 @@ float4 PS_VelocitySetup(Quad_VS2PS input) : SV_Target depth = LinearizeZ(gBufferData, depth); // Pack into 10/10/10/2 format - return float4((v * RcpMaxBlurRadius + 1.0) * 0.5, depth, 0.0); + return float4((v * RcpMaxBlurRadius + 1.0f) * 0.5f, depth, 0.0f); } float2 MaxV(float2 v1, float2 v2) @@ -220,40 +208,40 @@ float4 PS_TileMax1(Quad_VS2PS input) : SV_Target float2 v3 = SAMPLE_RT(Input0, input.TexCoord + d.xw).rg; float2 v4 = SAMPLE_RT(Input0, input.TexCoord + d.zw).rg; - v1 = (v1 * 2.0 - 1.0) * MaxBlurRadius; - v2 = (v2 * 2.0 - 1.0) * MaxBlurRadius; - v3 = (v3 * 2.0 - 1.0) * MaxBlurRadius; - v4 = (v4 * 2.0 - 1.0) * MaxBlurRadius; + v1 = (v1 * 2.0f - 1.0f) * MaxBlurRadius; + v2 = (v2 * 2.0f - 1.0f) * MaxBlurRadius; + v3 = (v3 * 2.0f - 1.0f) * MaxBlurRadius; + v4 = (v4 * 2.0f - 1.0f) * MaxBlurRadius; - return float4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0, 0.0); + return float4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0f, 0.0f); } // Pixel Shader for TileMax filter (2 pixel width) META_PS(true, FEATURE_LEVEL_ES2) float4 PS_TileMax2(Quad_VS2PS input) : SV_Target { - float4 d = TexelSize2.xyxy * float4(-0.5, -0.5, 0.5, 0.5); + float4 d = TexelSize2.xyxy * float4(-0.5f, -0.5f, 0.5f, 0.5f); float2 v1 = SAMPLE_RT(Input0, input.TexCoord + d.xy).rg; float2 v2 = SAMPLE_RT(Input0, input.TexCoord + d.zy).rg; float2 v3 = SAMPLE_RT(Input0, input.TexCoord + d.xw).rg; float2 v4 = SAMPLE_RT(Input0, input.TexCoord + d.zw).rg; - return float4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0, 0.0); + return float4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0f, 0.0f); } // Pixel Shader for TileMax filter (2 pixel width) META_PS(true, FEATURE_LEVEL_ES2) float4 PS_TileMax4(Quad_VS2PS input) : SV_Target { - float4 d = TexelSize4.xyxy * float4(-0.5, -0.5, 0.5, 0.5); + float4 d = TexelSize4.xyxy * float4(-0.5f, -0.5f, 0.5f, 0.5f); float2 v1 = SAMPLE_RT(Input0, input.TexCoord + d.xy).rg; float2 v2 = SAMPLE_RT(Input0, input.TexCoord + d.zy).rg; float2 v3 = SAMPLE_RT(Input0, input.TexCoord + d.xw).rg; float2 v4 = SAMPLE_RT(Input0, input.TexCoord + d.zw).rg; - return float4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0, 0.0); + return float4(MaxV(MaxV(MaxV(v1, v2), v3), v4), 0.0f, 0.0f); } // Pixel Shader for TileMax filter (variable width) @@ -306,7 +294,7 @@ float4 PS_NeighborMax(Quad_VS2PS input) : SV_Target float2 vb = MaxV(v4, MaxV(v5, v6)); float2 vc = MaxV(v7, MaxV(v8, v9)); - return float4(MaxV(va, MaxV(vb, vc)) * (1.0 / cw), 0.0, 0.0); + return float4(MaxV(va, MaxV(vb, vc)) * (1.0f / cw), 0.0f, 0.0f); } // Interleaved gradient function from Jimenez 2014 @@ -314,8 +302,8 @@ float4 PS_NeighborMax(Quad_VS2PS input) : SV_Target float GradientNoise(float2 uv) { uv = floor(uv * GBuffer.ScreenSize.xy); - float f = dot(float2(0.06711056, 0.00583715), uv); - return frac(52.9829189 * frac(f)); + float f = dot(float2(0.06711056f, 0.00583715f), uv); + return frac(52.9829189f * frac(f)); } // Returns true or false with a given interval @@ -328,103 +316,77 @@ bool Interval(float phase, float interval) float2 JitterTile(float2 uv) { float rx, ry; - sincos(GradientNoise(uv + float2(2.0, 0.0)) * (2.0f * PI), ry, rx); - return float2(rx, ry) * TexelSizeNM.xy * 0.25; + sincos(GradientNoise(uv + float2(2.0f, 0.0f)) * (2.0f * PI), ry, rx); + return float2(rx, ry) * TexelSizeNM.xy * 0.25f; } // Velocity sampling function float3 SampleVelocity(float2 uv) { float3 v = SAMPLE_RT(Input1, uv).xyz; - return float3((v.xy * 2.0 - 1.0) * MaxBlurRadius, v.z); + return float3((v.xy * 2.0f - 1.0f) * MaxBlurRadius, v.z); } // Pixel Shader for reconstruction filter (applies the motion blur to the frame) META_PS(true, FEATURE_LEVEL_ES2) float4 PS_Reconstruction(Quad_VS2PS input) : SV_Target { - // Color sample at the center point - const float4 c_p = SAMPLE_RT(Input0, input.TexCoord); + // Sample at the current location + const float4 color = SAMPLE_RT(Input0, input.TexCoord); + const float3 velocity = SampleVelocity(input.TexCoord); + const float velocityLen = max(length(velocity.xy), 0.5); + const float depthInv = 1.0 / velocity.z; - // Velocity/Depth sample at the center point - const float3 vd_p = SampleVelocity(input.TexCoord); - const float l_v_p = max(length(vd_p.xy), 0.5); - const float rcp_d_p = 1.0 / vd_p.z; + const float2 velocityMax = SAMPLE_RT(Input2, input.TexCoord + JitterTile(input.TexCoord)).xy; + const float velocityMaxLength = length(velocityMax); + if (velocityMaxLength < 2.0f) + return color; + const float2 velocityWeighted = (velocityLen * 2.0f > velocityMaxLength) ? velocity.xy * (velocityMaxLength / velocityLen) : velocityMax; - // NeighborMax vector sample at the center point - const float2 v_max = SAMPLE_RT(Input2, input.TexCoord + JitterTile(input.TexCoord)).xy; - const float l_v_max = length(v_max); - const float rcp_l_v_max = 1.0 / l_v_max; + // Calculate the amount of samples + const float sc = floor(min(LoopCount, velocityMaxLength * 0.5f)); - // Escape early if the NeighborMax vector is small enough - if (l_v_max < 2.0) - return c_p; - - // Use V_p as a secondary sampling direction except when it's too small - // compared to V_max. This vector is rescaled to be the length of V_max. - const float2 v_alt = (l_v_p * 2.0 > l_v_max) ? vd_p.xy * (l_v_max / l_v_p) : v_max; - - // Determine the sample count. - const float sc = floor(min(LoopCount, l_v_max * 0.5)); - - // Loop variables (starts from the outermost sample) - const float dt = 1.0 / sc; - const float t_offs = (GradientNoise(input.TexCoord) - 0.5) * dt; - float t = 1.0 - dt * 0.5; - float count = 0.0; - - // Background velocity - // This is used for tracking the maximum velocity in the background layer - float l_v_bg = max(l_v_p, 1.0); - - // Color accumlation - float4 acc = 0.0; + // Accumlation loop + float backgroudVelocity = max(velocityLen, 1.0f); + const float dt = 1.0f / sc; + const float offsetNoise = (GradientNoise(input.TexCoord) - 0.5f) * dt; + float t = 1.0f - dt * 0.5f; + float count = 0.0f; + float4 sum = 0.0f; LOOP while (t > dt * 0.25) { // Sampling direction (switched per every two samples) - const float2 v_s = Interval(count, 4.0) ? v_alt : v_max; + const float2 sampleVelocity = Interval(count, 4.0) ? velocityWeighted : velocityMax; // Sample position (inverted per every sample) - const float t_s = (Interval(count, 2.0) ? -t : t) + t_offs; + const float samplePosition = (Interval(count, 2.0) ? -t : t) + offsetNoise; - // Distance to the sample position - const float l_t = l_v_max * abs(t_s); + // Calculate UVs for the sample position + const float2 sampleUV = input.TexCoord + sampleVelocity * samplePosition * GBuffer.ScreenSize.zw; - // UVs for the sample position - const float2 uv0 = input.TexCoord + v_s * t_s * GBuffer.ScreenSize.zw; - //const float2 uv1 = input.TexCoord + v_s * t_s * MotionVectorsTexelSize.xy; - const float2 uv1 = uv0; - - // Color sample - const float3 c = SAMPLE_RT(Input0, uv0).rgb; - - // Velocity/Depth sample - const float3 vd = SampleVelocity(uv1); - - // Background/Foreground separation - const float fg = saturate((vd_p.z - vd.z) * 20.0 * rcp_d_p); + // Sample color and velocity with depth + const float3 c = SAMPLE_RT(Input0, sampleUV).rgb; + const float3 velocityDepth = SampleVelocity(sampleUV); // Length of the velocity vector - const float l_v = lerp(l_v_bg, length(vd.xy), fg); + const float foreground = saturate((velocity.z - velocityDepth.z) * 20.0f * depthInv); + const float sampleVelocityLength = lerp(backgroudVelocity, length(velocityDepth.xy), foreground); - // Sample weight - // (Distance test) * (Spreading out by motion) * (Triangular window) - const float w = saturate(l_v - l_t) / l_v * (1.2 - t); + // Apply color accumulation + float weight = saturate(sampleVelocityLength - (velocityMaxLength * abs(samplePosition))) / sampleVelocityLength * (1.2f - t); + sum += float4(c, 1.0) * weight; - // Color accumulation - acc += float4(c, 1.0) * w; + // Calculate the background velocity + backgroudVelocity = max(backgroudVelocity, sampleVelocityLength); - // Update the background velocity. - l_v_bg = max(l_v_bg, l_v); - - // Advance to the next sample. - t = Interval(count, 2.0) ? t - dt : t; - count += 1.0; + // Move to the next sample + t = Interval(count, 2.0f) ? t - dt : t; + count += 1.0f; } // Add the center sample - acc += float4(c_p.rgb, 1.0) * (1.2 / (l_v_bg * sc * 2.0)); + sum += float4(color.rgb, 1.0f) * (1.2f / (backgroudVelocity * sc * 2.0f)); - return float4(acc.rgb / acc.a, c_p.a); + return float4(sum.rgb / sum.a, color.a); } diff --git a/Source/Shaders/PostProcessing.shader b/Source/Shaders/PostProcessing.shader index 7ac812f06..1b8db3638 100644 --- a/Source/Shaders/PostProcessing.shader +++ b/Source/Shaders/PostProcessing.shader @@ -15,6 +15,10 @@ // // Perlin noise shader by toneburst: // http://machinesdontcare.wordpress.com/2009/06/25/3d-perlin-noise-sphere-vertex-shader-sourcecode/ +// +// Lens flares by John Chapman: +//https://john-chapman.github.io/2017/11/05/pseudo-lens-flare.html +// #include "./Flax/Common.hlsl" #include "./Flax/Random.hlsl" @@ -107,7 +111,6 @@ half3 ColorLookupTable(half3 linearColor) { // Move from linear color to encoded LUT color space //float3 encodedColor = linearColor; // Default - //float3 encodedColor = saturate(LinearToLogC(linearColor)); // LogC float3 encodedColor = LinearToLog(linearColor + LogToLinear(0)); // Log float3 uvw = encodedColor * ((LUTSize - 1) / LUTSize) + (0.5f / LUTSize); diff --git a/Source/Shaders/ProbesFilter.shader b/Source/Shaders/ProbesFilter.shader index 112cd9974..8ff0f8536 100644 --- a/Source/Shaders/ProbesFilter.shader +++ b/Source/Shaders/ProbesFilter.shader @@ -25,46 +25,44 @@ float4 SampleCubemap(float3 uv) return Cube.SampleLevel(SamplerLinearClamp, uv, SourceMipIndex); } -float3 GetCubemapVector(float2 scaledUVs) +float3 UvToCubeMapUv(float2 uv) { - float3 cubeCoordinates; - + float3 coords; if (CubeFace == 0) { - cubeCoordinates = float3(1, -scaledUVs.y, -scaledUVs.x); + coords = float3(1, -uv.y, -uv.x); } else if (CubeFace == 1) { - cubeCoordinates = float3(-1, -scaledUVs.y, scaledUVs.x); + coords = float3(-1, -uv.y, uv.x); } else if (CubeFace == 2) { - cubeCoordinates = float3(scaledUVs.x, 1, scaledUVs.y); + coords = float3(uv.x, 1, uv.y); } else if (CubeFace == 3) { - cubeCoordinates = float3(scaledUVs.x, -1, -scaledUVs.y); + coords = float3(uv.x, -1, -uv.y); } else if (CubeFace == 4) { - cubeCoordinates = float3(scaledUVs.x, -scaledUVs.y, 1); + coords = float3(uv.x, -uv.y, 1); } else { - cubeCoordinates = float3(-scaledUVs.x, -scaledUVs.y, -1); + coords = float3(-uv.x, -uv.y, -1); } - - return cubeCoordinates; + return coords; } // Pixel Shader for filtring probe mip levels META_PS(true, FEATURE_LEVEL_ES2) float4 PS_FilterFace(Quad_VS2PS input) : SV_Target { - float2 scaledUVs = input.TexCoord * 2 - 1; - float3 cubeCoordinates = GetCubemapVector(scaledUVs); + float2 uv = input.TexCoord * 2 - 1; + float3 cubeCoordinates = UvToCubeMapUv(uv); - #define NUM_FILTER_SAMPLES 512 +#define NUM_FILTER_SAMPLES 512 float3 N = normalize(cubeCoordinates); float roughness = ComputeReflectionCaptureRoughnessFromMip(SourceMipIndex); @@ -102,19 +100,15 @@ float4 PS_CopyFace(Quad_VS2PS input) : SV_Target META_PS(true, FEATURE_LEVEL_ES2) float4 PS_CalcDiffuseIrradiance(Quad_VS2PS input) : SV_Target { - float2 scaledUVs = input.TexCoord * 2 - 1; - float3 cubeCoordinates = normalize(GetCubemapVector(scaledUVs)); - - float squaredUVs = 1 + dot(scaledUVs, scaledUVs); - - // Dividing by NumSamples here to keep the sum in the range of fp16, once we get down to the 1x1 mip + float2 uv = input.TexCoord * 2 - 1; + float3 cubeCoordinates = normalize(UvToCubeMapUv(uv)); + float squaredUVs = 1 + dot(uv, uv); float weight = 4 / (sqrt(squaredUVs) * squaredUVs); ThreeBandSHVector shCoefficients = SHBasisFunction3(cubeCoordinates); float currentSHCoefficient = dot(shCoefficients.V0, CoefficientMask0) + dot(shCoefficients.V1, CoefficientMask1) + shCoefficients.V2 * CoefficientMask2; float3 radiance = SampleCubemap(cubeCoordinates).rgb; - return float4(radiance * currentSHCoefficient * weight, weight); } @@ -124,23 +118,23 @@ float4 PS_AccDiffuseIrradiance(Quad_VS2PS input) : SV_Target { float4 result = 0; { - float2 scaledUVs = saturate(input.TexCoord + Sample01.xy) * 2 - 1; - float3 cubeCoordinates = GetCubemapVector(scaledUVs); + float2 uv = saturate(input.TexCoord + Sample01.xy) * 2 - 1; + float3 cubeCoordinates = UvToCubeMapUv(uv); result += SampleCubemap(cubeCoordinates); } { - float2 scaledUVs = saturate(input.TexCoord + Sample01.zw) * 2 - 1; - float3 cubeCoordinates = GetCubemapVector(scaledUVs); + float2 uv = saturate(input.TexCoord + Sample01.zw) * 2 - 1; + float3 cubeCoordinates = UvToCubeMapUv(uv); result += SampleCubemap(cubeCoordinates); } { - float2 scaledUVs = saturate(input.TexCoord + Sample23.xy) * 2 - 1; - float3 cubeCoordinates = GetCubemapVector(scaledUVs); + float2 uv = saturate(input.TexCoord + Sample23.xy) * 2 - 1; + float3 cubeCoordinates = UvToCubeMapUv(uv); result += SampleCubemap(cubeCoordinates); } { - float2 scaledUVs = saturate(input.TexCoord + Sample23.zw) * 2 - 1; - float3 cubeCoordinates = GetCubemapVector(scaledUVs); + float2 uv = saturate(input.TexCoord + Sample23.zw) * 2 - 1; + float3 cubeCoordinates = UvToCubeMapUv(uv); result += SampleCubemap(cubeCoordinates); } return result / 4.0f; diff --git a/Source/Shaders/Random.hlsl b/Source/Shaders/Random.hlsl index ca5335458..01378ba09 100644 --- a/Source/Shaders/Random.hlsl +++ b/Source/Shaders/Random.hlsl @@ -3,104 +3,38 @@ #ifndef __RANDOM__ #define __RANDOM__ -// @param xy should be a integer position (e.g. pixel position on the screen), repeats each 128x128 pixels similar to a texture lookup but is only ALU float PseudoRandom(float2 xy) { - float2 pos = frac(xy / 128.0f) * 128.0f + float2(-64.340622f, -72.465622f); - return frac(dot(pos.xyx * pos.xyy, float3(20.390625f, 60.703125f, 2.4281209f))); + float2 p = frac(xy / 128.0f) * 128.0f + float2(-64.340622f, -72.465622f); + return frac(dot(p.xyx * p.xyy, float3(20.390625f, 60.703125f, 2.4281209f))); } -// Find good arbitrary axis vectors to represent U and V axes of a plane, given just the normal void FindBestAxisVectors(float3 input, out float3 axis1, out float3 axis2) { - const float3 N = abs(input); - - // Find best basis vectors - if( N.z > N.x && N.z > N.y ) - { + const float3 a = abs(input); + if (a.z > a.x && a.z > a.y) axis1 = float3(1, 0, 0); - } else - { axis1 = float3(0, 0, 1); - } - axis1 = normalize(axis1 - input * dot(axis1, input)); axis2 = cross(axis1, input); } -// References for noise: -// -// Improved Perlin noise -// http://mrl.nyu.edu/~perlin/noise/ -// http://http.developer.nvidia.com/GPUGems/gpugems_ch05.html -// Modified Noise for Evaluation on Graphics Hardware -// http://www.csee.umbc.edu/~olano/papers/mNoise.pdf -// Perlin Noise -// http://mrl.nyu.edu/~perlin/doc/oscar.html -// Fast Gradient Noise -// http://prettyprocs.wordpress.com/2012/10/20/fast-perlin-noise - - -// -------- ALU based method --------- - -/* - * Pseudo random number generator, based on "TEA, a tiny Encrytion Algorithm" - * http://citeseer.ist.psu.edu/viewdoc/download?doi=10.1.1.45.281&rep=rep1&type=pdf - * @param v - old seed (full 32bit range) - * @param iterationCount - >=1, bigger numbers cost more performance but improve quality - * @return new seed - */ -uint2 ScrambleTEA(uint2 v, uint iterationCount = 3) -{ - // Start with some random data (numbers can be arbitrary but those have been used by others and seem to work well) - uint k[4] ={ 0xA341316Cu , 0xC8013EA4u , 0xAD90777Du , 0x7E95761Eu }; - - uint y = v[0]; - uint z = v[1]; - uint sum = 0; - - UNROLL - for (uint i = 0; i < iterationCount; i++) - { - sum += 0x9e3779b9; - y += (z << 4u) + k[0] ^ z + sum ^ (z >> 5u) + k[1]; - z += (y << 4u) + k[2] ^ y + sum ^ (y >> 5u) + k[3]; - } - - return uint2(y, z); -} - -// Computes a pseudo random number for a given integer 2D position -// @param v - old seed (full 32bit range) -// @return random number in the range -1 .. 1 -float ComputeRandomFrom2DPosition(uint2 v) -{ - return (ScrambleTEA(v).x & 0xffff ) / (float)(0xffff) * 2 - 1; -} - -// Computes a pseudo random number for a given integer 2D position -// @param v - old seed (full 32bit range) -// @return random number in the range -1 .. 1 -float ComputeRandomFrom3DPosition(int3 v) -{ - // numbers found by experimentation - return ComputeRandomFrom2DPosition(v.xy ^ (uint2(0x123456, 0x23446) * v.zx) ); -} - -// Evaluate polynomial to get smooth transitions for Perlin noise (2 add, 5 mul) float PerlinRamp(in float t) { return t * t * t * (t * (t * 6 - 15) + 10); } + float2 PerlinRamp(in float2 t) { return t * t * t * (t * (t * 6 - 15) + 10); } + float3 PerlinRamp(in float3 t) { return t * t * t * (t * (t * 6 - 15) + 10); } + float4 PerlinRamp(in float4 t) { return t * t * t * (t * (t * 6 - 15) + 10); diff --git a/Source/Shaders/SH.hlsl b/Source/Shaders/SH.hlsl index c845c5a5d..b038554db 100644 --- a/Source/Shaders/SH.hlsl +++ b/Source/Shaders/SH.hlsl @@ -11,21 +11,20 @@ struct ThreeBandSHVector half V2; }; -ThreeBandSHVector SHBasisFunction3(half3 inputVector) +ThreeBandSHVector SHBasisFunction3(half3 v) { ThreeBandSHVector result; result.V0.x = 0.282095f; - result.V0.y = -0.488603f * inputVector.y; - result.V0.z = 0.488603f * inputVector.z; - result.V0.w = -0.488603f * inputVector.x; + result.V0.y = -0.488603f * v.y; + result.V0.z = 0.488603f * v.z; + result.V0.w = -0.488603f * v.x; - half3 vectorSquared = inputVector * inputVector; - result.V1.x = 1.092548f * inputVector.x * inputVector.y; - result.V1.y = -1.092548f * inputVector.y * inputVector.z; - result.V1.z = 0.315392f * (3.0f * inputVector.z - 1.0f); - result.V1.w = -1.092548f * inputVector.x * inputVector.z; - result.V2 = 0.546274f * (inputVector.x - inputVector.y); + result.V1.x = 1.092548f * v.x * v.y; + result.V1.y = -1.092548f * v.y * v.z; + result.V1.z = 0.315392f * (3.0f * v.z - 1.0f); + result.V1.w = -1.092548f * v.x * v.z; + result.V2 = 0.546274f * (v.x - v.y); return result; } diff --git a/Source/Shaders/ShadowsCommon.hlsl b/Source/Shaders/ShadowsCommon.hlsl index ad83fb7e5..81128adc4 100644 --- a/Source/Shaders/ShadowsCommon.hlsl +++ b/Source/Shaders/ShadowsCommon.hlsl @@ -39,25 +39,8 @@ struct LightShadowData #define DECLARE_LIGHTSHADOWDATA_ACCESS(uniformName) LightShadowData Get##uniformName##Data() { return uniformName; } #endif -// Gets the cube texture face index to use for shadow map sampling for the given view-to-light direction vector -// Where: direction = normalize(worldPosition - lightPosition) -int GetCubeFaceIndex(float3 direction) -{ - int cubeFaceIndex; - float3 absDirection = abs(direction); - float maxDirection = max(absDirection.x, max(absDirection.y, absDirection.z)); - if (maxDirection == absDirection.x) - cubeFaceIndex = absDirection.x == direction.x ? 0 : 1; - else if (maxDirection == absDirection.y) - cubeFaceIndex = absDirection.y == direction.y ? 2 : 3; - else - cubeFaceIndex = absDirection.z == direction.z ? 4 : 5; - return cubeFaceIndex; -} - float3 GetShadowPositionOffset(float offsetScale, float NoL, float3 normal) { - // Note: offsetScale should be multiplied by 2*ShadowMapTextureTexelSize on CPU float normalOffsetScale = saturate(1.0f - NoL); return normal * (offsetScale * normalOffsetScale); } @@ -65,8 +48,6 @@ float3 GetShadowPositionOffset(float offsetScale, float NoL, float3 normal) float CalculateSubsurfaceOcclusion(float opacity, float sceneDepth, float shadowMapDepth) { float thickness = max(sceneDepth - shadowMapDepth, 0); - //float density = -0.05f * log(1 - min(opacity, 0.999f)); - //float occlusion = saturate(exp(-thickness * density)); float occlusion = 1 - thickness * lerp(1.0f, 100.0f, opacity); return shadowMapDepth > 0.99f ? 1 : occlusion; } diff --git a/Source/Shaders/ShadowsSampling.hlsl b/Source/Shaders/ShadowsSampling.hlsl index 694f24f72..fbadc64de 100644 --- a/Source/Shaders/ShadowsSampling.hlsl +++ b/Source/Shaders/ShadowsSampling.hlsl @@ -42,6 +42,22 @@ #include "./Flax/PCFKernels.hlsl" #endif +// Gets the cube texture face index to use for shadow map sampling for the given view-to-light direction vector +// Where: direction = normalize(worldPosition - lightPosition) +int GetCubeFaceIndex(float3 direction) +{ + int cubeFaceIndex; + float3 absDirection = abs(direction); + float maxDirection = max(absDirection.x, max(absDirection.y, absDirection.z)); + if (maxDirection == absDirection.x) + cubeFaceIndex = absDirection.x == direction.x ? 0 : 1; + else if (maxDirection == absDirection.y) + cubeFaceIndex = absDirection.y == direction.y ? 2 : 3; + else + cubeFaceIndex = absDirection.z == direction.z ? 4 : 5; + return cubeFaceIndex; +} + // Samples the shadow map with a fixed-size PCF kernel optimized with GatherCmpRed. // Uses code from "Fast Conventional Shadow Filtering" by Holger Gruen, in GPU Pro. float SampleShadowMapFixedSizePCF(Texture2DArray shadowMap, float2 shadowMapSize, float sceneDepth, float2 shadowPos, uint cascadeIndex) diff --git a/Source/Shaders/VolumetricFog.shader b/Source/Shaders/VolumetricFog.shader index 169e7db5e..cc07de293 100644 --- a/Source/Shaders/VolumetricFog.shader +++ b/Source/Shaders/VolumetricFog.shader @@ -103,30 +103,12 @@ float3 ComputeVolumeUV(float3 worldPosition, float4x4 worldToClip) return float3(ndcPosition.xy * float2(0.5f, -0.5f) + 0.5f, ComputeNormalizedZSliceFromDepth(ndcPosition.w)); } -float IsotropicPhase() -{ - return 1 / (4 * PI); -} - float HenyeyGreensteinPhase(float g, float cosTheta) { return (1 - g * g) / (4 * PI * pow(1 + g * g + 2 * g * cosTheta, 1.5f)); } -float SchlickPhase(float k, float cosTheta) -{ - float t = (1 + k * cosTheta); - return (1 - k * k) / (4 * PI * t * t); -} - -float RaleighPhase(float cosTheta) -{ - return 3.0f * (1.0f + cosTheta * cosTheta) / (16.0f * PI); -} - -// Positive g = forward scattering -// Zero g = isotropic -// Negative g = backward scattering +// +g = forward scattering, 0=g = isotropic, -g = backward scattering float PhaseFunction(float g, float cosTheta) { return HenyeyGreensteinPhase(g, cosTheta); diff --git a/Source/Tools/Flax.Build/Build/Builder.Projects.cs b/Source/Tools/Flax.Build/Build/Builder.Projects.cs index 27f2dbecb..7270dcb6c 100644 --- a/Source/Tools/Flax.Build/Build/Builder.Projects.cs +++ b/Source/Tools/Flax.Build/Build/Builder.Projects.cs @@ -476,6 +476,25 @@ namespace Flax.Build "System.Core", }; SetupProjectConfigurations(project, rootProject); + if (project.Configurations.Count == 0) + { + // Hardcoded dummy configuration even if platform tools are missing for this platform + var platform = Platform.BuildPlatform; + var architecture = TargetArchitecture.x64; + var configuration = TargetConfiguration.Debug; + project.Configurations.Add(new Project.ConfigurationData + { + Platform = platform.Target, + PlatformName = platform.Target.ToString(), + Architecture = architecture, + ArchitectureName = architecture.ToString(), + Configuration = configuration, + ConfigurationName = configuration.ToString(), + Target = target, + TargetBuildOptions = GetBuildOptions(target, platform, null, architecture, configuration, project.WorkspaceRootPath), + Modules = new Dictionary(), + }); + } var c = project.Configurations[0]; c.Name = "Debug|AnyCPU"; c.Text = "Debug"; diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs index 6c606f0e6..bc6f1a157 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/Builder.NativeCpp.cs @@ -946,7 +946,7 @@ namespace Flax.Build { using (new ProfileEventScope(reference.Project.Name)) { - if (Configuration.BuildBindingsOnly || reference.Project.IsCSharpOnlyProject) + if (Configuration.BuildBindingsOnly || reference.Project.IsCSharpOnlyProject || !platform.HasRequiredSDKsInstalled) { BuildTargetReferenceNativeCppBindingsOnly(buildContext, buildData, reference); } diff --git a/Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs b/Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs index 6f8e2f756..f6a7816cf 100644 --- a/Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs +++ b/Source/Tools/Flax.Build/Platforms/Android/AndroidNdk.cs @@ -37,7 +37,7 @@ namespace Flax.Build.Platforms if (string.IsNullOrEmpty(sdkPath)) { // Look for ndk installed side-by-side with an sdk - if (AndroidSdk.Instance.IsValid) + if (AndroidSdk.Instance.IsValid && Directory.Exists(Path.Combine(AndroidSdk.Instance.RootPath, "ndk"))) { var subdirs = Directory.GetDirectories(Path.Combine(AndroidSdk.Instance.RootPath, "ndk")); if (subdirs.Length != 0)