Skip to content

Commit

Permalink
Added an implementation of depth-weighted transparency technique from…
Browse files Browse the repository at this point in the history
… nvidia's "A Phenomenological Scattering Model for Order-Independent Transparency"

- different order independent transparency modes are selected with "cv.OITransMode"
- default is 1, for stochastic transparency
- this is just a basic implementation, very similar to the algorithm presented in the paper
- not really polished or optimised
  • Loading branch information
djewsbury committed Mar 31, 2016
1 parent 527df0f commit 13f8626
Show file tree
Hide file tree
Showing 11 changed files with 391 additions and 10 deletions.
2 changes: 1 addition & 1 deletion RenderCore/Assets/ModelCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ namespace RenderCore { namespace Assets

Config()
: _modelScaffoldCount(2000), _materialScaffoldCount(2000)
, _rendererCount(100) {}
, _rendererCount(200) {}
};

using ResChar = ::Assets::ResChar;
Expand Down
3 changes: 2 additions & 1 deletion RenderCore/Techniques/CommonBindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ namespace RenderCore { namespace Techniques
static const auto VisWireframe = 8u;
static const auto WriteTriangleIndex = 9u;
static const auto StochasticTransparency = 10u;
static const auto DepthWeightedTransparency = 11u;

static const auto Max = 11u;
static const auto Max = 12u;
};

extern const ::Assets::ResChar* DefaultPredefinedCBLayout;
Expand Down
1 change: 1 addition & 0 deletions RenderCore/Techniques/Techniques.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ namespace RenderCore { namespace Techniques
// note -- lexographically sorted!
{ u("Deferred"), unsigned(TechniqueIndex::Deferred) },
{ u("DepthOnly"), unsigned(TechniqueIndex::DepthOnly) },
{ u("DepthWeightedTransparency"), unsigned(TechniqueIndex::DepthWeightedTransparency) },
{ u("Illum"), unsigned(TechniqueIndex::Forward) },
{ u("OrderIndependentTransparency"), unsigned(TechniqueIndex::OrderIndependentTransparency) },
{ u("PrepareVegetationSpawn"), unsigned(TechniqueIndex::PrepareVegetationSpawn) },
Expand Down
169 changes: 169 additions & 0 deletions SceneEngine/DepthWeightedTransparency.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Copyright 2016 XLGAMES Inc.
//
// Distributed under the MIT License (See
// accompanying file "LICENSE" or the website
// http://www.opensource.org/licenses/mit-license.php)

#include "DepthWeightedTransparency.h"
#include "GestaltResource.h"
#include "LightingParserContext.h"
#include "SceneEngineUtils.h"
#include "../RenderCore/Metal/Format.h"
#include "../RenderCore/Metal/State.h"
#include "../RenderCore/Metal/DeviceContext.h"
#include "../RenderCore/Metal/ShaderResource.h"
#include "../RenderCore/Metal/Shader.h"
#include "../RenderCore/Techniques/ResourceBox.h"
#include "../RenderCore/Techniques/CommonResources.h"
#include "../RenderCore/Techniques/Techniques.h"
#include "../BufferUploads/IBufferUploads.h"
#include "../Assets/Assets.h"

#include "../RenderCore/DX11/Metal/IncludeDX11.h"

namespace SceneEngine
{
using namespace RenderCore;

class DepthWeightedTransparencyBox
{
public:
class Desc
{
public:
unsigned _width, _height;
Desc(unsigned width, unsigned height)
{
_width = width;
_height = height;
}
};
GestaltTypes::RTVSRV _accumulationBuffer;
GestaltTypes::RTVSRV _modulationBuffer;
GestaltTypes::RTVSRV _refractionBuffer;

Metal::BlendState _blendState;

DepthWeightedTransparencyBox(const Desc& desc);
};

DepthWeightedTransparencyBox::DepthWeightedTransparencyBox(const Desc& desc)
{
using namespace BufferUploads;
_accumulationBuffer = GestaltTypes::RTVSRV(
TextureDesc::Plain2D(desc._width, desc._height, Metal::NativeFormat::R32G32B32A32_FLOAT),
"TransAccBuffer", nullptr);
_modulationBuffer = GestaltTypes::RTVSRV(
TextureDesc::Plain2D(desc._width, desc._height, Metal::NativeFormat::R16G16B16A16_FLOAT),
"TransModulationBuffer", nullptr);
_refractionBuffer = GestaltTypes::RTVSRV(
TextureDesc::Plain2D(desc._width, desc._height, Metal::NativeFormat::R16G16B16A16_FLOAT),
"TransRefractBuffer", nullptr);

D3D11_BLEND_DESC blendStateDesc;
blendStateDesc.AlphaToCoverageEnable = false;
blendStateDesc.IndependentBlendEnable = true;
for (unsigned c=0; c<dimof(blendStateDesc.RenderTarget); ++c) {
blendStateDesc.RenderTarget[c].BlendEnable = false;
blendStateDesc.RenderTarget[c].SrcBlend = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[c].DestBlend = D3D11_BLEND_ZERO;
blendStateDesc.RenderTarget[c].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDesc.RenderTarget[c].SrcBlendAlpha = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[c].DestBlendAlpha = D3D11_BLEND_ZERO;
blendStateDesc.RenderTarget[c].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendStateDesc.RenderTarget[c].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
}

blendStateDesc.RenderTarget[0].BlendEnable = true;
blendStateDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;

blendStateDesc.RenderTarget[1].BlendEnable = true;
blendStateDesc.RenderTarget[1].SrcBlend = D3D11_BLEND_ZERO;
blendStateDesc.RenderTarget[1].DestBlend = D3D11_BLEND_INV_SRC_COLOR;
blendStateDesc.RenderTarget[1].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDesc.RenderTarget[1].SrcBlendAlpha = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[1].DestBlendAlpha = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[1].BlendOpAlpha = D3D11_BLEND_OP_ADD;

blendStateDesc.RenderTarget[2].BlendEnable = true;
blendStateDesc.RenderTarget[2].SrcBlend = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[2].DestBlend = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[2].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDesc.RenderTarget[2].SrcBlendAlpha = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[2].DestBlendAlpha = D3D11_BLEND_ONE;
blendStateDesc.RenderTarget[2].BlendOpAlpha = D3D11_BLEND_OP_ADD;

auto blendState = RenderCore::Metal::ObjectFactory().CreateBlendState(&blendStateDesc);
_blendState = Metal::BlendState(std::move(blendState));
}

void DepthWeightedTransparencyOp::PrepareFirstPass(const Metal::DepthStencilView* dsv)
{
// We need to bind the render targets and blend modes for the initial accumulation pass
// We can use a downsampled translucency buffer here -- when the loss of resolution doesn't
// matter.
Metal::ViewportDesc viewport(*_context);
auto& box = Techniques::FindCachedBox2<DepthWeightedTransparencyBox>(
unsigned(viewport.Width), unsigned(viewport.Height));

_context->Clear(box._accumulationBuffer.RTV(), Float4(0.f, 0.f, 0.f, 0.f));
_context->Clear(box._modulationBuffer.RTV(), Float4(1.f, 1.f, 1.f, 0.f));
_context->Clear(box._refractionBuffer.RTV(), Float4(0.f, 0.f, 0.f, 0.f));
_context->Bind(
MakeResourceList(
box._accumulationBuffer.RTV(),
box._modulationBuffer.RTV(),
box._refractionBuffer.RTV()), dsv);
_context->Bind(box._blendState);
_context->Bind(Techniques::CommonResources()._dssReadOnly);

_box = &box;
}

void DepthWeightedTransparencyOp::Resolve()
{
if (!_box) return;

{
SetupVertexGeneratorShader(*_context);
auto& shader = ::Assets::GetAssetDep<Metal::ShaderProgram>(
"game/xleres/basic2d.vsh:fullscreen:vs_*",
"game/xleres/forward/transparency/depthweighted.sh:resolve:ps_*");
Metal::BoundUniforms uniforms(shader);
Techniques::TechniqueContext::BindGlobalUniforms(uniforms);
uniforms.BindShaderResources(1, {"Accumulator", "Modulator", "Refraction"});
uniforms.Apply(
*_context,
_parserContext->GetGlobalUniformsStream(),
Metal::UniformsStream(
{},
{
&_box->_accumulationBuffer.SRV(),
&_box->_modulationBuffer.SRV(),
&_box->_refractionBuffer.SRV()
}));

_context->Bind(Techniques::CommonResources()._blendOneSrcAlpha);
_context->Bind(shader);
_context->Draw(4);
}
}

DepthWeightedTransparencyOp::DepthWeightedTransparencyOp(
RenderCore::Metal::DeviceContext& context,
LightingParserContext& parserContext)
: _context(&context)
, _parserContext(&parserContext)
, _box(nullptr)
{}

DepthWeightedTransparencyOp::~DepthWeightedTransparencyOp()
{}
}


35 changes: 35 additions & 0 deletions SceneEngine/DepthWeightedTransparency.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2016 XLGAMES Inc.
//
// Distributed under the MIT License (See
// accompanying file "LICENSE" or the website
// http://www.opensource.org/licenses/mit-license.php)

#pragma once

#include "../RenderCore/Metal/Forward.h"

namespace SceneEngine
{
class LightingParserContext;
class DepthWeightedTransparencyBox;

class DepthWeightedTransparencyOp
{
public:
void PrepareFirstPass(const RenderCore::Metal::DepthStencilView* dsv);
void Resolve();

DepthWeightedTransparencyOp(
RenderCore::Metal::DeviceContext& context,
LightingParserContext& parserContext);
~DepthWeightedTransparencyOp();

DepthWeightedTransparencyOp(const DepthWeightedTransparencyOp&) = delete;
DepthWeightedTransparencyOp& operator=(const DepthWeightedTransparencyOp&) = delete;
protected:
DepthWeightedTransparencyBox* _box;
RenderCore::Metal::DeviceContext* _context;
LightingParserContext* _parserContext;
};
}

46 changes: 38 additions & 8 deletions SceneEngine/LightingParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "RefractionsBuffer.h"
#include "OrderIndependentTransparency.h"
#include "StochasticTransparency.h"
#include "DepthWeightedTransparency.h"
#include "Sky.h"
#include "SunFlare.h"
#include "Rain.h"
Expand Down Expand Up @@ -290,6 +291,8 @@ namespace SceneEngine
Metal::NativeFormat::Enum resolveFormat)
{
// todo -- support custom resolve (tone-map aware)
// See AMD post on this topic:
// http://gpuopen.com/optimized-reversible-tonemapper-for-resolve/
context.GetUnderlying()->ResolveSubresource(
destinationTexture, D3D11CalcSubresource(0,0,0),
sourceTexture, D3D11CalcSubresource(0,0,0),
Expand Down Expand Up @@ -562,10 +565,14 @@ namespace SceneEngine

//////////////////////////////////////////////////////////////////////////////////////////////////
const bool hasOITrans = BatchHasContent(parserContext, SPS::BatchFilter::OITransparent);
const auto enabledSortedTrans =
Tweakable("UseOITrans", false)
&& (mainTargets._desc._sampling._sampleCount <= 1)
&& hasOITrans;

enum OIMode { Unordered, Stochastic, DepthWeighted, SortedRef } oiMode;
switch (Tweakable("OITransMode", 1)) {
case 1: oiMode = OIMode::Stochastic; break;
case 2: oiMode = OIMode::DepthWeighted; break;
case 3: oiMode = (mainTargets._desc._sampling._sampleCount <= 1) ? OIMode::SortedRef : OIMode::Stochastic; break;
default: oiMode = OIMode::Unordered; break;
}

// When enable OI transparency is enabled, we do a pre-depth pass
// on all transparent geometry.
Expand All @@ -577,7 +584,7 @@ namespace SceneEngine
//
// The depth pre-pass helps a little bit for stochastic transparency,
// but it's not clear that it helps overall.
if (enabledSortedTrans && Tweakable("TransPrePass", false)) {
if (oiMode == OIMode::SortedRef && Tweakable("TransPrePass", false)) {
StateSetChangeMarker marker(parserContext, GetStateSetResolvers()._depthOnly);
ExecuteScene(
context, parserContext, SPS::BatchFilter::TransparentPreDepth,
Expand All @@ -594,8 +601,8 @@ namespace SceneEngine
}

if (hasOITrans) {
StateSetChangeMarker marker(parserContext, GetStateSetResolvers()._depthOnly);
if (enabledSortedTrans) {
if (oiMode == OIMode::SortedRef) {
StateSetChangeMarker marker(parserContext, GetStateSetResolvers()._depthOnly);
auto duplicatedDepthBuffer = BuildDuplicatedDepthBuffer(&metalContext, mainTargets._msaaDepthBufferTexture.get());
auto* transTargets = OrderIndependentTransparency_Prepare(metalContext, parserContext, duplicatedDepthBuffer);

Expand All @@ -606,7 +613,8 @@ namespace SceneEngine

// note; we use the main depth buffer for this call (not the duplicated buffer)
OrderIndependentTransparency_Resolve(metalContext, parserContext, *transTargets, mainTargets._msaaDepthBufferSRV);
} else if (Tweakable("UseStochasticTrans", true)) {
} else if (oiMode == OIMode::Stochastic) {
StateSetChangeMarker marker(parserContext, GetStateSetResolvers()._depthOnly);
SavedTargets savedTargets(metalContext);
auto resetMarker = savedTargets.MakeResetMarker(metalContext);

Expand All @@ -632,6 +640,28 @@ namespace SceneEngine

resetMarker = SavedTargets::ResetMarker(); // back to normal targets now
stochTransOp.Resolve();
} else if (oiMode == OIMode::DepthWeighted) {
StateSetChangeMarker marker(parserContext, GetStateSetResolvers()._depthOnly);
SavedTargets savedTargets(metalContext);
auto resetMarker = savedTargets.MakeResetMarker(metalContext);

DepthWeightedTransparencyOp transOp(metalContext, parserContext);

Metal::DepthStencilView dsv(savedTargets.GetDepthStencilView());
transOp.PrepareFirstPass(&dsv);
ExecuteScene(
context, parserContext, SPS::BatchFilter::OITransparent,
preparedScene,
TechniqueIndex_DepthWeightedTransparency, L"MainScene-PostGBuffer-OI");

resetMarker = SavedTargets::ResetMarker(); // back to normal targets now
transOp.Resolve();
} else if (oiMode == OIMode::Unordered) {
StateSetChangeMarker marker(parserContext, GetStateSetResolvers()._forward);
ExecuteScene(
context, parserContext, SPS::BatchFilter::OITransparent,
preparedScene,
TechniqueIndex_General, L"MainScene-PostGBuffer-OI");
}
}

Expand Down
2 changes: 2 additions & 0 deletions SceneEngine/Project/SceneEngine.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@
<ItemGroup>
<ClCompile Include="..\AmbientOcclusion.cpp" />
<ClCompile Include="..\CloudsForm.cpp" />
<ClCompile Include="..\DepthWeightedTransparency.cpp" />
<ClCompile Include="..\DualContour.cpp" />
<ClCompile Include="..\DualContourRender.cpp" />
<ClCompile Include="..\DynamicImposters.cpp" />
Expand Down Expand Up @@ -259,6 +260,7 @@
<ItemGroup>
<ClInclude Include="..\AmbientOcclusion.h" />
<ClInclude Include="..\CloudsForm.h" />
<ClInclude Include="..\DepthWeightedTransparency.h" />
<ClInclude Include="..\Documentation.h" />
<ClInclude Include="..\DualContour.h" />
<ClInclude Include="..\DualContourRender.h" />
Expand Down
6 changes: 6 additions & 0 deletions SceneEngine/Project/SceneEngine.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@
<Filter>Lighting And Processing</Filter>
</ClCompile>
<ClCompile Include="..\PreparedScene.cpp" />
<ClCompile Include="..\DepthWeightedTransparency.cpp">
<Filter>Lighting And Processing</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\AmbientOcclusion.h">
Expand Down Expand Up @@ -323,6 +326,9 @@
</ClInclude>
<ClInclude Include="..\PreparedScene.h" />
<ClInclude Include="..\ShaderLightDesc.h" />
<ClInclude Include="..\DepthWeightedTransparency.h">
<Filter>Lighting And Processing</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Lighting And Processing">
Expand Down
1 change: 1 addition & 0 deletions SceneEngine/SceneEngineUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ namespace SceneEngine
static const auto TechniqueIndex_OrderIndependentTransparency = RenderCore::Techniques::TechniqueIndex::OrderIndependentTransparency;
static const auto TechniqueIndex_RTShadowGen = RenderCore::Techniques::TechniqueIndex::WriteTriangleIndex;
static const auto TechniqueIndex_StochasticTransparency = RenderCore::Techniques::TechniqueIndex::StochasticTransparency;
static const auto TechniqueIndex_DepthWeightedTransparency = RenderCore::Techniques::TechniqueIndex::DepthWeightedTransparency;

typedef intrusive_ptr<ID3D::Resource> ResourcePtr;
ResourcePtr CreateResourceImmediate(const BufferUploads::BufferDesc& desc);
Expand Down
Loading

0 comments on commit 13f8626

Please sign in to comment.