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)