Merge remote-tracking branch 'origin/master' into navigation-features
This commit is contained in:
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -34,24 +34,16 @@ if errorlevel 1 goto Error_FlaxBuildFailed
|
||||
exit /B 0
|
||||
|
||||
:Error_InvalidLocation
|
||||
echo.
|
||||
echo CallBuildTool ERROR: The script is in invalid directory.
|
||||
echo.
|
||||
goto Exit
|
||||
:Error_NoVisualStudioEnvironment
|
||||
echo.
|
||||
echo CallBuildTool ERROR: Missing Visual Studio 2015 or newer.
|
||||
echo.
|
||||
goto Exit
|
||||
: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
|
||||
exit /B 1
|
||||
|
||||
@@ -16,10 +16,6 @@ This repository contains full source code of the Flax (excluding NDA-protected p
|
||||
* [Forum](https://forum.flaxengine.com)
|
||||
* [Roadmap](https://trello.com/b/NQjLXRCP/flax-roadmap)
|
||||
|
||||
# Flax plugin for Visual Studio
|
||||
|
||||
Flax Visual Studio extension provides better programming workflow, C# scripts debugging functionality and allows to attach to running engine instance to debug C# source. This extension is available to download [here](https://marketplace.visualstudio.com/items?itemName=Flax.FlaxVS).
|
||||
|
||||
# Screenshots
|
||||
|
||||

|
||||
@@ -53,6 +49,10 @@ Follow the instructions below to compile and run the engine from source.
|
||||
* Open workspace with Visual Code
|
||||
* Build and run
|
||||
|
||||
# Flax plugin for Visual Studio
|
||||
|
||||
Flax Visual Studio extension provides better programming workflow, C# scripts debugging functionality and allows to attach to running engine instance to debug C# source. This extension is available to download [here](https://marketplace.visualstudio.com/items?itemName=Flax.FlaxVS).
|
||||
|
||||
## Workspace directory
|
||||
|
||||
- **Binaries/** - executable files
|
||||
|
||||
@@ -968,7 +968,7 @@ namespace FlaxEditor.Viewport
|
||||
_wheelMovementChangeDeltaSum -= step;
|
||||
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Min(camValueIndex + 1, EditorViewportCameraSpeedValues.Length - 1)];
|
||||
}
|
||||
else if (_wheelMovementChangeDeltaSum <= step)
|
||||
else if (_wheelMovementChangeDeltaSum <= -step)
|
||||
{
|
||||
_wheelMovementChangeDeltaSum += step;
|
||||
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Max(camValueIndex - 1, 0)];
|
||||
|
||||
@@ -296,9 +296,14 @@ namespace FlaxEditor.Windows
|
||||
return;
|
||||
}
|
||||
|
||||
// Renaming a file to an extension it already has
|
||||
if (!item.IsFolder && StringUtils.NormalizeExtension(Path.GetExtension(newShortName)) == StringUtils.NormalizeExtension(Path.GetExtension(item.Path)))
|
||||
{
|
||||
newShortName = StringUtils.GetPathWithoutExtension(newShortName);
|
||||
}
|
||||
|
||||
// Check if name is valid
|
||||
string hint;
|
||||
if (!Editor.ContentEditing.IsValidAssetName(item, newShortName, out hint))
|
||||
if (!Editor.ContentEditing.IsValidAssetName(item, newShortName, out string hint))
|
||||
{
|
||||
// Invalid name
|
||||
MessageBox.Show("Given asset name is invalid. " + hint,
|
||||
@@ -317,7 +322,7 @@ namespace FlaxEditor.Windows
|
||||
}
|
||||
|
||||
// Cache data
|
||||
var extension = Path.GetExtension(item.Path);
|
||||
string extension = Path.GetExtension(item.Path);
|
||||
var newPath = StringUtils.CombinePaths(item.ParentFolder.Path, newShortName + extension);
|
||||
|
||||
// Check if was renaming mock element
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
bool TAA::Init()
|
||||
{
|
||||
// Create pipeline state
|
||||
_psTAA.CreatePipelineStates();
|
||||
//_psTAA.CreatePipelineStates();
|
||||
|
||||
// Load shader
|
||||
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/TAA"));
|
||||
@@ -34,22 +34,6 @@ bool TAA::setupResources()
|
||||
}
|
||||
const auto shader = _shader->GetShader();
|
||||
|
||||
// Validate shader constant buffer size
|
||||
if (shader->GetCB(0)->GetSize() != sizeof(Data))
|
||||
{
|
||||
REPORT_INVALID_SHADER_PASS_CB_SIZE(shader, 0, Data);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create pipeline state
|
||||
GPUPipelineState::Description psDesc;
|
||||
if (!_psTAA.IsValid())
|
||||
{
|
||||
psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle;
|
||||
if (_psTAA.Create(psDesc, shader, "PS"))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -58,10 +42,7 @@ void TAA::Dispose()
|
||||
// Base
|
||||
RendererPass::Dispose();
|
||||
|
||||
// Delete pipeline state
|
||||
_psTAA.Delete();
|
||||
|
||||
// Release asset
|
||||
_psTAA = nullptr;
|
||||
_shader.Unlink();
|
||||
}
|
||||
|
||||
@@ -75,7 +56,7 @@ void TAA::Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView
|
||||
auto context = GPUDevice::Instance->GetMainContext();
|
||||
|
||||
// Ensure to have valid data
|
||||
if (checkIfSkipPass())
|
||||
//if (checkIfSkipPass())
|
||||
{
|
||||
// Resources are missing. Do not perform rendering, just copy source frame.
|
||||
context->SetRenderTarget(output);
|
||||
@@ -119,32 +100,5 @@ void TAA::Render(RenderContext& renderContext, GPUTexture* input, GPUTextureView
|
||||
blendStrength = 0.0f;
|
||||
}
|
||||
|
||||
// Bind input
|
||||
Data data;
|
||||
data.ScreenSize = renderContext.View.ScreenSize;
|
||||
data.TaaJitterStrength.X = renderContext.View.TemporalAAJitter.X;
|
||||
data.TaaJitterStrength.Y = renderContext.View.TemporalAAJitter.Y;
|
||||
data.TaaJitterStrength.Z = data.TaaJitterStrength.X / tempDesc.Width;
|
||||
data.TaaJitterStrength.W = data.TaaJitterStrength.Y / tempDesc.Height;
|
||||
data.FinalBlendParameters.X = settings.TAA_StationaryBlending * blendStrength;
|
||||
data.FinalBlendParameters.Y = settings.TAA_MotionBlending * blendStrength;
|
||||
data.FinalBlendParameters.Z = 100.0f * 60.0f;
|
||||
data.FinalBlendParameters.W = settings.TAA_Sharpness;
|
||||
const auto cb = _shader->GetShader()->GetCB(0);
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
context->BindSR(0, input);
|
||||
context->BindSR(1, inputHistory);
|
||||
context->BindSR(2, renderContext.Buffers->MotionVectors);
|
||||
context->BindSR(3, renderContext.Buffers->DepthBuffer);
|
||||
|
||||
// Render
|
||||
GPUTextureView* rts[] = { output, outputHistory->View() };
|
||||
context->SetRenderTarget(nullptr, ToSpan(rts, ARRAY_COUNT(rts)));
|
||||
context->SetState(_psTAA.Get(renderContext.View.IsOrthographicProjection() ? 1 : 0));
|
||||
context->DrawFullscreenTriangle();
|
||||
|
||||
// Swap the history
|
||||
RenderTargetPool::Release(inputHistory);
|
||||
renderContext.Buffers->TemporalAA = outputHistory;
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -12,15 +12,8 @@ class TAA : public RendererPass<TAA>
|
||||
{
|
||||
private:
|
||||
|
||||
PACK_STRUCT(struct Data
|
||||
{
|
||||
Vector4 ScreenSize;
|
||||
Vector4 TaaJitterStrength;
|
||||
Vector4 FinalBlendParameters;
|
||||
});
|
||||
|
||||
AssetReference<Shader> _shader;
|
||||
GPUPipelineStatePermutationsPs<2> _psTAA;
|
||||
GPUPipelineState* _psTAA;
|
||||
|
||||
public:
|
||||
|
||||
@@ -44,7 +37,7 @@ private:
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
void OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_psTAA.Release();
|
||||
_psTAA = nullptr;
|
||||
invalidateResources();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -11,19 +11,16 @@
|
||||
#include "Engine/Graphics/RenderTargetPool.h"
|
||||
#include "Engine/Graphics/RenderBuffers.h"
|
||||
|
||||
PACK_STRUCT(struct Data {
|
||||
GBufferData GBuffer;
|
||||
Matrix CurrentVP;
|
||||
Matrix PreviousVP;
|
||||
Vector4 TemporalAAJitter;
|
||||
});
|
||||
|
||||
MotionBlurPass::MotionBlurPass()
|
||||
: _motionVectorsFormat(PixelFormat::Unknown)
|
||||
, _velocityFormat(PixelFormat::Unknown)
|
||||
, _psCameraMotionVectors(nullptr)
|
||||
, _psMotionVectorsDebug(nullptr)
|
||||
, _psMotionVectorsDebugArrow(nullptr)
|
||||
, _psVelocitySetup(nullptr)
|
||||
, _psTileMax1(nullptr)
|
||||
, _psTileMax2(nullptr)
|
||||
, _psTileMax4(nullptr)
|
||||
, _psTileMaxV(nullptr)
|
||||
, _psNeighborMax(nullptr)
|
||||
, _psReconstruction(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -36,15 +33,6 @@ bool MotionBlurPass::Init()
|
||||
{
|
||||
// Create pipeline state
|
||||
_psCameraMotionVectors = GPUDevice::Instance->CreatePipelineState();
|
||||
_psMotionVectorsDebug = GPUDevice::Instance->CreatePipelineState();
|
||||
_psMotionVectorsDebugArrow = GPUDevice::Instance->CreatePipelineState();
|
||||
_psVelocitySetup = GPUDevice::Instance->CreatePipelineState();
|
||||
_psTileMax1 = GPUDevice::Instance->CreatePipelineState();
|
||||
_psTileMax2 = GPUDevice::Instance->CreatePipelineState();
|
||||
_psTileMax4 = GPUDevice::Instance->CreatePipelineState();
|
||||
_psTileMaxV = GPUDevice::Instance->CreatePipelineState();
|
||||
_psNeighborMax = GPUDevice::Instance->CreatePipelineState();
|
||||
_psReconstruction = GPUDevice::Instance->CreatePipelineState();
|
||||
|
||||
// Load shader
|
||||
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/MotionBlur"));
|
||||
@@ -98,62 +86,6 @@ bool MotionBlurPass::setupResources()
|
||||
if (_psCameraMotionVectors->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
if (!_psVelocitySetup->IsValid())
|
||||
{
|
||||
psDesc.PS = shader->GetPS("PS_VelocitySetup");
|
||||
if (_psVelocitySetup->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
if (!_psTileMax1->IsValid())
|
||||
{
|
||||
psDesc.PS = shader->GetPS("PS_TileMax1");
|
||||
if (_psTileMax1->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
if (!_psTileMax2->IsValid())
|
||||
{
|
||||
psDesc.PS = shader->GetPS("PS_TileMax2");
|
||||
if (_psTileMax2->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
if (!_psTileMax4->IsValid())
|
||||
{
|
||||
psDesc.PS = shader->GetPS("PS_TileMax4");
|
||||
if (_psTileMax4->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
if (!_psTileMaxV->IsValid())
|
||||
{
|
||||
psDesc.PS = shader->GetPS("PS_TileMaxV");
|
||||
if (_psTileMaxV->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
if (!_psNeighborMax->IsValid())
|
||||
{
|
||||
psDesc.PS = shader->GetPS("PS_NeighborMax");
|
||||
if (_psNeighborMax->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
if (!_psReconstruction->IsValid())
|
||||
{
|
||||
psDesc.PS = shader->GetPS("PS_Reconstruction");
|
||||
if (_psReconstruction->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
if (!_psMotionVectorsDebug->IsValid())
|
||||
{
|
||||
psDesc.PS = shader->GetPS("PS_MotionVectorsDebug");
|
||||
if (_psMotionVectorsDebug->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
if (!_psMotionVectorsDebugArrow->IsValid())
|
||||
{
|
||||
psDesc.PrimitiveTopologyType = PrimitiveTopologyType::Line;
|
||||
psDesc.VS = shader->GetVS("VS_DebugArrow");
|
||||
psDesc.PS = shader->GetPS("PS_DebugArrow");
|
||||
if (_psMotionVectorsDebugArrow->Init(psDesc))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -165,15 +97,6 @@ void MotionBlurPass::Dispose()
|
||||
|
||||
// Delete pipeline state
|
||||
SAFE_DELETE_GPU_RESOURCE(_psCameraMotionVectors);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psMotionVectorsDebug);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psMotionVectorsDebugArrow);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psVelocitySetup);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psTileMax1);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psTileMax2);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psTileMax4);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psTileMaxV);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psNeighborMax);
|
||||
SAFE_DELETE_GPU_RESOURCE(_psReconstruction);
|
||||
|
||||
// Release asset
|
||||
_shader.Unlink();
|
||||
@@ -275,39 +198,13 @@ void MotionBlurPass::RenderDebug(RenderContext& renderContext, GPUTextureView* f
|
||||
{
|
||||
auto context = GPUDevice::Instance->GetMainContext();
|
||||
const auto motionVectors = renderContext.Buffers->MotionVectors;
|
||||
if (!motionVectors->IsAllocated() || setupResources())
|
||||
//if (!motionVectors->IsAllocated() || setupResources())
|
||||
{
|
||||
context->Draw(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
PROFILE_GPU_CPU("Motion Vectors Debug");
|
||||
|
||||
// Bind input
|
||||
Data data;
|
||||
GBufferPass::SetInputs(renderContext.View, data.GBuffer);
|
||||
const float rows = 16.0f;
|
||||
const float cols = rows * renderContext.Buffers->GetWidth() / renderContext.Buffers->GetHeight();
|
||||
data.DebugBlend = 0.7f;
|
||||
data.DebugAmplitude = 2.0f;
|
||||
data.DebugRowCount = static_cast<int32>(rows);
|
||||
data.DebugColumnCount = static_cast<int32>(cols);
|
||||
auto cb = _shader->GetShader()->GetCB(0);
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
context->BindSR(0, frame);
|
||||
context->BindSR(1, renderContext.Buffers->MotionVectors);
|
||||
|
||||
// Draw motion gradient
|
||||
context->SetState(_psMotionVectorsDebug);
|
||||
context->DrawFullscreenTriangle();
|
||||
|
||||
// Draw arrows
|
||||
context->SetState(_psMotionVectorsDebugArrow);
|
||||
context->Draw(0, static_cast<uint32>(cols * rows * 6));
|
||||
|
||||
// Cleanup
|
||||
context->ResetSR();
|
||||
// ..
|
||||
}
|
||||
|
||||
void MotionBlurPass::Render(RenderContext& renderContext, GPUTexture*& input, GPUTexture*& output)
|
||||
@@ -335,128 +232,5 @@ void MotionBlurPass::Render(RenderContext& renderContext, GPUTexture*& input, GP
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to have valid motion vectors created and rendered before
|
||||
ASSERT(motionVectors->IsAllocated());
|
||||
|
||||
PROFILE_GPU_CPU("Motion Blur");
|
||||
|
||||
// Calculate the maximum blur radius in pixels
|
||||
const float maxBlurRadius = 5.0f;
|
||||
const int32 maxBlurPixels = static_cast<int32>(maxBlurRadius * motionVectorsHeight / 100.0f);
|
||||
|
||||
// Calculate the TileMax size (it should be a multiple of 8 and larger than maxBlur)
|
||||
const int32 tileSize = ((maxBlurPixels - 1) / 8 + 1) * 8;
|
||||
|
||||
// Bind input
|
||||
Data data;
|
||||
GBufferPass::SetInputs(renderContext.View, data.GBuffer);
|
||||
Matrix::Transpose(renderContext.View.ViewProjection(), data.CurrentVP);
|
||||
Matrix::Transpose(renderContext.View.PrevViewProjection, data.PreviousVP);
|
||||
data.TemporalAAJitter = renderContext.View.TemporalAAJitter;
|
||||
data.VelocityScale = settings.Scale;
|
||||
data.MaxBlurRadius = static_cast<float>(maxBlurPixels);
|
||||
data.RcpMaxBlurRadius = 1.0f / maxBlurPixels;
|
||||
data.TileMaxOffs = Vector2::One * (tileSize / 8.0f - 1.0f) * -0.5f;
|
||||
data.TileMaxLoop = static_cast<int32>(tileSize / 8.0f);
|
||||
data.LoopCount = Math::Clamp(settings.SampleCount / 2.0f, 1.0f, 64.0f);
|
||||
const float invWidth = 1.0f / motionVectorsWidth;
|
||||
const float invHeight = 1.0f / motionVectorsHeight;
|
||||
data.TexelSize1 = Vector2(invWidth, invHeight);
|
||||
data.TexelSize2 = Vector2(invWidth * 2.0f, invHeight * 2.0f);
|
||||
data.TexelSize4 = Vector2(invWidth * 4.0f, invHeight * 4.0f);
|
||||
data.TexelSizeV = Vector2(invWidth * 8.0f, invHeight * 8.0f);
|
||||
data.TexelSizeNM = Vector2(invWidth * tileSize, invHeight * tileSize);
|
||||
data.MotionVectorsTexelSize = Vector2(1.0f / motionVectorsWidth, invHeight * tileSize);
|
||||
auto cb = _shader->GetShader()->GetCB(0);
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
context->BindSR(0, renderContext.Buffers->DepthBuffer);
|
||||
auto rtDesc = GPUTextureDescription::New2D(motionVectorsWidth, motionVectorsHeight, _velocityFormat);
|
||||
|
||||
// Pass 1 - Velocity/depth packing
|
||||
auto vBuffer = RenderTargetPool::Get(rtDesc);
|
||||
context->SetRenderTarget(*vBuffer);
|
||||
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
|
||||
context->BindSR(0, motionVectors->View());
|
||||
context->BindSR(1, renderContext.Buffers->DepthBuffer->View());
|
||||
context->SetState(_psVelocitySetup);
|
||||
context->DrawFullscreenTriangle();
|
||||
context->UnBindSR(1);
|
||||
|
||||
// Pass 2 - First TileMax filter (1/2 downsize)
|
||||
rtDesc.Format = _motionVectorsFormat;
|
||||
rtDesc.Width = motionVectorsWidth / 2;
|
||||
rtDesc.Height = motionVectorsHeight / 2;
|
||||
auto tile2 = RenderTargetPool::Get(rtDesc);
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(tile2->View());
|
||||
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
|
||||
context->BindSR(0, vBuffer->View());
|
||||
context->SetState(_psTileMax1);
|
||||
context->DrawFullscreenTriangle();
|
||||
|
||||
// Pass 3 - Second TileMax filter (1/4 downsize)
|
||||
rtDesc.Width = motionVectorsWidth / 4;
|
||||
rtDesc.Height = motionVectorsHeight / 4;
|
||||
auto tile4 = RenderTargetPool::Get(rtDesc);
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(tile4->View());
|
||||
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
|
||||
context->BindSR(0, tile2->View());
|
||||
context->SetState(_psTileMax2);
|
||||
context->DrawFullscreenTriangle();
|
||||
RenderTargetPool::Release(tile2);
|
||||
|
||||
// Pass 4 - Third TileMax filter (1/8 downsize)
|
||||
rtDesc.Width = motionVectorsWidth / 8;
|
||||
rtDesc.Height = motionVectorsHeight / 8;
|
||||
auto tile8 = RenderTargetPool::Get(rtDesc);
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(tile8->View());
|
||||
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
|
||||
context->BindSR(0, tile4->View());
|
||||
context->SetState(_psTileMax4);
|
||||
context->DrawFullscreenTriangle();
|
||||
RenderTargetPool::Release(tile4);
|
||||
|
||||
// Pass 5 - Fourth TileMax filter (reduce to tileSize)
|
||||
rtDesc.Width = motionVectorsWidth / tileSize;
|
||||
rtDesc.Height = motionVectorsHeight / tileSize;
|
||||
auto tile = RenderTargetPool::Get(rtDesc);
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(tile->View());
|
||||
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
|
||||
context->BindSR(0, tile8->View());
|
||||
context->SetState(_psTileMaxV);
|
||||
context->DrawFullscreenTriangle();
|
||||
RenderTargetPool::Release(tile8);
|
||||
|
||||
// Pass 6 - NeighborMax filter
|
||||
rtDesc.Width = motionVectorsWidth / tileSize;
|
||||
rtDesc.Height = motionVectorsHeight / tileSize;
|
||||
auto neighborMax = RenderTargetPool::Get(rtDesc);
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(neighborMax->View());
|
||||
context->SetViewportAndScissors((float)rtDesc.Width, (float)rtDesc.Height);
|
||||
context->BindSR(0, tile->View());
|
||||
context->SetState(_psNeighborMax);
|
||||
context->DrawFullscreenTriangle();
|
||||
RenderTargetPool::Release(tile);
|
||||
|
||||
// Pass 7 - Reconstruction pass
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(*output);
|
||||
context->SetViewportAndScissors((float)screenWidth, (float)screenHeight);
|
||||
context->BindSR(0, input->View());
|
||||
context->BindSR(1, vBuffer->View());
|
||||
context->BindSR(2, neighborMax->View());
|
||||
context->SetState(_psReconstruction);
|
||||
context->DrawFullscreenTriangle();
|
||||
|
||||
// Cleanup
|
||||
context->ResetSR();
|
||||
context->ResetRenderTarget();
|
||||
RenderTargetPool::Release(vBuffer);
|
||||
RenderTargetPool::Release(neighborMax);
|
||||
Swap(output, input);
|
||||
// ..
|
||||
}
|
||||
|
||||
@@ -10,43 +10,11 @@
|
||||
class MotionBlurPass : public RendererPass<MotionBlurPass>
|
||||
{
|
||||
private:
|
||||
PACK_STRUCT(struct Data {
|
||||
GBufferData GBuffer;
|
||||
Matrix CurrentVP;
|
||||
Matrix PreviousVP;
|
||||
Vector4 TemporalAAJitter;
|
||||
Vector2 TileMaxOffs;
|
||||
float VelocityScale;
|
||||
int32 TileMaxLoop;
|
||||
float MaxBlurRadius;
|
||||
float RcpMaxBlurRadius;
|
||||
Vector2 TexelSize1;
|
||||
Vector2 TexelSize2;
|
||||
Vector2 TexelSize4;
|
||||
Vector2 TexelSizeV;
|
||||
Vector2 TexelSizeNM;
|
||||
float LoopCount;
|
||||
float Dummy0;
|
||||
Vector2 MotionVectorsTexelSize;
|
||||
float DebugBlend;
|
||||
float DebugAmplitude;
|
||||
int32 DebugColumnCount;
|
||||
int32 DebugRowCount;
|
||||
});
|
||||
|
||||
PixelFormat _motionVectorsFormat;
|
||||
PixelFormat _velocityFormat;
|
||||
AssetReference<Shader> _shader;
|
||||
GPUPipelineState* _psCameraMotionVectors;
|
||||
GPUPipelineState* _psMotionVectorsDebug;
|
||||
GPUPipelineState* _psMotionVectorsDebugArrow;
|
||||
GPUPipelineState* _psVelocitySetup;
|
||||
GPUPipelineState* _psTileMax1;
|
||||
GPUPipelineState* _psTileMax2;
|
||||
GPUPipelineState* _psTileMax4;
|
||||
GPUPipelineState* _psTileMaxV;
|
||||
GPUPipelineState* _psNeighborMax;
|
||||
GPUPipelineState* _psReconstruction;
|
||||
GPUPipelineState* _psCameraMotionVectors = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
@@ -84,15 +52,6 @@ private:
|
||||
void OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_psCameraMotionVectors->ReleaseGPU();
|
||||
_psMotionVectorsDebug->ReleaseGPU();
|
||||
_psMotionVectorsDebugArrow->ReleaseGPU();
|
||||
_psVelocitySetup->ReleaseGPU();
|
||||
_psTileMax1->ReleaseGPU();
|
||||
_psTileMax2->ReleaseGPU();
|
||||
_psTileMax4->ReleaseGPU();
|
||||
_psTileMaxV->ReleaseGPU();
|
||||
_psNeighborMax->ReleaseGPU();
|
||||
_psReconstruction->ReleaseGPU();
|
||||
invalidateResources();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -306,6 +306,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
#endif
|
||||
renderContext.List->Settings.AntiAliasing.Mode = aaMode;
|
||||
|
||||
|
||||
// Prepare
|
||||
renderContext.View.Prepare(renderContext);
|
||||
renderContext.Buffers->Prepare();
|
||||
@@ -484,7 +485,8 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
||||
context->ResetRenderTarget();
|
||||
context->SetRenderTarget(task->GetOutputView());
|
||||
context->SetViewportAndScissors((float)renderContext.Buffers->GetWidth(), (float)renderContext.Buffers->GetHeight());
|
||||
MotionBlurPass::Instance()->RenderDebug(renderContext, frameBuffer->View());
|
||||
context->Clear(frameBuffer->View(), Color::Black);
|
||||
//MotionBlurPass::Instance()->RenderDebug(renderContext, frameBuffer->View());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace FlaxEngine
|
||||
/// <returns>The normalized extension.</returns>
|
||||
public static string NormalizeExtension(string extension)
|
||||
{
|
||||
if (extension[0] == '.')
|
||||
if (extension.Length != 0 && extension[0] == '.')
|
||||
extension = extension.Remove(0, 1);
|
||||
return extension.ToLower();
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ float D_GGX(float roughness, float NoH)
|
||||
float Vis_Schlick(float roughness, float NoV, float NoL)
|
||||
{
|
||||
float k = Square(roughness) * 0.5;
|
||||
float vis_SchlickV = NoV * (1 - k) + k;
|
||||
float vis_SchlickL = NoL * (1 - k) + k;
|
||||
return 0.25 / (vis_SchlickV * vis_SchlickL);
|
||||
float visSchlickV = NoV * (1 - k) + k;
|
||||
float visSchlickL = NoL * (1 - k) + k;
|
||||
return 0.25 / (visSchlickV * visSchlickL);
|
||||
}
|
||||
|
||||
// Smith term for GGX
|
||||
@@ -36,9 +36,9 @@ 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);
|
||||
return rcp(vis_SmithV * vis_SmithL);
|
||||
float visSmithV = NoV + sqrt(NoV * (NoV - NoV * a2) + a2);
|
||||
float visSmithL = NoL + sqrt(NoL * (NoL - NoL * a2) + a2);
|
||||
return rcp(visSmithV * visSmithL);
|
||||
}
|
||||
|
||||
// Appoximation of joint Smith term for GGX
|
||||
@@ -74,7 +74,7 @@ half SSRMipFromRoughness(half roughness)
|
||||
return max(1, 10 - mip1px);
|
||||
}
|
||||
|
||||
float ComputeReflectionCaptureRoughnessFromMip(float mip)
|
||||
float ProbeRoughnessFromMip(float mip)
|
||||
{
|
||||
float mip1px = REFLECTION_CAPTURE_NUM_MIPS - 1 - mip;
|
||||
return exp2((REFLECTION_CAPTURE_ROUGHEST_MIP - mip1px) / REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE);
|
||||
@@ -99,8 +99,6 @@ float3 EnvBRDF(Texture2D preIntegratedGF, float3 specularColor, float roughness,
|
||||
return specularColor * ab.x + saturate(50.0 * specularColor.g) * ab.y;
|
||||
}
|
||||
|
||||
#define MAX_SPECULAR_POWER 10000000000.0f
|
||||
|
||||
float RoughnessToSpecularPower(float roughness)
|
||||
{
|
||||
return pow(2, 13 * (1 - roughness));
|
||||
|
||||
@@ -264,37 +264,33 @@ META_VS(true, FEATURE_LEVEL_SM4)
|
||||
META_FLAG(VertexToGeometryShader)
|
||||
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_VS2GS VS_WriteToSlice(float2 Position : POSITION0, float2 TexCoord : TEXCOORD0, uint LayerIndex : SV_InstanceID)
|
||||
Quad_VS2GS VS_WriteToSlice(float2 position : POSITION0, float2 texCoord : TEXCOORD0, uint layerIndex : SV_InstanceID)
|
||||
{
|
||||
Quad_VS2GS output;
|
||||
|
||||
output.Vertex.Position = float4(Position, 0, 1);
|
||||
output.Vertex.TexCoord = TexCoord;
|
||||
output.LayerIndex = LayerIndex;
|
||||
|
||||
output.Vertex.Position = float4(position, 0, 1);
|
||||
output.Vertex.TexCoord = texCoord;
|
||||
output.LayerIndex = layerIndex;
|
||||
return output;
|
||||
}
|
||||
|
||||
// Geometry shader that writes to a range of slices of a volume texture
|
||||
META_GS(true, FEATURE_LEVEL_SM4)
|
||||
[maxvertexcount(3)]
|
||||
void GS_WriteToSlice(triangle Quad_VS2GS input[3], inout TriangleStream<Quad_GS2PS> OutStream)
|
||||
void GS_WriteToSlice(triangle Quad_VS2GS input[3], inout TriangleStream<Quad_GS2PS> stream)
|
||||
{
|
||||
Quad_GS2PS vertex0;
|
||||
vertex0.Vertex = input[0].Vertex;
|
||||
vertex0.LayerIndex = input[0].LayerIndex;
|
||||
Quad_GS2PS vertex;
|
||||
|
||||
Quad_GS2PS vertex1;
|
||||
vertex1.Vertex = input[1].Vertex;
|
||||
vertex1.LayerIndex = input[1].LayerIndex;
|
||||
vertex.Vertex = input[0].Vertex;
|
||||
vertex.LayerIndex = input[0].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
|
||||
Quad_GS2PS vertex2;
|
||||
vertex2.Vertex = input[2].Vertex;
|
||||
vertex2.LayerIndex = input[2].LayerIndex;
|
||||
vertex.Vertex = input[1].Vertex;
|
||||
vertex.LayerIndex = input[1].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
|
||||
OutStream.Append(vertex0);
|
||||
OutStream.Append(vertex1);
|
||||
OutStream.Append(vertex2);
|
||||
vertex.Vertex = input[2].Vertex;
|
||||
vertex.LayerIndex = input[2].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
|
||||
@@ -571,9 +571,9 @@ StructuredBuffer<BokehPoint> BokehPointBuffer : register(t2);
|
||||
// Vertex Shader, positions and scales the bokeh point
|
||||
META_VS(true, FEATURE_LEVEL_SM5)
|
||||
META_FLAG(VertexToGeometryShader)
|
||||
BokehVSOutput VS_Bokeh(in uint VertexID : SV_VertexID)
|
||||
BokehVSOutput VS_Bokeh(in uint vertexID : SV_VertexID)
|
||||
{
|
||||
BokehPoint bPoint = BokehPointBuffer[VertexID];
|
||||
BokehPoint bPoint = BokehPointBuffer[vertexID];
|
||||
BokehVSOutput output;
|
||||
|
||||
// Position the vertex in normalized device coordinate space [-1, 1]
|
||||
@@ -599,7 +599,7 @@ BokehVSOutput VS_Bokeh(in uint VertexID : SV_VertexID)
|
||||
// Geometry Shader, expands a vertex into a quad with two triangles
|
||||
META_GS(true, FEATURE_LEVEL_SM5)
|
||||
[maxvertexcount(4)]
|
||||
void GS_Bokeh(point BokehVSOutput input[1], inout TriangleStream<BokehGSOutput> SpriteStream)
|
||||
void GS_Bokeh(point BokehVSOutput input[1], inout TriangleStream<BokehGSOutput> stream)
|
||||
{
|
||||
BokehGSOutput output;
|
||||
|
||||
@@ -613,9 +613,9 @@ void GS_Bokeh(point BokehVSOutput input[1], inout TriangleStream<BokehGSOutput>
|
||||
output.Color = input[0].Color;
|
||||
output.Depth = input[0].Depth;
|
||||
|
||||
SpriteStream.Append(output);
|
||||
stream.Append(output);
|
||||
}
|
||||
SpriteStream.RestartStrip();
|
||||
stream.RestartStrip();
|
||||
}
|
||||
|
||||
// Pixel Shader, applies the bokeh shape texture
|
||||
|
||||
@@ -29,29 +29,29 @@ struct ExponentialHeightFogData
|
||||
float StartDistance;
|
||||
};
|
||||
|
||||
half4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 worldPosition, float3 cameraPosition, float excludeDistance)
|
||||
float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance)
|
||||
{
|
||||
float3 cameraToReceiver = worldPosition - cameraPosition;
|
||||
float cameraToReceiverLengthSqr = dot(cameraToReceiver, cameraToReceiver);
|
||||
float cameraToReceiverLengthInv = rsqrt(cameraToReceiverLengthSqr);
|
||||
float cameraToReceiverLength = cameraToReceiverLengthSqr * cameraToReceiverLengthInv;
|
||||
half3 cameraToReceiverNormalized = cameraToReceiver * cameraToReceiverLengthInv;
|
||||
float3 cameraToPos = posWS - camWS;
|
||||
float cameraToPosSqr = dot(cameraToPos, cameraToPos);
|
||||
float cameraToPosLenInv = rsqrt(cameraToPosSqr);
|
||||
float cameraToPosLen = cameraToPosSqr * cameraToPosLenInv;
|
||||
float3 cameraToReceiverNorm = cameraToPos * cameraToPosLenInv;
|
||||
|
||||
float rayOriginTerms = exponentialHeightFog.FogAtViewPosition;
|
||||
float rayLength = cameraToReceiverLength;
|
||||
float rayDirectionY = cameraToReceiver.y;
|
||||
float rayLength = cameraToPosLen;
|
||||
float rayDirectionY = cameraToPos.y;
|
||||
|
||||
// Apply start distance offset
|
||||
excludeDistance = max(excludeDistance, exponentialHeightFog.StartDistance);
|
||||
if (excludeDistance > 0)
|
||||
skipDistance = max(skipDistance, exponentialHeightFog.StartDistance);
|
||||
if (skipDistance > 0)
|
||||
{
|
||||
float excludeIntersectionTime = excludeDistance * cameraToReceiverLengthInv;
|
||||
float cameraToExclusionIntersectionY = excludeIntersectionTime * cameraToReceiver.y;
|
||||
float exclusionIntersectionY = cameraPosition.y + cameraToExclusionIntersectionY;
|
||||
float exclusionIntersectionToReceiverY = cameraToReceiver.y - cameraToExclusionIntersectionY;
|
||||
float excludeIntersectionTime = skipDistance * cameraToPosLenInv;
|
||||
float cameraToExclusionIntersectionY = excludeIntersectionTime * cameraToPos.y;
|
||||
float exclusionIntersectionY = camWS.y + cameraToExclusionIntersectionY;
|
||||
float exclusionIntersectionToReceiverY = cameraToPos.y - cameraToExclusionIntersectionY;
|
||||
|
||||
// Calculate fog off of the ray starting from the exclusion distance, instead of starting from the camera
|
||||
rayLength = (1.0f - excludeIntersectionTime) * cameraToReceiverLength;
|
||||
rayLength = (1.0f - excludeIntersectionTime) * cameraToPosLen;
|
||||
rayDirectionY = exclusionIntersectionToReceiverY;
|
||||
|
||||
// Move off the viewer
|
||||
@@ -67,22 +67,22 @@ half4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, flo
|
||||
float exponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * rayLength;
|
||||
|
||||
// Calculate the amount of light that made it through the fog using the transmission equation
|
||||
half expFogFactor = max(saturate(exp2(-exponentialHeightLineIntegral)), exponentialHeightFog.FogMinOpacity);
|
||||
float expFogFactor = max(saturate(exp2(-exponentialHeightLineIntegral)), exponentialHeightFog.FogMinOpacity);
|
||||
|
||||
// Calculate the directional light inscattering
|
||||
half3 inscatteringColor = exponentialHeightFog.FogInscatteringColor;
|
||||
half3 directionalInscattering = 0;
|
||||
float3 inscatteringColor = exponentialHeightFog.FogInscatteringColor;
|
||||
float3 directionalInscattering = 0;
|
||||
BRANCH
|
||||
if (exponentialHeightFog.ApplyDirectionalInscattering > 0)
|
||||
{
|
||||
// Setup a cosine lobe around the light direction to approximate inscattering from the directional light off of the ambient haze
|
||||
half3 directionalLightInscattering = exponentialHeightFog.DirectionalInscatteringColor * pow(saturate(dot(cameraToReceiverNormalized, exponentialHeightFog.InscatteringLightDirection)), exponentialHeightFog.DirectionalInscatteringExponent);
|
||||
float3 directionalLightInscattering = exponentialHeightFog.DirectionalInscatteringColor * pow(saturate(dot(cameraToReceiverNorm, exponentialHeightFog.InscatteringLightDirection)), exponentialHeightFog.DirectionalInscatteringExponent);
|
||||
|
||||
// Calculate the line integral of the eye ray through the haze, using a special starting distance to limit the inscattering to the distance
|
||||
float dirExponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * max(rayLength - exponentialHeightFog.DirectionalInscatteringStartDistance, 0.0f);
|
||||
|
||||
// Calculate the amount of light that made it through the fog using the transmission equation
|
||||
half directionalInscatteringFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral));
|
||||
float directionalInscatteringFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral));
|
||||
|
||||
// Final inscattering from the light
|
||||
directionalInscattering = directionalLightInscattering * (1 - directionalInscatteringFogFactor);
|
||||
@@ -90,13 +90,13 @@ half4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, flo
|
||||
|
||||
// Disable fog after a certain distance
|
||||
FLATTEN
|
||||
if (exponentialHeightFog.FogCutoffDistance > 0 && cameraToReceiverLength > exponentialHeightFog.FogCutoffDistance)
|
||||
if (exponentialHeightFog.FogCutoffDistance > 0 && cameraToPosLen > exponentialHeightFog.FogCutoffDistance)
|
||||
{
|
||||
expFogFactor = 1;
|
||||
directionalInscattering = 0;
|
||||
}
|
||||
|
||||
return half4((inscatteringColor) * (1 - expFogFactor) + directionalInscattering, expFogFactor);
|
||||
return float4(inscatteringColor * (1.0f - expFogFactor) + directionalInscattering, expFogFactor);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,15 +33,15 @@ float3 GetWorldPos(float2 uv)
|
||||
return mul(float4(viewPos, 1), gBufferData.InvViewMatrix).xyz;
|
||||
}
|
||||
|
||||
float4 CalculateCombinedFog(float3 worldPosition, float sceneDepth, float3 volumeUV)
|
||||
float4 CalculateCombinedFog(float3 posWS, float sceneDepth, float3 volumeUV)
|
||||
{
|
||||
float excludeDistance = 0;
|
||||
float skipDistance = 0;
|
||||
|
||||
#if VOLUMETRIC_FOG
|
||||
excludeDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
|
||||
skipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
|
||||
#endif
|
||||
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, worldPosition, GBuffer.ViewPos, excludeDistance);
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, posWS, GBuffer.ViewPos, skipDistance);
|
||||
|
||||
#if VOLUMETRIC_FOG
|
||||
float4 volumetricFog = IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0);
|
||||
@@ -57,8 +57,8 @@ META_PERMUTATION_1(VOLUMETRIC_FOG=1)
|
||||
float4 PS_Fog(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
// Calculate pixel world space position
|
||||
float3 worldPosition = GetWorldPos(input.TexCoord);
|
||||
float3 viewVector = worldPosition - GBuffer.ViewPos;
|
||||
float3 posWS = GetWorldPos(input.TexCoord);
|
||||
float3 viewVector = posWS - GBuffer.ViewPos;
|
||||
float sceneDepth = length(viewVector);
|
||||
|
||||
// Calculate volumetric fog coordinates
|
||||
@@ -67,17 +67,17 @@ float4 PS_Fog(Quad_VS2PS input) : SV_Target0
|
||||
|
||||
// Debug code
|
||||
#if VOLUMETRIC_FOG && 0
|
||||
volumeUV = worldPosition / 1000;
|
||||
volumeUV = posWS / 1000;
|
||||
if (!all(volumeUV >= 0 && volumeUV <= 1))
|
||||
return 0;
|
||||
|
||||
return float4(IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0).rgb, 1);
|
||||
//return float4(volumeUV, 1);
|
||||
//return float4(worldPosition / 100, 1);
|
||||
//return float4(posWS / 100, 1);
|
||||
#endif
|
||||
|
||||
// Calculate fog color
|
||||
float4 fog = CalculateCombinedFog(worldPosition, sceneDepth, volumeUV);
|
||||
float4 fog = CalculateCombinedFog(posWS, sceneDepth, volumeUV);
|
||||
|
||||
return fog;
|
||||
}
|
||||
|
||||
@@ -14,27 +14,6 @@ float4x4 CurrentVP;
|
||||
float4x4 PreviousVP;
|
||||
float4 TemporalAAJitter;
|
||||
|
||||
// Motion Blur
|
||||
float2 TileMaxOffs;
|
||||
float VelocityScale;
|
||||
int TileMaxLoop;
|
||||
float MaxBlurRadius;
|
||||
float RcpMaxBlurRadius;
|
||||
float2 TexelSize1;
|
||||
float2 TexelSize2;
|
||||
float2 TexelSize4;
|
||||
float2 TexelSizeV;
|
||||
float2 TexelSizeNM;
|
||||
float LoopCount;
|
||||
float Dummy0;
|
||||
float2 MotionVectorsTexelSize;
|
||||
|
||||
// Motion Vectors Debug Parameters
|
||||
float DebugBlend;
|
||||
float DebugAmplitude;
|
||||
int DebugColumnCount;
|
||||
int DebugRowCount;
|
||||
|
||||
META_CB_END
|
||||
|
||||
DECLARE_GBUFFERDATA_ACCESS(GBuffer)
|
||||
@@ -43,106 +22,6 @@ Texture2D Input0 : register(t0);
|
||||
Texture2D Input1 : register(t1);
|
||||
Texture2D Input2 : register(t2);
|
||||
|
||||
// Calculates the color for the a motion vector debugging
|
||||
float4 VectorToColor(float2 motionVector)
|
||||
{
|
||||
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(motionVector);
|
||||
|
||||
return saturate(float4(r, g, b, a));
|
||||
}
|
||||
|
||||
// Pixel shader for motion vectors debug view
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_MotionVectorsDebug(Quad_VS2PS input) : SV_Target
|
||||
{
|
||||
float4 color = SAMPLE_RT(Input0, input.TexCoord);
|
||||
float2 motionVector = SAMPLE_RT(Input1, input.TexCoord).rg * (DebugAmplitude * 5.0f);
|
||||
float4 motionColor = VectorToColor(motionVector);
|
||||
|
||||
float colorRation = saturate(2 - DebugBlend * 2);
|
||||
float motionColorRatio = saturate(DebugBlend * 2);
|
||||
color.rgb = lerp(color.rgb * colorRation, motionColor.rgb, motionColor.a * motionColorRatio);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// Motion vector arrow data from VS to PS
|
||||
struct ArrowVaryings
|
||||
{
|
||||
float4 Position : SV_POSITION;
|
||||
float2 ScreenUV : TEXCOORD;
|
||||
float4 Color : COLOR;
|
||||
};
|
||||
|
||||
META_VS(true, FEATURE_LEVEL_ES2)
|
||||
ArrowVaryings VS_DebugArrow(uint VertexId : SV_VertexID)
|
||||
{
|
||||
// Screen aspect ratio
|
||||
float aspect = GBuffer.ScreenSize.x * GBuffer.ScreenSize.w;
|
||||
float aspectInv = GBuffer.ScreenSize.y * GBuffer.ScreenSize.z;
|
||||
|
||||
// Vertex IDs
|
||||
uint arrowId = VertexId / 6;
|
||||
uint pointId = VertexId - arrowId * 6;
|
||||
|
||||
// Column and row number of the arrow
|
||||
uint row = arrowId / DebugColumnCount;
|
||||
uint col = arrowId - row * DebugColumnCount;
|
||||
|
||||
// Get the motion vector
|
||||
float2 uv = float2((col + 0.5) / DebugColumnCount, (row + 0.5) / DebugRowCount);
|
||||
float2 motionVector = SAMPLE_RT(Input1, uv).rg * DebugAmplitude;
|
||||
|
||||
// Arrow color
|
||||
float4 color = VectorToColor(motionVector);
|
||||
|
||||
// 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 pos = motionVector * isEnd + offset * 2 / DebugRowCount + uv * 2.0f - 1.0f;
|
||||
|
||||
// Convert to the screen coordinates
|
||||
float2 posSS = (pos + 1) * 0.5f * GBuffer.ScreenSize.xy;
|
||||
posSS = round(posSS);
|
||||
|
||||
// Bring back to the clip space
|
||||
pos = (posSS + 0.5f) * GBuffer.ScreenSize.zw * 2.0f - 1.0f;
|
||||
pos.y *= -1;
|
||||
|
||||
// Color tweaks
|
||||
color.rgb = lerp(color.rgb, 1, 0.5f);
|
||||
color.a = DebugBlend;
|
||||
|
||||
// Output
|
||||
ArrowVaryings output;
|
||||
output.Position = float4(pos, 0, 1);
|
||||
output.ScreenUV = posSS;
|
||||
output.Color = color;
|
||||
return output;
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_DebugArrow(ArrowVaryings input) : SV_Target
|
||||
{
|
||||
// Pseudo anti-aliasing
|
||||
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);
|
||||
}
|
||||
|
||||
// Pixel shader for camera motion vectors
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_CameraMotionVectors(Quad_VS2PS input) : SV_Target
|
||||
@@ -169,224 +48,3 @@ float4 PS_CameraMotionVectors(Quad_VS2PS input) : SV_Target
|
||||
|
||||
return float4(vPosCur - vPosPrev, 0, 1);
|
||||
}
|
||||
|
||||
// Pixel Shader for velocity texture setup
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_VelocitySetup(Quad_VS2PS input) : SV_Target
|
||||
{
|
||||
// Sample the motion vector
|
||||
float2 v = SAMPLE_RT(Input0, input.TexCoord).rg;
|
||||
|
||||
// Apply the exposure time and convert to the pixel space
|
||||
v *= (VelocityScale * 0.5f) * GBuffer.ScreenSize.xy;
|
||||
|
||||
// Clamp the vector with the maximum blur radius
|
||||
v /= max(1.0f, length(v) * RcpMaxBlurRadius);
|
||||
|
||||
// Sample the depth of the pixel
|
||||
float depth = SAMPLE_RT(Input1, input.TexCoord).r;
|
||||
GBufferData gBufferData = GetGBufferData();
|
||||
depth = LinearizeZ(gBufferData, depth);
|
||||
|
||||
// Pack into 10/10/10/2 format
|
||||
return float4((v * RcpMaxBlurRadius + 1.0f) * 0.5f, depth, 0.0f);
|
||||
}
|
||||
|
||||
float2 MaxV(float2 v1, float2 v2)
|
||||
{
|
||||
return dot(v1, v1) < dot(v2, v2) ? v2 : v1;
|
||||
}
|
||||
|
||||
// Pixel Shader for TileMax filter (2 pixel width with normalization)
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_TileMax1(Quad_VS2PS input) : SV_Target
|
||||
{
|
||||
float4 d = TexelSize1.xyxy * float4(-0.5, -0.5, 0.5, 0.5);
|
||||
|
||||
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;
|
||||
|
||||
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.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.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.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.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.0f, 0.0f);
|
||||
}
|
||||
|
||||
// Pixel Shader for TileMax filter (variable width)
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_TileMaxV(Quad_VS2PS input) : SV_Target
|
||||
{
|
||||
float2 uv0 = input.TexCoord + TexelSizeV.xy * TileMaxOffs.xy;
|
||||
|
||||
float2 du = float2(TexelSizeV.x, 0.0);
|
||||
float2 dv = float2(0.0, TexelSizeV.y);
|
||||
|
||||
float2 vo = 0.0;
|
||||
|
||||
LOOP
|
||||
for (int x = 0; x < TileMaxLoop; x++)
|
||||
{
|
||||
LOOP
|
||||
for (int y = 0; y < TileMaxLoop; y++)
|
||||
{
|
||||
float2 uv = uv0 + du * x + dv * y;
|
||||
vo = MaxV(vo, SAMPLE_RT(Input0, uv).rg);
|
||||
}
|
||||
}
|
||||
|
||||
return float4(vo, 0.0, 0.0);
|
||||
}
|
||||
|
||||
// Pixel Shader for NeighborMax filter
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
float4 PS_NeighborMax(Quad_VS2PS input) : SV_Target
|
||||
{
|
||||
// Center weight tweak
|
||||
const float cw = 1.01;
|
||||
|
||||
float4 d = TexelSizeNM.xyxy * float4(1.0, 1.0, -1.0, 0.0);
|
||||
|
||||
float2 v1 = SAMPLE_RT(Input0, input.TexCoord - d.xy).rg;
|
||||
float2 v2 = SAMPLE_RT(Input0, input.TexCoord - d.wy).rg;
|
||||
float2 v3 = SAMPLE_RT(Input0, input.TexCoord - d.zy).rg;
|
||||
|
||||
float2 v4 = SAMPLE_RT(Input0, input.TexCoord - d.xw).rg;
|
||||
float2 v5 = SAMPLE_RT(Input0, input.TexCoord).rg * cw;
|
||||
float2 v6 = SAMPLE_RT(Input0, input.TexCoord + d.xw).rg;
|
||||
|
||||
float2 v7 = SAMPLE_RT(Input0, input.TexCoord + d.zy).rg;
|
||||
float2 v8 = SAMPLE_RT(Input0, input.TexCoord + d.wy).rg;
|
||||
float2 v9 = SAMPLE_RT(Input0, input.TexCoord + d.xy).rg;
|
||||
|
||||
float2 va = MaxV(v1, MaxV(v2, v3));
|
||||
float2 vb = MaxV(v4, MaxV(v5, v6));
|
||||
float2 vc = MaxV(v7, MaxV(v8, v9));
|
||||
|
||||
return float4(MaxV(va, MaxV(vb, vc)) * (1.0f / cw), 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
// Interleaved gradient function from Jimenez 2014
|
||||
// http://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
|
||||
float GradientNoise(float2 uv)
|
||||
{
|
||||
uv = floor(uv * GBuffer.ScreenSize.xy);
|
||||
float f = dot(float2(0.06711056f, 0.00583715f), uv);
|
||||
return frac(52.9829189f * frac(f));
|
||||
}
|
||||
|
||||
// Returns true or false with a given interval
|
||||
bool Interval(float phase, float interval)
|
||||
{
|
||||
return frac(phase / interval) > 0.499;
|
||||
}
|
||||
|
||||
// Jitter function for tile lookup
|
||||
float2 JitterTile(float2 uv)
|
||||
{
|
||||
float rx, ry;
|
||||
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.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
|
||||
{
|
||||
// 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;
|
||||
|
||||
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;
|
||||
|
||||
// Calculate the amount of samples
|
||||
const float sc = floor(min(LoopCount, velocityMaxLength * 0.5f));
|
||||
|
||||
// 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 sampleVelocity = Interval(count, 4.0) ? velocityWeighted : velocityMax;
|
||||
|
||||
// Sample position (inverted per every sample)
|
||||
const float samplePosition = (Interval(count, 2.0) ? -t : t) + offsetNoise;
|
||||
|
||||
// Calculate UVs for the sample position
|
||||
const float2 sampleUV = input.TexCoord + sampleVelocity * samplePosition * GBuffer.ScreenSize.zw;
|
||||
|
||||
// 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 foreground = saturate((velocity.z - velocityDepth.z) * 20.0f * depthInv);
|
||||
const float sampleVelocityLength = lerp(backgroudVelocity, length(velocityDepth.xy), foreground);
|
||||
|
||||
// Apply color accumulation
|
||||
float weight = saturate(sampleVelocityLength - (velocityMaxLength * abs(samplePosition))) / sampleVelocityLength * (1.2f - t);
|
||||
sum += float4(c, 1.0) * weight;
|
||||
|
||||
// Calculate the background velocity
|
||||
backgroudVelocity = max(backgroudVelocity, sampleVelocityLength);
|
||||
|
||||
// Move to the next sample
|
||||
t = Interval(count, 2.0f) ? t - dt : t;
|
||||
count += 1.0f;
|
||||
}
|
||||
|
||||
// Add the center sample
|
||||
sum += float4(color.rgb, 1.0f) * (1.2f / (backgroudVelocity * sc * 2.0f));
|
||||
|
||||
return float4(sum.rgb / sum.a, color.a);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ float4 PS_FilterFace(Quad_VS2PS input) : SV_Target
|
||||
#define NUM_FILTER_SAMPLES 512
|
||||
|
||||
float3 N = normalize(cubeCoordinates);
|
||||
float roughness = ComputeReflectionCaptureRoughnessFromMip(SourceMipIndex);
|
||||
float roughness = ProbeRoughnessFromMip(SourceMipIndex);
|
||||
|
||||
float4 filteredColor = 0;
|
||||
float weight = 0;
|
||||
|
||||
+2
-143
@@ -1,151 +1,10 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/GammaCorrectionCommon.hlsl"
|
||||
|
||||
#define USE_TONEMAP 0
|
||||
|
||||
META_CB_BEGIN(0, Data)
|
||||
float4 ScreenSize;// x-width, y-height, z-1/width, w-1/height
|
||||
float4 TaaJitterStrength; // x, y, x/width, y/height
|
||||
float4 FinalBlendParameters; // x: static, y: dynamic, z: motion amplification, w; sharpness
|
||||
META_CB_END
|
||||
|
||||
Texture2D Input : register(t0);
|
||||
Texture2D InputHistory : register(t1);
|
||||
Texture2D MotionVectors : register(t2);
|
||||
Texture2D Depth : register(t3);
|
||||
|
||||
float3 Fetch(Texture2D tex, float2 coords)
|
||||
{
|
||||
return tex.SampleLevel(SamplerLinearClamp, coords, 0).rgb;
|
||||
}
|
||||
|
||||
float3 Map(float3 x)
|
||||
{
|
||||
#if USE_TONEMAP
|
||||
return FastTonemap(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
|
||||
float3 Unmap(float3 x)
|
||||
{
|
||||
#if USE_TONEMAP
|
||||
return FastTonemapInvert(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
|
||||
float3 ClipToAABB(float3 color, float3 minimum, float3 maximum)
|
||||
{
|
||||
// Note: only clips towards aabb center (but fast!)
|
||||
float3 center = 0.5 * (maximum + minimum);
|
||||
float3 extents = 0.5 * (maximum - minimum);
|
||||
|
||||
// This is actually `distance`, however the keyword is reserved
|
||||
float3 offset = color - center;
|
||||
|
||||
float3 ts = abs(extents / max(offset, 0.0001));
|
||||
float t = saturate(min(min(ts.x, ts.y), ts.z));
|
||||
return center + offset * t;
|
||||
}
|
||||
|
||||
float2 GetClosestFragment(float2 uv)
|
||||
{
|
||||
const float2 k = ScreenSize.zw;
|
||||
|
||||
const float4 neighborhood = float4(
|
||||
SAMPLE_RT(Depth, uv - k).r,
|
||||
SAMPLE_RT(Depth, uv + float2(k.x, -k.y)).r,
|
||||
SAMPLE_RT(Depth, uv + float2(-k.x, k.y)).r,
|
||||
SAMPLE_RT(Depth, uv + k).r
|
||||
);
|
||||
|
||||
#if defined(REVERSED_Z)
|
||||
#define COMPARE_DEPTH(a, b) step(b, a)
|
||||
#else
|
||||
#define COMPARE_DEPTH(a, b) step(a, b)
|
||||
#endif
|
||||
|
||||
float3 result = float3(0.0, 0.0, SAMPLE_RT(Depth, uv).r);
|
||||
result = lerp(result, float3(-1.0, -1.0, neighborhood.x), COMPARE_DEPTH(neighborhood.x, result.z));
|
||||
result = lerp(result, float3( 1.0, -1.0, neighborhood.y), COMPARE_DEPTH(neighborhood.y, result.z));
|
||||
result = lerp(result, float3(-1.0, 1.0, neighborhood.z), COMPARE_DEPTH(neighborhood.z, result.z));
|
||||
result = lerp(result, float3( 1.0, 1.0, neighborhood.w), COMPARE_DEPTH(neighborhood.w, result.z));
|
||||
|
||||
return (uv + result.xy * k);
|
||||
}
|
||||
|
||||
// Pixel Shader for Temporal Anti-Aliasing
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
META_PERMUTATION_1(IS_ORTHO=0)
|
||||
META_PERMUTATION_1(IS_ORTHO=1)
|
||||
void PS(Quad_VS2PS input, out float4 output : SV_Target0, out float4 outputHistory : SV_Target1)
|
||||
float4 PS(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
float2 jitter = TaaJitterStrength.zw;
|
||||
float2 texcoord = input.TexCoord;
|
||||
const float2 k = ScreenSize.zw;
|
||||
|
||||
#if IS_ORTHO
|
||||
float2 closest = texcoord;
|
||||
#else
|
||||
float2 closest = GetClosestFragment(texcoord);
|
||||
#endif
|
||||
|
||||
// Sample velocity
|
||||
float2 velocity = MotionVectors.SampleLevel(SamplerLinearClamp, closest, 0).xy;
|
||||
|
||||
// Sample color and surround
|
||||
float2 uv = texcoord - jitter;
|
||||
float3 color = Fetch(Input, uv);
|
||||
float3 topLeft = Fetch(Input, uv - k);
|
||||
float3 bottomRight = Fetch(Input, uv + k);
|
||||
float3 topRight = Fetch(Input, uv + float2(k.x, -k.y));
|
||||
float3 bottomLeft = Fetch(Input, uv + float2(-k.x, k.y));
|
||||
|
||||
float3 corners = 4.0 * (topLeft + bottomRight) - 2.0 * color;
|
||||
|
||||
// Sharpen output
|
||||
float sharpness = FinalBlendParameters.w;
|
||||
float3 blur = (topLeft + topRight + bottomLeft + bottomRight) * 0.25;
|
||||
color += (color - blur) * sharpness;
|
||||
color = clamp(color, 0.0, HDR_CLAMP_MAX);
|
||||
|
||||
// Tonemap color
|
||||
float3 average = Map((corners + color) / 7.0);
|
||||
topLeft = Map(topLeft);
|
||||
bottomRight = Map(bottomRight);
|
||||
color = Map(color);
|
||||
|
||||
// Sample history
|
||||
float3 history = Fetch(InputHistory, texcoord - velocity);
|
||||
history = Map(history);
|
||||
|
||||
float colorLuma = Luminance(color);
|
||||
float averageLuma = Luminance(average);
|
||||
float velocityLength = length(velocity);
|
||||
float nudge = lerp(4.0, 0.25, velocityLength * 100.0) * abs(averageLuma - colorLuma);
|
||||
|
||||
float3 minimum = min(bottomRight, topLeft) - nudge;
|
||||
float3 maximum = max(topLeft, bottomRight) + nudge;
|
||||
|
||||
// Clip history sample
|
||||
history = ClipToAABB(history, minimum, maximum);
|
||||
|
||||
// Blend color with history
|
||||
//float historyLuma = Luminance(history);
|
||||
//float weight = 1.0f - saturate(abs(colorLuma - historyLuma) / max(max(colorLuma, historyLuma), 0.2));
|
||||
float weight = saturate(velocityLength * FinalBlendParameters.z);
|
||||
float feedback = lerp(FinalBlendParameters.x, FinalBlendParameters.y, weight * weight);
|
||||
//feedback = lerp(feedback, 0.02, velocityWeight);
|
||||
color = Unmap(lerp(color, history, feedback));
|
||||
color = clamp(color, 0.0, HDR_CLAMP_MAX);
|
||||
|
||||
output = float4(color, 1);
|
||||
outputHistory = output;
|
||||
|
||||
//output = float4(1, 0, 0, 1) * feedback;
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ META_CB_END
|
||||
META_CB_BEGIN(1, PerLight)
|
||||
|
||||
float2 Dummy1;
|
||||
int MinZ; // Z index of the minimum slice in the range
|
||||
int MinZ;
|
||||
float LocalLightScatteringIntensity;
|
||||
|
||||
float4 ViewSpaceBoundingSphere;
|
||||
@@ -72,48 +72,44 @@ LightShadowData LocalLightShadow;
|
||||
|
||||
META_CB_END
|
||||
|
||||
float ComputeDepthFromZSlice(float zSlice)
|
||||
{
|
||||
return (zSlice / GridSize.z) * VolumetricFogMaxDistance;
|
||||
}
|
||||
|
||||
float3 ComputeCellWorldPosition(uint3 gridCoordinate, float3 cellOffset, out float sceneDepth)
|
||||
{
|
||||
float2 volumeUV = (gridCoordinate.xy + cellOffset.xy) / GridSize.xy;
|
||||
sceneDepth = ComputeDepthFromZSlice(gridCoordinate.z + cellOffset.z) / GBuffer.ViewFar;
|
||||
float deviceDepth = LinearZ2DeviceDepth(GBuffer, sceneDepth);
|
||||
return GetWorldPos(GBuffer, volumeUV, deviceDepth);
|
||||
}
|
||||
|
||||
float3 ComputeCellWorldPosition(uint3 gridCoordinate, float3 cellOffset)
|
||||
{
|
||||
float unused;
|
||||
return ComputeCellWorldPosition(gridCoordinate, cellOffset, unused);
|
||||
}
|
||||
|
||||
float ComputeNormalizedZSliceFromDepth(float sceneDepth)
|
||||
{
|
||||
return sceneDepth / VolumetricFogMaxDistance;
|
||||
}
|
||||
|
||||
float3 ComputeVolumeUV(float3 worldPosition, float4x4 worldToClip)
|
||||
{
|
||||
float4 ndcPosition = mul(float4(worldPosition, 1), worldToClip);
|
||||
ndcPosition.xy /= ndcPosition.w;
|
||||
return float3(ndcPosition.xy * float2(0.5f, -0.5f) + 0.5f, ComputeNormalizedZSliceFromDepth(ndcPosition.w));
|
||||
}
|
||||
|
||||
// The Henyey-Greenstein phase function
|
||||
// [Henyey and Greenstein 1941, https://www.astro.umd.edu/~jph/HG_note.pdf]
|
||||
float HenyeyGreensteinPhase(float g, float cosTheta)
|
||||
{
|
||||
return (1 - g * g) / (4 * PI * pow(1 + g * g + 2 * g * cosTheta, 1.5f));
|
||||
}
|
||||
|
||||
// +g = forward scattering, 0=g = isotropic, -g = backward scattering
|
||||
float PhaseFunction(float g, float cosTheta)
|
||||
float GetPhase(float g, float cosTheta)
|
||||
{
|
||||
return HenyeyGreensteinPhase(g, cosTheta);
|
||||
}
|
||||
|
||||
float GetSliceDepth(float zSlice)
|
||||
{
|
||||
return (zSlice / GridSize.z) * VolumetricFogMaxDistance;
|
||||
}
|
||||
|
||||
float3 GetCellPositionWS(uint3 gridCoordinate, float3 cellOffset, out float sceneDepth)
|
||||
{
|
||||
float2 volumeUV = (gridCoordinate.xy + cellOffset.xy) / GridSize.xy;
|
||||
sceneDepth = GetSliceDepth(gridCoordinate.z + cellOffset.z) / GBuffer.ViewFar;
|
||||
float deviceDepth = LinearZ2DeviceDepth(GBuffer, sceneDepth);
|
||||
return GetWorldPos(GBuffer, volumeUV, deviceDepth);
|
||||
}
|
||||
|
||||
float3 GetCellPositionWS(uint3 gridCoordinate, float3 cellOffset)
|
||||
{
|
||||
float temp;
|
||||
return GetCellPositionWS(gridCoordinate, cellOffset, temp);
|
||||
}
|
||||
|
||||
float3 GetVolumeUV(float3 worldPosition, float4x4 worldToClip)
|
||||
{
|
||||
float4 ndcPosition = mul(float4(worldPosition, 1), worldToClip);
|
||||
ndcPosition.xy /= ndcPosition.w;
|
||||
return float3(ndcPosition.xy * float2(0.5f, -0.5f) + 0.5f, ndcPosition.w / VolumetricFogMaxDistance);
|
||||
}
|
||||
|
||||
// Vertex shader that writes to a range of slices of a volume texture
|
||||
META_VS(true, FEATURE_LEVEL_SM5)
|
||||
META_FLAG(VertexToGeometryShader)
|
||||
@@ -123,22 +119,18 @@ Quad_VS2GS VS_WriteToSlice(float2 TexCoord : TEXCOORD0, uint LayerIndex : SV_Ins
|
||||
Quad_VS2GS output;
|
||||
|
||||
uint slice = LayerIndex + MinZ;
|
||||
float sliceDepth = ComputeDepthFromZSlice(slice);
|
||||
float sliceDepthOffset = abs(sliceDepth - ViewSpaceBoundingSphere.z);
|
||||
float depth = GetSliceDepth(slice);
|
||||
float depthOffset = abs(depth - ViewSpaceBoundingSphere.z);
|
||||
|
||||
if (sliceDepthOffset < ViewSpaceBoundingSphere.w)
|
||||
if (depthOffset < ViewSpaceBoundingSphere.w)
|
||||
{
|
||||
// Compute the radius of the circle formed by the intersection of the bounding sphere and the current depth slice
|
||||
float sliceRadius = sqrt(ViewSpaceBoundingSphere.w * ViewSpaceBoundingSphere.w - sliceDepthOffset * sliceDepthOffset);
|
||||
|
||||
// Place the quad vertex to tightly bound the circle
|
||||
float3 viewSpaceVertexPosition = float3(ViewSpaceBoundingSphere.xy + (TexCoord * 2 - 1) * sliceRadius, sliceDepth);
|
||||
output.Vertex.Position = mul(float4(viewSpaceVertexPosition, 1), ViewToVolumeClip);
|
||||
float radius = sqrt(ViewSpaceBoundingSphere.w * ViewSpaceBoundingSphere.w - depthOffset * depthOffset);
|
||||
float3 positionVS = float3(ViewSpaceBoundingSphere.xy + (TexCoord * 2 - 1) * radius, depth);
|
||||
output.Vertex.Position = mul(float4(positionVS, 1), ViewToVolumeClip);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Slice does not intersect bounding sphere, emit degenerate triangle
|
||||
output.Vertex.Position = 0;
|
||||
output.Vertex.Position = float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
output.Vertex.TexCoord = 0;
|
||||
@@ -150,23 +142,21 @@ Quad_VS2GS VS_WriteToSlice(float2 TexCoord : TEXCOORD0, uint LayerIndex : SV_Ins
|
||||
// Geometry shader that writes to a range of slices of a volume texture
|
||||
META_GS(true, FEATURE_LEVEL_SM5)
|
||||
[maxvertexcount(3)]
|
||||
void GS_WriteToSlice(triangle Quad_VS2GS input[3], inout TriangleStream<Quad_GS2PS> OutStream)
|
||||
void GS_WriteToSlice(triangle Quad_VS2GS input[3], inout TriangleStream<Quad_GS2PS> stream)
|
||||
{
|
||||
Quad_GS2PS vertex0;
|
||||
vertex0.Vertex = input[0].Vertex;
|
||||
vertex0.LayerIndex = input[0].LayerIndex;
|
||||
Quad_GS2PS vertex;
|
||||
|
||||
Quad_GS2PS vertex1;
|
||||
vertex1.Vertex = input[1].Vertex;
|
||||
vertex1.LayerIndex = input[1].LayerIndex;
|
||||
vertex.Vertex = input[0].Vertex;
|
||||
vertex.LayerIndex = input[0].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
|
||||
Quad_GS2PS vertex2;
|
||||
vertex2.Vertex = input[2].Vertex;
|
||||
vertex2.LayerIndex = input[2].LayerIndex;
|
||||
vertex.Vertex = input[1].Vertex;
|
||||
vertex.LayerIndex = input[1].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
|
||||
OutStream.Append(vertex0);
|
||||
OutStream.Append(vertex1);
|
||||
OutStream.Append(vertex2);
|
||||
vertex.Vertex = input[2].Vertex;
|
||||
vertex.LayerIndex = input[2].LayerIndex;
|
||||
stream.Append(vertex);
|
||||
}
|
||||
|
||||
#if USE_SHADOW
|
||||
@@ -208,18 +198,16 @@ float4 PS_InjectLight(Quad_GS2PS input) : SV_Target0
|
||||
return 0;
|
||||
|
||||
#if USE_TEMPORAL_REPROJECTION
|
||||
float3 historyUV = ComputeVolumeUV(ComputeCellWorldPosition(gridCoordinate, 0.5f), PrevWorldToClip);
|
||||
float3 historyUV = GetVolumeUV(GetCellPositionWS(gridCoordinate, 0.5f), PrevWorldToClip);
|
||||
float historyAlpha = HistoryWeight;
|
||||
|
||||
FLATTEN
|
||||
if (any(historyUV < 0) || any(historyUV > 1))
|
||||
{
|
||||
historyAlpha = 0;
|
||||
}
|
||||
|
||||
uint numSuperSamples = historyAlpha < .001f ? HistoryMissSuperSampleCount : 1;
|
||||
uint samplesCount = historyAlpha < 0.001f ? HistoryMissSuperSampleCount : 1;
|
||||
#else
|
||||
uint numSuperSamples = 1;
|
||||
uint samplesCount = 1;
|
||||
#endif
|
||||
|
||||
float3 L = 0;
|
||||
@@ -229,22 +217,19 @@ float4 PS_InjectLight(Quad_GS2PS input) : SV_Target0
|
||||
float lightRadiusMask = 1;
|
||||
float spotAttenuation = 1;
|
||||
bool isSpotLight = LocalLight.SpotAngles.x > -2.0f;
|
||||
|
||||
float4 scattering = 0;
|
||||
for (uint sampleIndex = 0; sampleIndex < numSuperSamples; sampleIndex++)
|
||||
for (uint sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++)
|
||||
{
|
||||
float3 cellOffset = FrameJitterOffsets[sampleIndex].xyz;
|
||||
//float cellOffset = 0.5f;
|
||||
|
||||
float3 worldPosition = ComputeCellWorldPosition(gridCoordinate, cellOffset);
|
||||
float3 cameraVector = normalize(worldPosition - GBuffer.ViewPos);
|
||||
float cellRadius = length(worldPosition - ComputeCellWorldPosition(gridCoordinate + uint3(1, 1, 1), cellOffset));
|
||||
|
||||
// Bias the inverse squared light falloff based on voxel size to prevent aliasing near the light source
|
||||
float3 positionWS = GetCellPositionWS(gridCoordinate, cellOffset);
|
||||
float3 cameraVector = normalize(positionWS - GBuffer.ViewPos);
|
||||
float cellRadius = length(positionWS - GetCellPositionWS(gridCoordinate + uint3(1, 1, 1), cellOffset));
|
||||
float distanceBias = max(cellRadius * InverseSquaredLightDistanceBiasScale, 1);
|
||||
|
||||
// Get the light attenuation
|
||||
GetRadialLightAttenuation(LocalLight, isSpotLight, worldPosition, float3(0, 0, 1), distanceBias * distanceBias, toLight, L, NoL, distanceAttenuation, lightRadiusMask, spotAttenuation);
|
||||
// Calculate the light attenuation
|
||||
GetRadialLightAttenuation(LocalLight, isSpotLight, positionWS, float3(0, 0, 1), distanceBias * distanceBias, toLight, L, NoL, distanceAttenuation, lightRadiusMask, spotAttenuation);
|
||||
float combinedAttenuation = distanceAttenuation * lightRadiusMask * spotAttenuation;
|
||||
|
||||
// Peek the shadow
|
||||
@@ -252,16 +237,14 @@ float4 PS_InjectLight(Quad_GS2PS input) : SV_Target0
|
||||
#if USE_SHADOW
|
||||
if (combinedAttenuation > 0)
|
||||
{
|
||||
shadowFactor = ComputeVolumeShadowing(worldPosition, isSpotLight);
|
||||
shadowFactor = ComputeVolumeShadowing(positionWS, isSpotLight);
|
||||
}
|
||||
#endif
|
||||
|
||||
scattering.rgb += LocalLight.Color * (PhaseFunction(PhaseG, dot(L, -cameraVector)) * combinedAttenuation * shadowFactor * LocalLightScatteringIntensity);
|
||||
scattering.rgb += LocalLight.Color * (GetPhase(PhaseG, dot(L, -cameraVector)) * combinedAttenuation * shadowFactor * LocalLightScatteringIntensity);
|
||||
}
|
||||
|
||||
// Normalize
|
||||
scattering.rgb /= (float)numSuperSamples;
|
||||
|
||||
scattering.rgb /= (float)samplesCount;
|
||||
return scattering;
|
||||
}
|
||||
|
||||
@@ -280,7 +263,7 @@ void CS_Initialize(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_Dispa
|
||||
|
||||
// Center of the voxel
|
||||
float voxelOffset = 0.5f;
|
||||
float3 worldPosition = ComputeCellWorldPosition(gridCoordinate, voxelOffset);
|
||||
float3 positionWS = GetCellPositionWS(gridCoordinate, voxelOffset);
|
||||
|
||||
// Unpack the fog parameters (packing done in C++ ExponentialHeightFog::GetVolumetricFogOptions)
|
||||
float fogDensity = FogParameters.x;
|
||||
@@ -288,7 +271,7 @@ void CS_Initialize(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_Dispa
|
||||
float fogHeightFalloff = FogParameters.z;
|
||||
|
||||
// Calculate the global fog density that matches the exponential height fog density
|
||||
float globalDensity = fogDensity * exp2(-fogHeightFalloff * (worldPosition.y - fogHeight));
|
||||
float globalDensity = fogDensity * exp2(-fogHeightFalloff * (positionWS.y - fogHeight));
|
||||
float matchFactor = 0.24f;
|
||||
float extinction = max(globalDensity * GlobalExtinctionScale * matchFactor, 0);
|
||||
|
||||
@@ -326,7 +309,7 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
|
||||
uint numSuperSamples = 1;
|
||||
|
||||
#if USE_TEMPORAL_REPROJECTION
|
||||
float3 historyUV = ComputeVolumeUV(ComputeCellWorldPosition(gridCoordinate, 0.5f), PrevWorldToClip);
|
||||
float3 historyUV = GetVolumeUV(GetCellPositionWS(gridCoordinate, 0.5f), PrevWorldToClip);
|
||||
float historyAlpha = HistoryWeight;
|
||||
|
||||
// Discard history if it lays outside the current view
|
||||
@@ -347,8 +330,8 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
|
||||
//float3 cellOffset = 0.5f;
|
||||
|
||||
float sceneDepth;
|
||||
float3 worldPosition = ComputeCellWorldPosition(gridCoordinate, cellOffset, sceneDepth);
|
||||
float3 cameraVector = worldPosition - GBuffer.ViewPos;
|
||||
float3 positionWS = GetCellPositionWS(gridCoordinate, cellOffset, sceneDepth);
|
||||
float3 cameraVector = positionWS - GBuffer.ViewPos;
|
||||
float cameraVectorLength = length(cameraVector);
|
||||
float3 cameraVectorNormalized = cameraVector / cameraVectorLength;
|
||||
|
||||
@@ -360,10 +343,10 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
|
||||
float shadow = 1;
|
||||
if (DirectionalLightShadow.NumCascades > 0)
|
||||
{
|
||||
shadow = SampleShadow(DirectionalLight, DirectionalLightShadow, ShadowMapCSM, worldPosition, cameraVectorLength);
|
||||
shadow = SampleShadow(DirectionalLight, DirectionalLightShadow, ShadowMapCSM, positionWS, cameraVectorLength);
|
||||
}
|
||||
|
||||
lightScattering += DirectionalLight.Color * (8 * shadow * PhaseFunction(PhaseG, dot(DirectionalLight.Direction, cameraVectorNormalized)));
|
||||
lightScattering += DirectionalLight.Color * (8 * shadow * GetPhase(PhaseG, dot(DirectionalLight.Direction, cameraVectorNormalized)));
|
||||
}
|
||||
|
||||
// Sky light
|
||||
@@ -414,38 +397,30 @@ META_CS(true, FEATURE_LEVEL_SM5)
|
||||
void CS_FinalIntegration(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_DispatchThreadID, uint3 GroupThreadId : SV_GroupThreadID)
|
||||
{
|
||||
uint3 gridCoordinate = DispatchThreadId;
|
||||
|
||||
float4 accumulatedLightingAndTransmittance = float4(0, 0, 0, 1);
|
||||
float3 previousSliceWorldPosition = GBuffer.ViewPos;
|
||||
float4 acc = float4(0, 0, 0, 1);
|
||||
float3 prevPositionWS = GBuffer.ViewPos;
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < GridSizeInt.z; layerIndex++)
|
||||
{
|
||||
uint3 layerCoordinate = uint3(gridCoordinate.xy, layerIndex);
|
||||
float4 scatteringAndExtinction = LightScattering[layerCoordinate];
|
||||
|
||||
float3 layerWorldPosition = ComputeCellWorldPosition(layerCoordinate, 0.5f);
|
||||
float stepLength = length(layerWorldPosition - previousSliceWorldPosition);
|
||||
previousSliceWorldPosition = layerWorldPosition;
|
||||
|
||||
float transmittance = exp(-scatteringAndExtinction.w * stepLength);
|
||||
uint3 coords = uint3(gridCoordinate.xy, layerIndex);
|
||||
float4 scatteringExtinction = LightScattering[coords];
|
||||
float3 positionWS = GetCellPositionWS(coords, 0.5f);
|
||||
|
||||
// Ref: "Physically Based and Unified Volumetric Rendering in Frostbite"
|
||||
#define ENERGY_CONSERVING_INTEGRATION 1
|
||||
#if ENERGY_CONSERVING_INTEGRATION
|
||||
float3 scatteringIntegratedOverSlice = (scatteringAndExtinction.rgb - scatteringAndExtinction.rgb * transmittance) / max(scatteringAndExtinction.w, .00001f);
|
||||
accumulatedLightingAndTransmittance.rgb += scatteringIntegratedOverSlice * accumulatedLightingAndTransmittance.a;
|
||||
#else
|
||||
accumulatedLightingAndTransmittance.rgb += scatteringAndExtinction.rgb * accumulatedLightingAndTransmittance.a;
|
||||
#endif
|
||||
accumulatedLightingAndTransmittance.a *= transmittance;
|
||||
|
||||
float transmittance = exp(-scatteringExtinction.w * length(positionWS - prevPositionWS));
|
||||
float3 scatteringIntegratedOverSlice = (scatteringExtinction.rgb - scatteringExtinction.rgb * transmittance) / max(scatteringExtinction.w, 0.00001f);
|
||||
acc.rgb += scatteringIntegratedOverSlice * acc.a;
|
||||
acc.a *= transmittance;
|
||||
|
||||
#if DEBUG_VOXELS
|
||||
RWIntegratedLightScattering[layerCoordinate] = float4(scatteringAndExtinction.rgb, 1.0f);
|
||||
RWIntegratedLightScattering[coords] = float4(scatteringExtinction.rgb, 1.0f);
|
||||
#elif DEBUG_VOXEL_WS_POS
|
||||
RWIntegratedLightScattering[layerCoordinate] = float4(layerWorldPosition.rgb, 1.0f);
|
||||
RWIntegratedLightScattering[coords] = float4(positionWS.rgb, 1.0f);
|
||||
#else
|
||||
RWIntegratedLightScattering[layerCoordinate] = accumulatedLightingAndTransmittance;
|
||||
RWIntegratedLightScattering[coords] = acc;
|
||||
#endif
|
||||
|
||||
prevPositionWS = positionWS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
Copyright (C) 2011-2017, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://www.lz4.org
|
||||
- LZ4 source repository : https://github.com/lz4/lz4
|
||||
*/
|
||||
Vendored
+1
@@ -13,5 +13,6 @@ public class lz4 : ThirdPartyModule
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.BSD2Clause;
|
||||
LicenseFilePath = "LICENSE.txt";
|
||||
}
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Mikulas Florek
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+1
@@ -13,5 +13,6 @@ public class OpenFBX : ThirdPartyModule
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.MIT;
|
||||
LicenseFilePath = "LICENSE.txt";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2013-2014, Adswerve, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -14,6 +14,7 @@ public class UniversalAnalytics : ThirdPartyModule
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.BSD3Clause;
|
||||
LicenseFilePath = "LICENSE.txt";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
Vendored
+1
@@ -15,6 +15,7 @@ public class fmt : ThirdPartyModule
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.BSD2Clause;
|
||||
LicenseFilePath = "cppformat license.txt";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -13,5 +13,6 @@ public class meshoptimizer : ThirdPartyModule
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.MIT;
|
||||
LicenseFilePath = "LICENSE.md";
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -13,5 +13,6 @@ public class pugixml : ThirdPartyModule
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.MIT;
|
||||
LicenseFilePath = "pugixml license.txt";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ public class rapidjson : HeaderOnlyModule
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.MIT;
|
||||
LicenseFilePath = "RapidJSON license.txt";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -13,5 +13,6 @@ public class recastnavigation : ThirdPartyModule
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.zLib;
|
||||
LicenseFilePath = "License.txt";
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2018-2019 Arseny Kapoulkine
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Vendored
+1
@@ -14,6 +14,7 @@ public class volk : ThirdPartyModule
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.MIT;
|
||||
LicenseFilePath = "LICENSE.txt";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -199,9 +199,9 @@ namespace Flax.Build
|
||||
// Perform license validation
|
||||
if (LicenseType == LicenseTypes.Invalid)
|
||||
throw new Exception(string.Format("Cannot build module {0}. Third Party modules must have license type specified.", Name));
|
||||
if (LicenseType == LicenseTypes.Custom && LicenseFilePath == null)
|
||||
throw new Exception(string.Format("Cannot build module {0}. Third Party modules with Custom license must have license file specified.", Name));
|
||||
if (LicenseFilePath != null && !File.Exists(Path.Combine(FolderPath, LicenseFilePath)))
|
||||
if (LicenseFilePath == null)
|
||||
throw new Exception(string.Format("Cannot build module {0}. Third Party modules must have license file specified.", Name));
|
||||
if (!File.Exists(Path.Combine(FolderPath, LicenseFilePath)))
|
||||
throw new Exception(string.Format("Cannot build module {0}. Specified license file does not exist.", Name));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user