You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/XRenderD3D9/D3DVolumetricFog.cpp

3086 lines
125 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "D3DVolumetricFog.h"
#include "DriverD3D.h"
#include "D3DPostProcess.h"
#include "CREFogVolume.h"
#define ENABLE_VOLFOG_TEX_FORMAT_RGBA16F
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
#define D3DVOLUMETRICFOG_CPP_SECTION_1 1
#endif
namespace vfInternal
{
static const uint32 MaxNumTileLights = 255;
static const uint32 MaxNumFogVolumes = 64;
static const float ThresholdLengthGlobalProbe = 1.732f * (1000.0f * 0.5f);
enum EVolumeVolumeTypes
{
tlVolumeSphere = 1,
tlVolumeCone = 2,
tlVolumeOBB = 3,
tlVolumeSun = 4,
};
enum EVolumeLightTypes
{
tlTypeProbe = 1,
tlTypeAmbientPoint = 2,
tlTypeAmbientProjector = 3,
tlTypeAmbientArea = 4,
tlTypeRegularPoint = 5,
tlTypeRegularProjector = 6,
tlTypeRegularPointFace = 7,
tlTypeRegularArea = 8,
tlTypeSun = 9,
};
struct SVolumeLightCullInfo
{
uint32 volumeType;
uint32 miscFlag;
Vec2 depthBounds;
Vec4 posRad;
Vec4 volumeParams0;
Vec4 volumeParams1;
Vec4 volumeParams2;
}; // 80 bytes
struct SVolumeLightShadeInfo
{
uint32 lightType;
uint32 resIndex;
uint32 shadowMaskIndex;
uint16 stencilID0;
uint16 stencilID1;
Vec4 posRad;
Vec2 attenuationParams;
Vec2 shadowParams;
Vec4 color;
Vec4 shadowChannelIndex;
Matrix44 projectorMatrix;
Matrix44 shadowMatrix;
}; // 208 bytes
struct SFogVolumeCullInfo
{
Vec4 posRad;
Vec4 volumeParams0;
Vec4 volumeParams1;
Vec4 volumeParams2;
};
struct SFogVolumeInjectInfo
{
uint32 miscFlag; // 1: volumeType, 8: stencilRef, 1: affectThisAreaOnly, 22: reserved
Vec3 fogColor;
float globalDensity;
Vec3 fogVolumePos;
Vec3 heightFalloffBasePoint;
float invSoftEdgeLerp;
Vec3 heightFallOffDirScaled;
float densityOffset;
Vec4 rampParams;
Vec3 windOffset;
float noiseElapsedTime;
Vec3 noiseSpatialFrequency;
float noiseScale;
Vec3 eyePosInOS;
float noiseOffset;
Matrix34 worldToObjMatrix;
};
int GetVolumeTexDepth()
{
int d = CRenderer::CV_r_VolumetricFogTexDepth;
d = (d < 4) ? 4 : d;
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION D3DVOLUMETRICFOG_CPP_SECTION_1
#include AZ_RESTRICTED_FILE(D3DVolumetricFog_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
d = (d > 255) ? 255 : d;// this limitation due to the limitation of CTexture::CreateTextureArray.
#endif
int f = d % 4;
d = (f > 0) ? d - f : d;// depth should be the multiples of 4.
return d;
}
int GetVolumeTexSize(int size, int scale)
{
scale = max(scale, 2);
return (size / scale) + ((size % scale) > 0 ? 1 : 0);
}
AABB RotateAABB(const AABB& aabb, const Matrix33& mat)
{
Matrix33 matAbs;
matAbs.m00 = fabs_tpl(mat.m00);
matAbs.m01 = fabs_tpl(mat.m01);
matAbs.m02 = fabs_tpl(mat.m02);
matAbs.m10 = fabs_tpl(mat.m10);
matAbs.m11 = fabs_tpl(mat.m11);
matAbs.m12 = fabs_tpl(mat.m12);
matAbs.m20 = fabs_tpl(mat.m20);
matAbs.m21 = fabs_tpl(mat.m21);
matAbs.m22 = fabs_tpl(mat.m22);
Vec3 sz = ((aabb.max - aabb.min) * 0.5f) * matAbs;
Vec3 pos = ((aabb.max + aabb.min) * 0.5f) * mat;
return AABB(pos - sz, pos + sz);
}
}
CVolumetricFog::CVolumetricFog()
{
STATIC_ASSERT(MaxFrameNum >= MAX_GPU_NUM, "MaxFrameNum must be more than or equal to MAX_GPU_NUM.");
for (int i = 0; i < MaxFrameNum; ++i)
{
m_viewProj[i].SetIdentity();
}
m_InscatteringVolume = NULL;
m_fogInscatteringVolume[0] = NULL;
m_fogInscatteringVolume[1] = NULL;
m_MaxDepth = NULL;
m_MaxDepthTemp = NULL;
m_ClipVolumeDSVArray = NULL;
m_fogDensityVolume[0] = NULL;
m_fogDensityVolume[1] = NULL;
for (int i = 0; i < 3; ++i)
{
m_downscaledShadow[i] = NULL;
}
m_downscaledShadowTemp = NULL;
m_globalEnvProveTex0 = NULL;
m_globalEnvProveTex1 = NULL;
m_nTexStateTriLinear = -1;
m_nTexStateCompare = -1;
m_nTexStatePoint = -1;
m_Cleared = MaxFrameNum;
m_Destroyed = MaxFrameNum;
m_numTileLights = 0;
m_numFogVolumes = 0;
m_frameID = -1;
m_tick = 0;
m_ReverseDepthMode = 1;
m_raymarchDistance = 0.0f;
m_globalEnvProbeParam0 = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
m_globalEnvProbeParam1 = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
for (int j = 0; j < MAX_REND_RECURSION_LEVELS; ++j)
{
for (int k = 0; k < MaxNumFogVolumeType; ++k)
{
m_fogVolumeInfoArray[i][j][k].Reserve(vfInternal::MaxNumFogVolumes);
}
}
}
}
void CVolumetricFog::CreateResources()
{
static const ICVar* pCVarVolumetricFog = NULL;
if (!pCVarVolumetricFog)
{
pCVarVolumetricFog = gEnv->pConsole->GetCVar("e_VolumetricFog");
}
if (!pCVarVolumetricFog || pCVarVolumetricFog->GetIVal() == 0)
{
return;
}
// downscaled shadow maps
ETEX_Format shadowFormat = eTF_D32F;
static const ICVar* pCVarShadowMaxTexRes = NULL;
if (!pCVarShadowMaxTexRes)
{
pCVarShadowMaxTexRes = gEnv->pConsole->GetCVar("e_ShadowsMaxTexRes");
}
int widthShadowMap = 0;
int widthShadowMapTemp = 0;
if (pCVarShadowMaxTexRes)
{
widthShadowMapTemp = max(pCVarShadowMaxTexRes->GetIVal(), 32);//this restriction is same as it in CD3D9Renderer::PrepareShadowGenForFrustum.
switch (CRenderer::CV_r_VolumetricFogDownscaledSunShadowRatio)
{
case 0:
widthShadowMapTemp /= 4;
widthShadowMap = widthShadowMapTemp;
break;
case 1:
widthShadowMapTemp /= 4;
widthShadowMap = widthShadowMapTemp / 2;
break;
case 2:
widthShadowMapTemp /= 4;
widthShadowMap = widthShadowMapTemp / 4;
break;
default:
widthShadowMapTemp /= 4;
widthShadowMap = widthShadowMapTemp / 4;
break;
}
}
// view frustum aligned volume texture
int width = vfInternal::GetVolumeTexSize(gRenDev->GetWidth(), CRenderer::CV_r_VolumetricFogTexScale);
int height = vfInternal::GetVolumeTexSize(gRenDev->GetHeight(), CRenderer::CV_r_VolumetricFogTexScale);
int depth = vfInternal::GetVolumeTexDepth();
#ifdef ENABLE_VOLFOG_TEX_FORMAT_RGBA16F
ETEX_Format fmt = eTF_R16G16B16A16F;
#else
ETEX_Format fmt = eTF_R11G11B10F;
#endif
ETEX_Format fmtDensityColor = eTF_R11G11B10F;
ETEX_Format fmtDensity = eTF_R16F;
bool validVolumeTexture = m_InscatteringVolume
&& (m_InscatteringVolume->GetWidth() == width)
&& (m_InscatteringVolume->GetHeight() == height)
&& (m_InscatteringVolume->GetDepth() == depth)
&& (m_InscatteringVolume->GetDstFormat() == fmt)
&& CTexture::s_ptexVolumetricFogDensityColor
&& (CTexture::s_ptexVolumetricFogDensityColor->GetDstFormat() == fmtDensityColor);
bool validDownscaledShadowMaps = (CRenderer::CV_r_VolumetricFogDownscaledSunShadow == 0 && !m_downscaledShadow[0])
|| (CRenderer::CV_r_VolumetricFogDownscaledSunShadow != 0
&& m_downscaledShadow[0] && m_downscaledShadow[0]->GetWidth() == widthShadowMap
&& m_downscaledShadow[0]->GetDstFormat() == shadowFormat
&& ((CRenderer::CV_r_VolumetricFogDownscaledSunShadow == 1 && !m_downscaledShadow[2])
|| (CRenderer::CV_r_VolumetricFogDownscaledSunShadow != 1 && m_downscaledShadow[2])));
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
if(gcpRendD3D->IsRenderToTextureActive())
{
return;
}
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
if (validVolumeTexture && validDownscaledShadowMaps)
{
return;
}
else
{
DestroyResources(false);
}
STexState ts0(FILTER_TRILINEAR, true);
STexState ts1(FILTER_BILINEAR, true);
STexState ts2(FILTER_POINT, true);
ts1.SetComparisonFilter(true);
m_nTexStateTriLinear = CTexture::GetTexState(ts0);
m_nTexStateCompare = CTexture::GetTexState(ts1);
m_nTexStatePoint = CTexture::GetTexState(ts2);
uint32 commonFlags = FT_NOMIPS | FT_DONT_RELEASE | FT_DONT_STREAM;
assert(!m_InscatteringVolume);
if (!m_InscatteringVolume)
{
const int32 w = width;
const int32 h = height;
const int32 d = depth;
//ETEX_Format format = eTF_R8G8B8A8;
//uint32 flags = FT_NOMIPS | FT_DONT_RELEASE | FT_DONT_STREAM | FT_USAGE_UNORDERED_ACCESS | FT_USAGE_UAV_RWTEXTURE;
ETEX_Format format = fmt;
uint32 flags = commonFlags | FT_USAGE_UNORDERED_ACCESS;
m_InscatteringVolume = CTexture::CreateTextureObject("$InscatteringVolume", w, h, d, eTT_3D, flags, format);
const byte* pData[6] = {NULL};
m_InscatteringVolume->CreateDeviceTexture(pData);
if (m_InscatteringVolume->GetFlags() & FT_FAILED)
{
CryFatalError("Couldn't allocate texture.");
}
}
{
uint32 flags = commonFlags | FT_USAGE_UNORDERED_ACCESS;
assert(CTexture::s_ptexVolumetricFog);
if (CTexture::s_ptexVolumetricFog)
{
const int32 w = width;
const int32 h = height;
const int32 d = depth;
ETEX_Format format = eTF_R16G16B16A16F;
if (!CTexture::s_ptexVolumetricFog->Create3DTexture(w, h, d, 1, flags, NULL, format, format))
{
CryFatalError("Couldn't allocate texture.");
}
}
}
{
const char* tname[2] =
{
"$FogInscatteringVolume0",
"$FogInscatteringVolume1",
};
for (int i = 0; i < 2; ++i)
{
assert(!m_fogInscatteringVolume[i]);
if (!m_fogInscatteringVolume[i])
{
const int32 w = width;
const int32 h = height;
const int32 d = depth;
ETEX_Format format = fmt;
uint32 flags = commonFlags | FT_USAGE_UNORDERED_ACCESS;
m_fogInscatteringVolume[i] = CTexture::CreateTextureObject(tname[i], w, h, d, eTT_3D, flags, format);
const byte* pData[6] = {NULL};
m_fogInscatteringVolume[i]->CreateDeviceTexture(pData);
if (m_fogInscatteringVolume[i]->GetFlags() & FT_FAILED)
{
CryFatalError("Couldn't allocate texture.");
}
}
}
}
assert(!m_MaxDepth);
if (!m_MaxDepth)
{
const int32 w = width;
const int32 h = height;
ETEX_Format format = eTF_R16F;
uint32 flags = commonFlags | FT_USAGE_UNORDERED_ACCESS;
m_MaxDepth = CTexture::CreateTextureObject("$MaxDepth", w, h, 1, eTT_2D, flags, format);
const byte* pData[6] = {NULL};
m_MaxDepth->CreateDeviceTexture(pData);
if (m_MaxDepth->GetFlags() & FT_FAILED)
{
CryFatalError("Couldn't allocate texture.");
}
}
assert(!m_MaxDepthTemp);
if (!m_MaxDepthTemp)
{
const int32 w = width << 1;
const int32 h = CTexture::s_ptexZTargetScaled->GetHeight() >> 1;
ETEX_Format format = eTF_R16F;
uint32 flags = commonFlags | FT_USAGE_UNORDERED_ACCESS;
m_MaxDepthTemp = CTexture::CreateTextureObject("$MaxDepthTemp", w, h, 1, eTT_2D, flags, format);
const byte* pData[6] = {NULL};
m_MaxDepthTemp->CreateDeviceTexture(pData);
if (m_MaxDepthTemp->GetFlags() & FT_FAILED)
{
CryFatalError("Couldn't allocate texture.");
}
}
assert(!m_ClipVolumeDSVArray);
if (!m_ClipVolumeDSVArray)
{
typedef D3DDepthSurface* DSVPTR;
m_ClipVolumeDSVArray = new DSVPTR[depth];
for (int i = 0; i < depth; ++i)
{
m_ClipVolumeDSVArray[i] = NULL;
}
}
assert(CTexture::s_ptexVolumetricClipVolumeStencil);
if (CTexture::s_ptexVolumetricClipVolumeStencil)
{
const int32 w = width;
const int32 h = height;
const int32 d = depth;
ETEX_Format format = eTF_D24S8;
uint32 flags = commonFlags | FT_USAGE_DEPTHSTENCIL | FT_USAGE_RENDERTARGET;
CTexture* ptex = CTexture::CreateTextureArray("$ClipVolumeStencilVolume", eTT_2D, w, h, d, 1, flags, format);
// texture name has to exactly match the name of CTexture::s_ptexVolumetricClipVolumeStencil.
if (CTexture::s_ptexVolumetricClipVolumeStencil != ptex || CTexture::s_ptexVolumetricClipVolumeStencil->GetFlags() & FT_FAILED)
{
CryFatalError("Couldn't allocate volumetric clip volume stencil texture.");
}
// This is the code for working around that stencil readable shader resource view can't be created directly.
D3DShaderResourceView* pSRV = CTexture::s_ptexVolumetricClipVolumeStencil->GetShaderResourceView();
pSRV->Release();
D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
ZeroStruct(SRVDesc);
SRVDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
D3DTexture* pID3DTexture = CTexture::s_ptexVolumetricClipVolumeStencil->GetDevTexture()->Get2DTexture();
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
SRVDesc.Texture2DArray.FirstArraySlice = 0;
SRVDesc.Texture2DArray.ArraySize = d;
SRVDesc.Texture2DArray.MipLevels = 1;
SRVDesc.Texture2DArray.MostDetailedMip = 0;
HRESULT hr = gcpRendD3D->GetDevice().CreateShaderResourceView(pID3DTexture, &SRVDesc, &pSRV);
assert(SUCCEEDED(hr));
CTexture::s_ptexVolumetricClipVolumeStencil->SetShaderResourceView(pSRV);
// Separate DSVs need to be created because of performance issue of drawing to single DSV array.
ID3D11DepthStencilView* pDSV;
D3D11_DEPTH_STENCIL_VIEW_DESC DsvDesc;
ZeroStruct(DsvDesc);
DsvDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
DsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
DsvDesc.Texture2DArray.ArraySize = 1;
DsvDesc.Texture2DArray.MipSlice = 0;
for (int i = 0; i < d; ++i)
{
DsvDesc.Texture2DArray.FirstArraySlice = i;
pDSV = NULL;
hr = gcpRendD3D->GetDevice().CreateDepthStencilView(pID3DTexture, &DsvDesc, &pDSV);
assert(SUCCEEDED(hr));
m_ClipVolumeDSVArray[i] = pDSV;
}
}
assert(CTexture::s_ptexVolumetricFogDensityColor);
if (CTexture::s_ptexVolumetricFogDensityColor)
{
const int32 w = width;
const int32 h = height;
const int32 d = depth;
ETEX_Format format = fmtDensityColor;
uint32 flags = commonFlags | FT_USAGE_UNORDERED_ACCESS | FT_USAGE_RENDERTARGET;
CTexture::s_ptexVolumetricFogDensityColor->Invalidate(w, h, format);
if (!CTexture::s_ptexVolumetricFogDensityColor->Create3DTexture(w, h, d, 1, flags, NULL, format, format))
{
CryFatalError("Couldn't allocate texture.");
}
}
assert(CTexture::s_ptexVolumetricFogDensity);
if (CTexture::s_ptexVolumetricFogDensity)
{
const int32 w = width;
const int32 h = height;
const int32 d = depth;
ETEX_Format format = fmtDensity;
uint32 flags = commonFlags | FT_USAGE_UNORDERED_ACCESS | FT_USAGE_RENDERTARGET;
CTexture::s_ptexVolumetricFogDensity->Invalidate(w, h, format);
if (!CTexture::s_ptexVolumetricFogDensity->Create3DTexture(w, h, d, 1, flags, NULL, format, format))
{
CryFatalError("Couldn't allocate texture.");
}
}
#ifndef ENABLE_VOLFOG_TEX_FORMAT_RGBA16F
{
const char* tname[2] =
{
"$FogDensityVolume0",
"$FogDensityVolume1",
};
for (int i = 0; i < 2; ++i)
{
assert(!m_fogDensityVolume[i]);
if (!m_fogDensityVolume[i])
{
const int32 w = width;
const int32 h = height;
const int32 d = depth;
ETEX_Format format = fmtDensity;
uint32 flags = commonFlags | FT_USAGE_UNORDERED_ACCESS;
m_fogDensityVolume[i] = CTexture::CreateTextureObject(tname[i], w, h, d, eTT_3D, flags, format);
m_fogDensityVolume[i]->CreateRenderTarget(format);
if (m_fogDensityVolume[i]->GetFlags() & FT_FAILED)
{
CryFatalError("Couldn't allocate texture.");
}
}
}
}
#endif
if (CRenderer::CV_r_VolumetricFogDownscaledSunShadow != 0)
{
const char* tname[3] =
{
"$DownscaledShadowMaps0",
"$DownscaledShadowMaps1",
"$DownscaledShadowMaps2",
};
int count = (CRenderer::CV_r_VolumetricFogDownscaledSunShadow == 1) ? 2 : 3;
for (int i = 0; i < count; ++i)
{
assert(!m_downscaledShadow[i]);
if (!m_downscaledShadow[i])
{
uint32 flags = commonFlags | FT_USAGE_DEPTHSTENCIL | FT_USAGE_RENDERTARGET;
m_downscaledShadow[i] = CTexture::Create2DTexture(tname[i], widthShadowMap, widthShadowMap, 1, flags, NULL, shadowFormat, shadowFormat);
}
if (!m_downscaledShadow[i] || m_downscaledShadow[i]->GetFlags() & FT_FAILED)
{
CryFatalError("Couldn't allocate texture.");
}
}
if (CRenderer::CV_r_VolumetricFogDownscaledSunShadowRatio != 0)
{
assert(!m_downscaledShadowTemp);
if (!m_downscaledShadowTemp)
{
uint32 flags = commonFlags | FT_USAGE_DEPTHSTENCIL | FT_USAGE_RENDERTARGET;
m_downscaledShadowTemp = CTexture::Create2DTexture("$DownscaledShadowMapsTemp", widthShadowMapTemp, widthShadowMapTemp, 1, flags, NULL, shadowFormat, shadowFormat);
}
if (!m_downscaledShadowTemp || m_downscaledShadowTemp->GetFlags() & FT_FAILED)
{
CryFatalError("Couldn't allocate texture.");
}
}
}
if (!m_lightCullInfoBuf.m_pBuffer)
{
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
uint32 stride = sizeof(vfInternal::SVolumeLightCullInfo);
m_lightCullInfoBuf.Create(vfInternal::MaxNumTileLights, stride, format, DX11BUF_DYNAMIC | DX11BUF_STRUCTURED | DX11BUF_BIND_SRV, NULL);
}
if (!m_LightShadeInfoBuf.m_pBuffer)
{
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
uint32 stride = sizeof(vfInternal::SVolumeLightShadeInfo);
m_LightShadeInfoBuf.Create(vfInternal::MaxNumTileLights, stride, format, DX11BUF_DYNAMIC | DX11BUF_STRUCTURED | DX11BUF_BIND_SRV, NULL);
}
if (!m_lightGridBuf.m_pBuffer)
{
const uint32 tileSizeX = 4;
const uint32 tileSizeY = 4;
const uint32 tileSizeZ = 4;
const uint32 dispatchSizeX = (width / tileSizeX) + (width % tileSizeX > 0 ? 1 : 0);
const uint32 dispatchSizeY = (height / tileSizeY) + (height % tileSizeY > 0 ? 1 : 0);
const uint32 dispatchSizeZ = (depth / tileSizeZ) + (depth % tileSizeZ > 0 ? 1 : 0);
DXGI_FORMAT format = DXGI_FORMAT_R8_UINT;
uint32 stride = sizeof(char);
m_lightGridBuf.Create(dispatchSizeX * dispatchSizeY * dispatchSizeZ * vfInternal::MaxNumTileLights, stride, format, DX11BUF_BIND_SRV | DX11BUF_BIND_UAV, NULL);
}
if (!m_lightCountBuf.m_pBuffer)
{
const uint32 tileSizeX = 4;
const uint32 tileSizeY = 4;
const uint32 tileSizeZ = 4;
const uint32 dispatchSizeX = (width / tileSizeX) + (width % tileSizeX > 0 ? 1 : 0);
const uint32 dispatchSizeY = (height / tileSizeY) + (height % tileSizeY > 0 ? 1 : 0);
const uint32 dispatchSizeZ = (depth / tileSizeZ) + (depth % tileSizeZ > 0 ? 1 : 0);
DXGI_FORMAT format = DXGI_FORMAT_R8_UINT;
uint32 stride = sizeof(char);
m_lightCountBuf.Create(dispatchSizeX * dispatchSizeY * dispatchSizeZ, stride, format, DX11BUF_BIND_SRV | DX11BUF_BIND_UAV, NULL);
}
if (!m_fogVolumeCullInfoBuf.m_pBuffer)
{
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
uint32 stride = sizeof(vfInternal::SFogVolumeCullInfo);
m_fogVolumeCullInfoBuf.Create(vfInternal::MaxNumFogVolumes, stride, format, DX11BUF_DYNAMIC | DX11BUF_STRUCTURED | DX11BUF_BIND_SRV, NULL);
}
if (!m_fogVolumeInjectInfoBuf.m_pBuffer)
{
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
uint32 stride = sizeof(vfInternal::SFogVolumeInjectInfo);
m_fogVolumeInjectInfoBuf.Create(vfInternal::MaxNumFogVolumes, stride, format, DX11BUF_DYNAMIC | DX11BUF_STRUCTURED | DX11BUF_BIND_SRV, NULL);
}
}
void CVolumetricFog::DestroyResources(bool destroyResolutionIndependentResources)
{
assert((m_ClipVolumeDSVArray && m_InscatteringVolume) || !(m_ClipVolumeDSVArray || m_InscatteringVolume));
if (m_ClipVolumeDSVArray && m_InscatteringVolume)
{
int depth = m_InscatteringVolume->GetDepth();
for (int i = 0; i < depth; ++i)
{
if (m_ClipVolumeDSVArray[i])
{
((ID3D11DepthStencilView*)m_ClipVolumeDSVArray[i])->Release();
}
}
delete [] m_ClipVolumeDSVArray;
m_ClipVolumeDSVArray = NULL;
}
SAFE_RELEASE_FORCE(m_InscatteringVolume);
SAFE_RELEASE_FORCE(m_fogInscatteringVolume[0]);
SAFE_RELEASE_FORCE(m_fogInscatteringVolume[1]);
SAFE_RELEASE_FORCE(m_MaxDepth);
SAFE_RELEASE_FORCE(m_MaxDepthTemp);
SAFE_RELEASE_FORCE(m_fogDensityVolume[0]);
SAFE_RELEASE_FORCE(m_fogDensityVolume[1]);
for (int i = 0; i < 3; ++i)
{
SAFE_RELEASE_FORCE(m_downscaledShadow[i]);
}
SAFE_RELEASE_FORCE(m_downscaledShadowTemp);
m_lightCullInfoBuf.Release();
m_LightShadeInfoBuf.Release();
m_lightGridBuf.Release();
m_lightCountBuf.Release();
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
for (int j = 0; j < MAX_REND_RECURSION_LEVELS; ++j)
{
for (int k = 0; k < MaxNumFogVolumeType; ++k)
{
m_fogVolumeInfoArray[i][j][k].clear();
}
}
}
m_fogVolumeCullInfoBuf.Release();
m_fogVolumeInjectInfoBuf.Release();
if (destroyResolutionIndependentResources)
{
if (CTexture::s_ptexVolumetricFog)
{
CTexture::s_ptexVolumetricFog->ReleaseDeviceTexture(false);
}
if (CTexture::s_ptexVolumetricClipVolumeStencil)
{
CTexture::s_ptexVolumetricClipVolumeStencil->ReleaseDeviceTexture(false);
}
if (CTexture::s_ptexVolumetricFogDensityColor)
{
CTexture::s_ptexVolumetricFogDensityColor->ReleaseDeviceTexture(false);
}
if (CTexture::s_ptexVolumetricFogDensity)
{
CTexture::s_ptexVolumetricFogDensity->ReleaseDeviceTexture(false);
}
}
m_Cleared = MaxFrameNum;
m_Destroyed = MaxFrameNum;
m_ReverseDepthMode = CRenderer::CV_r_ReverseDepth;
}
void CVolumetricFog::Clear()
{
ClearFogVolumes();
}
void CVolumetricFog::ClearAll()
{
Clear();
m_globalEnvProbeParam0 = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
m_globalEnvProbeParam1 = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
// ClearAll() is called during shutdown and post level unload
// when we should not be rendering volumetric fog.
SAFE_RELEASE(m_globalEnvProveTex0);
SAFE_RELEASE(m_globalEnvProveTex1);
ClearAllFogVolumes();
m_Cleared = MaxFrameNum;
}
void CVolumetricFog::PrepareLightList(TArray<SRenderLight>* envProbes, TArray<SRenderLight>* ambientLights, TArray<SRenderLight>* defLights, uint32 firstShadowLight, uint32 curShadowPoolLight)
{
const ICVar* pCVarVolumetricFog = gEnv->pConsole->GetCVar("e_VolumetricFog");
if (!pCVarVolumetricFog || pCVarVolumetricFog->GetIVal() == 0)
{
return;
}
if (!IsViable())
{
return;
}
AZ_TRACE_METHOD();
CD3D9Renderer* const __restrict rd = gcpRendD3D;
CTiledShading& tdsh = rd->GetTiledShading();
// Prepare view matrix with flipped z-axis
Matrix44A matView = rd->m_ViewMatrix;
matView.m02 *= -1;
matView.m12 *= -1;
matView.m22 *= -1;
matView.m32 *= -1;
int nThreadID = rd->m_RP.m_nProcessThreadID;
int nRecurseLevel = SRendItem::m_RecurseLevel[nThreadID];
uint32 numTileLights = 0;
uint32 numRenderLights = 0;
uint32 numValidRenderLights = 0;
CTexture* texGlobalEnvProbe0 = NULL;
CTexture* texGlobalEnvProbe1 = NULL;
Vec3 colorGlobalEnvProbe0(0.0f, 0.0f, 0.0f);
Vec3 colorGlobalEnvProbe1(0.0f, 0.0f, 0.0f);
float attenuationGlobalEnvProbe0 = 0.0f;
float attenuationGlobalEnvProbe1 = 0.0f;
float maxSizeGlobalEnvProbe0 = 0.0f;
float maxSizeGlobalEnvProbe1 = 0.0f;
vfInternal::SVolumeLightCullInfo tileLightsCull[vfInternal::MaxNumTileLights];
vfInternal::SVolumeLightShadeInfo tileLightsShade[vfInternal::MaxNumTileLights];
// Reset lights
ZeroMemory(tileLightsCull, sizeof(vfInternal::SVolumeLightCullInfo) * vfInternal::MaxNumTileLights);
ZeroMemory(tileLightsShade, sizeof(vfInternal::SVolumeLightShadeInfo) * vfInternal::MaxNumTileLights);
TArray<SRenderLight>* lightLists[3] = {
CRenderer::CV_r_DeferredShadingEnvProbes ? envProbes : NULL,
CRenderer::CV_r_DeferredShadingAmbientLights ? ambientLights : NULL,
CRenderer::CV_r_DeferredShadingLights ? defLights : NULL,
};
const bool areaLights = CRenderer::CV_r_DeferredShadingAreaLights > 0; //convert from int to bool
const float minBulbSize = max(0.001f, min(2.0f, CRenderer::CV_r_VolumetricFogMinimumLightBulbSize));// limit the minimum bulb size to reduce the light flicker.
for (uint32 lightListIdx = 0; lightListIdx < 3; ++lightListIdx)
{
if (lightLists[lightListIdx] == NULL)
{
continue;
}
for (uint32 lightIdx = 0, lightListSize = lightLists[lightListIdx]->size(); lightIdx < lightListSize; ++lightIdx)
{
SRenderLight& renderLight = (*lightLists[lightListIdx])[lightIdx];
vfInternal::SVolumeLightCullInfo& lightCullInfo = tileLightsCull[numTileLights];
vfInternal::SVolumeLightShadeInfo& lightShadeInfo = tileLightsShade[numTileLights];
if ((renderLight.m_Flags & DLF_FAKE) || !(renderLight.m_Flags & DLF_VOLUMETRIC_FOG))
{
continue;
}
// Skip non-ambient area light if support is disabled
if ((renderLight.m_Flags & DLF_AREA_LIGHT) && !(renderLight.m_Flags & DLF_AMBIENT) && !areaLights)
{
continue;
}
++numRenderLights;
if (numTileLights == vfInternal::MaxNumTileLights)
{
continue; // Skip light
}
// Setup standard parameters
bool areaLightRect = (renderLight.m_Flags & DLF_AREA_LIGHT) && renderLight.m_fAreaWidth && renderLight.m_fAreaHeight && renderLight.m_fLightFrustumAngle;
float volumeSize = (lightListIdx == 0) ? renderLight.m_ProbeExtents.len() : renderLight.m_fRadius;
Vec3 pos = renderLight.GetPosition();
Vec3 worldViewPos = rd->GetViewParameters().vOrigin;
lightShadeInfo.posRad = Vec4(pos.x - worldViewPos.x, pos.y - worldViewPos.y, pos.z - worldViewPos.z, volumeSize);
Vec4 posVS = Vec4(pos, 1) * matView;
lightCullInfo.posRad = Vec4(posVS.x, posVS.y, posVS.z, volumeSize);
lightShadeInfo.attenuationParams = Vec2(areaLightRect ? (renderLight.m_fAreaWidth + renderLight.m_fAreaHeight) * 0.25f : renderLight.m_fAttenuationBulbSize, renderLight.m_fAreaHeight * 0.5f);
lightCullInfo.depthBounds = Vec2(posVS.z - volumeSize, posVS.z + volumeSize);
lightShadeInfo.color = Vec4(renderLight.m_Color.r,
renderLight.m_Color.g,
renderLight.m_Color.b,
renderLight.m_fFogRadialLobe);
lightShadeInfo.resIndex = 0;
lightShadeInfo.shadowParams = Vec2(0, 0);
lightShadeInfo.stencilID0 = renderLight.m_nStencilRef[0] + 1;
lightShadeInfo.stencilID1 = renderLight.m_nStencilRef[1] + 1;
// Environment probes
if (lightListIdx == 0)
{
lightCullInfo.volumeType = vfInternal::tlVolumeOBB;
lightShadeInfo.lightType = vfInternal::tlTypeProbe;
lightShadeInfo.resIndex = 0xFFFFFFFF;
lightShadeInfo.attenuationParams.x = renderLight.m_fProbeAttenuation;
// assigning value isn't needed because AttenuationFalloffMax is hard-coded in VolumeLighting.cfi to mitigate sharp transition between probes.
//lightShadeInfo.attenuationParams.y = max( renderLight.GetFalloffMax(), 0.001f );
lightCullInfo.miscFlag = 0;
AABB aabb = vfInternal::RotateAABB(AABB(-renderLight.m_ProbeExtents, renderLight.m_ProbeExtents), Matrix33(renderLight.m_ObjMatrix));
aabb = vfInternal::RotateAABB(aabb, Matrix33(matView));
lightCullInfo.depthBounds = Vec2(posVS.z + aabb.min.z, posVS.z + aabb.max.z);
Vec4 u0 = Vec4(renderLight.m_ObjMatrix.GetColumn0().GetNormalized(), 0) * matView;
Vec4 u1 = Vec4(renderLight.m_ObjMatrix.GetColumn1().GetNormalized(), 0) * matView;
Vec4 u2 = Vec4(renderLight.m_ObjMatrix.GetColumn2().GetNormalized(), 0) * matView;
lightCullInfo.volumeParams0 = Vec4(u0.x, u0.y, u0.z, renderLight.m_ProbeExtents.x);
lightCullInfo.volumeParams1 = Vec4(u1.x, u1.y, u1.z, renderLight.m_ProbeExtents.y);
lightCullInfo.volumeParams2 = Vec4(u2.x, u2.y, u2.z, renderLight.m_ProbeExtents.z);
lightShadeInfo.projectorMatrix.SetRow4(0, Vec4(renderLight.m_ObjMatrix.GetColumn0().GetNormalized() / renderLight.m_ProbeExtents.x, 0));
lightShadeInfo.projectorMatrix.SetRow4(1, Vec4(renderLight.m_ObjMatrix.GetColumn1().GetNormalized() / renderLight.m_ProbeExtents.y, 0));
lightShadeInfo.projectorMatrix.SetRow4(2, Vec4(renderLight.m_ObjMatrix.GetColumn2().GetNormalized() / renderLight.m_ProbeExtents.z, 0));
Vec3 boxProxyMin(-1000000, -1000000, -1000000);
Vec3 boxProxyMax(1000000, 1000000, 1000000);
if (renderLight.m_Flags & DLF_BOX_PROJECTED_CM)
{
boxProxyMin = Vec3(-renderLight.m_fBoxLength * 0.5f, -renderLight.m_fBoxWidth * 0.5f, -renderLight.m_fBoxHeight * 0.5f);
boxProxyMax = Vec3(renderLight.m_fBoxLength * 0.5f, renderLight.m_fBoxWidth * 0.5f, renderLight.m_fBoxHeight * 0.5f);
}
lightShadeInfo.shadowMatrix.SetRow4(0, Vec4(boxProxyMin, 0));
lightShadeInfo.shadowMatrix.SetRow4(1, Vec4(boxProxyMax, 0));
int arrayIndex = tdsh.InsertTextureToSpecularProbeAtlas((CTexture*)renderLight.GetSpecularCubemap(), -1);
if (arrayIndex >= 0)
{
if (tdsh.InsertTextureToDiffuseProbeAtlas((CTexture*)renderLight.GetDiffuseCubemap(), arrayIndex) >= 0)
{
lightShadeInfo.resIndex = arrayIndex;
}
else
{
continue; // Skip light
}
}
else
{
continue; // Skip light
}
// Determine the global env probe for lighting analytical volumetric fog if we have it in the scene.
// Enough big(more than 1000 meters), the biggest and the second biggest including camera position are selected.
if (volumeSize >= vfInternal::ThresholdLengthGlobalProbe &&
(volumeSize > maxSizeGlobalEnvProbe0 || volumeSize > maxSizeGlobalEnvProbe1))
{
Vec3 vLightPos = renderLight.GetPosition();
Vec3 vCenterRel = worldViewPos - vLightPos;
if (vCenterRel.dot(vCenterRel) <= volumeSize * volumeSize)
{
Vec3 vCenterOBBSpace;
vCenterOBBSpace.x = renderLight.m_ObjMatrix.GetColumn0().GetNormalized().dot(vCenterRel);
vCenterOBBSpace.y = renderLight.m_ObjMatrix.GetColumn1().GetNormalized().dot(vCenterRel);
vCenterOBBSpace.z = renderLight.m_ObjMatrix.GetColumn2().GetNormalized().dot(vCenterRel);
// Check if camera position is within probe OBB
Vec3 vProbeExtents = renderLight.m_ProbeExtents;
if (fabs(vCenterOBBSpace.x) < vProbeExtents.x && fabs(vCenterOBBSpace.y) < vProbeExtents.y && fabs(vCenterOBBSpace.z) < vProbeExtents.z)
{
Vec3 probePos;
probePos.x = vCenterOBBSpace.x / vProbeExtents.x;
probePos.y = vCenterOBBSpace.y / vProbeExtents.y;
probePos.z = vCenterOBBSpace.z / vProbeExtents.z;
Vec3 pos2 = probePos.CompMul(probePos);
Vec3 t;
t.x = sqrt(1.0f - 0.5f * pos2.y - 0.5f * pos2.z + 0.333f * pos2.y * pos2.z);
t.y = sqrt(1.0f - 0.5f * pos2.z - 0.5f * pos2.x + 0.333f * pos2.z * pos2.x);
t.z = sqrt(1.0f - 0.5f * pos2.x - 0.5f * pos2.y + 0.333f * pos2.x * pos2.y);
probePos = probePos.CompMul(t);
float falloff = max(0.0f, min(1.0f, 1.0f + probePos.Dot(-probePos)));
const static float AttenuationFalloffMax = 0.2f;
falloff = min(1.0f, falloff / max(renderLight.GetFalloffMax(), AttenuationFalloffMax));
// This globalEnvProbe stuff has not been tested since the introduction of m_fProbeAttenuation
// because the feature is dead at this time; CVolumetricFog::Clear() gets called before m_globalEnvProbeParam0/1
// and m_globalEnvProveTex0/1 are copied to the GPU. I updated the code to use m_fProbeAttenuation as best I could,
// but can't be certain that the final result will be correct if/when globalEnvProbe functionality is restored. (9/21/2017)
float attenuation = falloff * falloff * (3.0f - 2.0f * falloff) * renderLight.m_fProbeAttenuation;
if (renderLight.m_fProbeAttenuation > 0)
{
if (volumeSize > maxSizeGlobalEnvProbe0)
{
maxSizeGlobalEnvProbe1 = maxSizeGlobalEnvProbe0;
texGlobalEnvProbe1 = texGlobalEnvProbe0;
colorGlobalEnvProbe1 = colorGlobalEnvProbe0;
attenuationGlobalEnvProbe1 = attenuationGlobalEnvProbe0;
maxSizeGlobalEnvProbe0 = volumeSize;
texGlobalEnvProbe0 = (CTexture*)renderLight.GetDiffuseCubemap();
colorGlobalEnvProbe0 = Vec3(lightShadeInfo.color);
attenuationGlobalEnvProbe0 = attenuation;
}
else if (volumeSize > maxSizeGlobalEnvProbe1)
{
maxSizeGlobalEnvProbe1 = volumeSize;
texGlobalEnvProbe1 = (CTexture*)renderLight.GetDiffuseCubemap();
colorGlobalEnvProbe1 = Vec3(lightShadeInfo.color);
attenuationGlobalEnvProbe1 = attenuation;
}
}
}
}
}
}
// Regular and ambient lights
else
{
const float sqrt_2 = 1.414214f; // Scale for cone so that it's base encloses a pyramid base
const bool ambientLight = (lightListIdx == 1);
lightCullInfo.volumeType = vfInternal::tlVolumeSphere;
lightShadeInfo.lightType = ambientLight ? vfInternal::tlTypeAmbientPoint : vfInternal::tlTypeRegularPoint;
lightCullInfo.miscFlag = 0;
if (!ambientLight)
{
lightShadeInfo.attenuationParams.x = max(lightShadeInfo.attenuationParams.x, minBulbSize);
// Adjust light intensity so that the intended brightness is reached 1 meter from the light's surface
// Solve I * 1 / (1 + d/lightsize)^2 = 1
float intensityMul = 1.0f + 1.0f / lightShadeInfo.attenuationParams.x;
intensityMul *= intensityMul;
lightShadeInfo.color.x *= intensityMul;
lightShadeInfo.color.y *= intensityMul;
lightShadeInfo.color.z *= intensityMul;
}
// Handle projectors
if (renderLight.m_Flags & DLF_PROJECT)
{
lightCullInfo.volumeType = vfInternal::tlVolumeCone;
lightShadeInfo.lightType = ambientLight ? vfInternal::tlTypeAmbientProjector : vfInternal::tlTypeRegularProjector;
lightShadeInfo.resIndex = 0xFFFFFFFF;
lightCullInfo.miscFlag = 0;
int arrayIndex = tdsh.InsertTextureToSpotTexAtlas((CTexture*)renderLight.m_pLightImage, -1);
if (arrayIndex >= 0)
{
lightShadeInfo.resIndex = (uint32)arrayIndex;
}
else
{
continue; // Skip light
}
// Prevent culling errors for frustums with large FOVs by slightly enlarging the frustum
const float frustumAngleDelta = renderLight.m_fLightFrustumAngle > 50 ? 7.5f : 0.0f;
Matrix34 objMat = renderLight.m_ObjMatrix;
objMat.m03 = objMat.m13 = objMat.m23 = 0; // Remove translation
Vec3 lightDir = objMat * Vec3(-1, 0, 0);
lightCullInfo.volumeParams0 = Vec4(lightDir.x, lightDir.y, lightDir.z, 0) * matView;
lightCullInfo.volumeParams0.w = renderLight.m_fRadius * tanf(DEG2RAD(min(renderLight.m_fLightFrustumAngle + frustumAngleDelta, 89.9f))) * sqrt_2;
Vec3 coneTip = Vec3(lightCullInfo.posRad.x, lightCullInfo.posRad.y, lightCullInfo.posRad.z);
Vec3 coneDir = Vec3(-lightCullInfo.volumeParams0.x, -lightCullInfo.volumeParams0.y, -lightCullInfo.volumeParams0.z);
AABB coneBounds = AABB::CreateAABBfromCone(Cone(coneTip, coneDir, renderLight.m_fRadius, lightCullInfo.volumeParams0.w));
lightCullInfo.depthBounds = Vec2(coneBounds.min.z, coneBounds.max.z);
Matrix44A projMatT;
CShadowUtils::GetProjectiveTexGen(&renderLight, 0, &projMatT);
// Translate into camera space
projMatT.Transpose();
const Vec4 vEye(rd->GetViewParameters().vOrigin, 0.0f);
Vec4 vecTranslation(vEye.Dot((Vec4&)projMatT.m00), vEye.Dot((Vec4&)projMatT.m10), vEye.Dot((Vec4&)projMatT.m20), vEye.Dot((Vec4&)projMatT.m30));
projMatT.m03 += vecTranslation.x;
projMatT.m13 += vecTranslation.y;
projMatT.m23 += vecTranslation.z;
projMatT.m33 += vecTranslation.w;
lightShadeInfo.projectorMatrix = projMatT;
}
// Handle rectangular area lights
if (areaLightRect)
{
lightCullInfo.volumeType = vfInternal::tlVolumeOBB;
lightShadeInfo.lightType = ambientLight ? vfInternal::tlTypeAmbientArea : vfInternal::tlTypeRegularArea;
lightCullInfo.miscFlag = 0;
float expensionRadius = renderLight.m_fRadius * 1.08f;
Vec3 scale(expensionRadius, expensionRadius, expensionRadius);
Matrix34 areaLightMat = CShadowUtils::GetAreaLightMatrix(&renderLight, scale);
Vec4 u0 = Vec4(areaLightMat.GetColumn0().GetNormalized(), 0) * matView;
Vec4 u1 = Vec4(areaLightMat.GetColumn1().GetNormalized(), 0) * matView;
Vec4 u2 = Vec4(areaLightMat.GetColumn2().GetNormalized(), 0) * matView;
lightCullInfo.volumeParams0 = Vec4(u0.x, u0.y, u0.z, areaLightMat.GetColumn0().GetLength() * 0.5f);
lightCullInfo.volumeParams1 = Vec4(u1.x, u1.y, u1.z, areaLightMat.GetColumn1().GetLength() * 0.5f);
lightCullInfo.volumeParams2 = Vec4(u2.x, u2.y, u2.z, areaLightMat.GetColumn2().GetLength() * 0.5f);
float volumeExtent = renderLight.m_fRadius + max(renderLight.m_fAreaWidth, renderLight.m_fAreaHeight);
lightCullInfo.depthBounds = Vec2(posVS.z - volumeExtent, posVS.z + volumeExtent);
float areaFov = renderLight.m_fLightFrustumAngle * 2.0f;
if (renderLight.m_Flags & DLF_CASTSHADOW_MAPS)
{
areaFov = min(areaFov, 135.0f); // Shadow can only cover ~135 degree FOV without looking bad, so we clamp the FOV to hide shadow clipping
}
const float cosAngle = cosf(areaFov * (gf_PI / 360.0f));
Matrix44 areaLightParams;
areaLightParams.SetRow4(0, Vec4(renderLight.m_ObjMatrix.GetColumn0().GetNormalized(), 1.0f));
areaLightParams.SetRow4(1, Vec4(renderLight.m_ObjMatrix.GetColumn1().GetNormalized(), 1.0f));
areaLightParams.SetRow4(2, Vec4(renderLight.m_ObjMatrix.GetColumn2().GetNormalized(), 1.0f));
areaLightParams.SetRow4(3, Vec4(renderLight.m_fAreaWidth * 0.5f, renderLight.m_fAreaHeight * 0.5f, 0, cosAngle));
lightShadeInfo.projectorMatrix = areaLightParams;
}
// Handle shadow casters
if (!ambientLight && lightIdx >= firstShadowLight && lightIdx < curShadowPoolLight)
{
int numDLights = rd->m_RP.m_DLights[nThreadID][nRecurseLevel].size();
int frustumIdx = lightIdx + numDLights;
int startIdx = SRendItem::m_StartFrust[nThreadID][frustumIdx];
int endIdx = SRendItem::m_EndFrust[nThreadID][frustumIdx];
if (endIdx > startIdx && nRecurseLevel < (int)rd->m_RP.m_SMFrustums[nThreadID]->size())
{
ShadowMapFrustum& firstFrustum = rd->m_RP.m_SMFrustums[nThreadID][nRecurseLevel][startIdx];
assert (firstFrustum.bUseShadowsPool);
int numSides = firstFrustum.bOmniDirectionalShadow ? 6 : 1;
float kernelSize = firstFrustum.bOmniDirectionalShadow ? 2.5f : 1.5f;
if (numTileLights + numSides > vfInternal::MaxNumTileLights)
{
continue; // Skip light
}
static ICVar* pShadowAtlasResCVar = iConsole->GetCVar("e_ShadowsPoolSize");
const Vec2 shadowParams = Vec2(kernelSize * ((float)firstFrustum.nTexSize / (float)pShadowAtlasResCVar->GetIVal()), firstFrustum.fDepthConstBias);
const Vec3 cubeDirs[6] = { Vec3(-1, 0, 0), Vec3(1, 0, 0), Vec3(0, -1, 0), Vec3(0, 1, 0), Vec3(0, 0, -1), Vec3(0, 0, 1) };
for (int side = 0; side < numSides; ++side)
{
rd->ConfigShadowTexgen(0, &firstFrustum, side);
Matrix44A shadowMat = rd->m_TempMatrices[0][0];
// Translate into camera space
const Vec4 vEye(rd->GetViewParameters().vOrigin, 0.0f);
Vec4 vecTranslation(vEye.Dot((Vec4&)shadowMat.m00), vEye.Dot((Vec4&)shadowMat.m10), vEye.Dot((Vec4&)shadowMat.m20), vEye.Dot((Vec4&)shadowMat.m30));
shadowMat.m03 += vecTranslation.x;
shadowMat.m13 += vecTranslation.y;
shadowMat.m23 += vecTranslation.z;
shadowMat.m33 += vecTranslation.w;
// Pre-multiply by inverse frustum far plane distance
(Vec4&)shadowMat.m20 *= rd->m_cEF.m_TempVecs[2].x;
Vec3 cubeDir = cubeDirs[side];
Vec4 spotParamsVS = Vec4(cubeDir.x, cubeDir.y, cubeDir.z, 0) * matView;
// slightly enlarge the frustum to prevent culling errors
spotParamsVS.w = renderLight.m_fRadius * tanf(DEG2RAD(45.0f + 14.5f)) * sqrt_2;
Vec3 coneTip = Vec3(lightCullInfo.posRad.x, lightCullInfo.posRad.y, lightCullInfo.posRad.z);
Vec3 coneDir = Vec3(-spotParamsVS.x, -spotParamsVS.y, -spotParamsVS.z);
AABB coneBounds = AABB::CreateAABBfromCone(Cone(coneTip, coneDir, renderLight.m_fRadius, spotParamsVS.w));
Vec2 depthBoundsVS = Vec2(coneBounds.min.z, coneBounds.max.z);
Vec2 sideShadowParams = (firstFrustum.nShadowGenMask & (1 << side)) ? shadowParams : Vec2(ZERO);
if (side == 0)
{
lightShadeInfo.shadowParams = sideShadowParams;
lightShadeInfo.shadowMatrix = shadowMat;
lightShadeInfo.shadowChannelIndex = Vec4(
renderLight.m_ShadowChanMask % 4 == 0,
renderLight.m_ShadowChanMask % 4 == 1,
renderLight.m_ShadowChanMask % 4 == 2,
renderLight.m_ShadowChanMask % 4 == 3
);
lightShadeInfo.shadowMaskIndex = renderLight.m_ShadowMaskIndex;
if (numSides > 1)
{
lightCullInfo.volumeType = vfInternal::tlVolumeCone;
lightShadeInfo.lightType = vfInternal::tlTypeRegularPointFace;
lightShadeInfo.resIndex = side;
lightCullInfo.volumeParams0 = spotParamsVS;
lightCullInfo.depthBounds = depthBoundsVS;
lightCullInfo.miscFlag = 0;
}
}
else
{
// Split point light
++numTileLights;
tileLightsCull[numTileLights] = lightCullInfo;
tileLightsShade[numTileLights] = lightShadeInfo;
tileLightsShade[numTileLights].shadowParams = sideShadowParams;
tileLightsShade[numTileLights].shadowMatrix = shadowMat;
tileLightsShade[numTileLights].resIndex = side;
tileLightsCull[numTileLights].volumeParams0 = spotParamsVS;
tileLightsCull[numTileLights].depthBounds = depthBoundsVS;
}
}
}
}
}
// Add current light
++numTileLights;
++numValidRenderLights;
}
}
// Invalidate last light in case it got skipped
if (numTileLights < vfInternal::MaxNumTileLights)
{
ZeroMemory(&tileLightsCull[numTileLights], sizeof(vfInternal::SVolumeLightCullInfo));
ZeroMemory(&tileLightsShade[numTileLights], sizeof(vfInternal::SVolumeLightShadeInfo));
}
// Update light buffer
m_lightCullInfoBuf.UpdateBufferContent(tileLightsCull, sizeof(vfInternal::SVolumeLightCullInfo) * vfInternal::MaxNumTileLights);
m_LightShadeInfoBuf.UpdateBufferContent(tileLightsShade, sizeof(vfInternal::SVolumeLightShadeInfo) * vfInternal::MaxNumTileLights);
m_numTileLights = numTileLights;
// Update global env probes for analytical volumetric fog
{
I3DEngine* pEng = gEnv->p3DEngine;
Vec3 fogAlbedo(0.0f, 0.0f, 0.0f);
pEng->GetGlobalParameter(E3DPARAM_VOLFOG2_COLOR, fogAlbedo);
colorGlobalEnvProbe0 = colorGlobalEnvProbe0.CompMul(fogAlbedo);
colorGlobalEnvProbe1 = colorGlobalEnvProbe1.CompMul(fogAlbedo);
m_globalEnvProbeParam0 = Vec4(colorGlobalEnvProbe0, attenuationGlobalEnvProbe0);
m_globalEnvProbeParam1 = Vec4(colorGlobalEnvProbe1, attenuationGlobalEnvProbe1);
SAFE_RELEASE(m_globalEnvProveTex0);
SAFE_RELEASE(m_globalEnvProveTex1);
if (texGlobalEnvProbe0)
{
m_globalEnvProveTex0 = texGlobalEnvProbe0;
m_globalEnvProveTex0->AddRef();
}
if (texGlobalEnvProbe1)
{
m_globalEnvProveTex1 = texGlobalEnvProbe1;
m_globalEnvProveTex1->AddRef();
}
}
}
void CVolumetricFog::RenderVolumetricsToVolume(void (* RenderFunc)())
{
if (!IsViable())
{
return;
}
AZ_TRACE_METHOD();
static const ICVar* pCVarFogVolumeInject = NULL;
if (!pCVarFogVolumeInject)
{
pCVarFogVolumeInject = gEnv->pConsole->GetCVar("e_FogVolumesTiledInjection");
}
bool bFogVolumeInjection = (pCVarFogVolumeInject && pCVarFogVolumeInject->GetIVal() != 0);
UpdateFrame();
RenderDownscaledShadowmap();
BuildLightListGrid();
RenderDownscaledDepth();
{
PROFILE_LABEL_SCOPE("INJECT_PARTICIPATING_MEDIA");
if (bFogVolumeInjection)
{
PrepareFogVolumeList();
InjectFogDensity();
}
else
{
InjectExponentialHeightFog();
}
CD3D9Renderer* const __restrict rd = gcpRendD3D;
SRenderPipeline& rp(rd->m_RP);
// store state
int oldX, oldY;
int oldWidth, oldHeight;
rd->GetViewport(&oldX, &oldY, &oldWidth, &oldHeight);
const uint64 prevShaderRtFlags = rp.m_FlagsShader_RT;
if (!bFogVolumeInjection)
{
// clear s_ptexVolumetricFogDensityColor.
rd->FX_ClearTarget(CTexture::s_ptexVolumetricFogDensityColor, Clr_Transparent);
}
rd->FX_PushRenderTarget(0, CTexture::s_ptexVolumetricFogDensityColor, NULL);
rd->FX_PushRenderTarget(1, CTexture::s_ptexVolumetricFogDensity, NULL);
rd->FX_SetActiveRenderTargets(false);
// Set the viewport.
int targetWidth = CTexture::s_ptexVolumetricFogDensity->GetWidth();
int targetHeight = CTexture::s_ptexVolumetricFogDensity->GetHeight();
rd->RT_SetViewport(0, 0, targetWidth, targetHeight);
// overwrite pipeline state.
const uint32 nOldForceStateAnd = rp.m_ForceStateAnd;
const uint32 nOldForceStateOr = rp.m_ForceStateOr;
rp.m_ForceStateAnd = GS_BLSRC_MASK | GS_BLDST_MASK | GS_DEPTHFUNC_MASK | GS_DEPTHWRITE | GS_NODEPTHTEST;
rp.m_ForceStateOr |= GS_BLSRC_ONE | GS_BLDST_ONE | GS_NODEPTHTEST;
// inject fog density and fog albedo into volume texture.
rd->FX_ProcessRenderList(EFSLIST_FOG_VOLUME, 0, RenderFunc, false);
rd->FX_ProcessRenderList(EFSLIST_FOG_VOLUME, 1, RenderFunc, false);
rd->FX_PopRenderTarget(0);
rd->FX_PopRenderTarget(1);
rd->FX_SetActiveRenderTargets(false);
// restore pipeline state.
rp.m_ForceStateAnd = nOldForceStateAnd;
rp.m_ForceStateOr = nOldForceStateOr;
rd->RT_SetViewport(oldX, oldY, oldWidth, oldHeight);
rp.m_FlagsShader_RT = prevShaderRtFlags;
rd->FX_Commit();
}
}
void CVolumetricFog::RenderVolumetricFog()
{
if (!IsViable())
{
return;
}
PROFILE_LABEL_SCOPE("RENDER_VOLUMETRIC_FOG");
InjectInscatteringLight();
const int VolumetricFogBlurInscattering = 1;
if constexpr (VolumetricFogBlurInscattering > 0)
{
int maxBlurCount = VolumetricFogBlurInscattering;
maxBlurCount = maxBlurCount <= 4 ? maxBlurCount : 4;
for (int count = 0; count < maxBlurCount; ++count)
{
#ifdef ENABLE_VOLFOG_TEX_FORMAT_RGBA16F
BlurInscatterVolume();
#else
BlurDensityVolume();
BlurInscatterVolume();
#endif
}
}
ReprojectVolume();
RaymarchVolumetricFog();
}
float CVolumetricFog::GetDepthIndex(float linearDepth) const
{
const float raymarchStart = gcpRendD3D->GetViewParameters().fNear;
Vec3 volFogCtrlParams(0.0f, 0.0f, 0.0f);
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_VOLFOG2_CTRL_PARAMS, volFogCtrlParams);
const float raymarchDistance = (volFogCtrlParams.x > raymarchStart) ? (volFogCtrlParams.x - raymarchStart) : 0.0001f;
float d = powf(((linearDepth - raymarchStart) / raymarchDistance), (1.0f / 2.0f));
float maxIndex = static_cast<f32>(CTexture::s_ptexVolumetricFog ? CTexture::s_ptexVolumetricFog->GetDepth() : 1.0f);
d = (0.5f - d) / maxIndex + d;
return d;
}
bool CVolumetricFog::IsEnableInFrame() const
{
bool v = CRenderer::CV_r_DeferredShadingTiled > 0
&& CRenderer::CV_r_DeferredShadingTiled < 4
&& CRenderer::CV_r_usezpass != 0
&& CRenderer::CV_r_Unlit == 0
&& CRenderer::CV_r_DeferredShadingDebug != 2
&& CRenderer::CV_r_measureoverdraw == 0;
return v;
}
void CVolumetricFog::PushFogVolume(CREFogVolume* pFogVolume, const SRenderingPassInfo& passInfo)
{
assert(pFogVolume != NULL);
if (pFogVolume == NULL)
{
return;
}
const uint32 nThreadID = gcpRendD3D->m_RP.m_nFillThreadID;
const uint32 nRecurseLevel = passInfo.GetRecursiveLevel();
const uint32 nVolumeType = pFogVolume->m_volumeType;
TArray<SFogVolumeInfo>& array = m_fogVolumeInfoArray[nThreadID][nRecurseLevel][nVolumeType];
if (array.size() >= vfInternal::MaxNumFogVolumes)
{
// TODO: show skipped FogVolume number on the screen.
return;
}
SFogVolumeInfo temp;
temp.m_center = pFogVolume->m_center;
temp.m_viewerInsideVolume = pFogVolume->m_viewerInsideVolume;
temp.m_affectsThisAreaOnly = pFogVolume->m_affectsThisAreaOnly;
temp.m_stencilRef = pFogVolume->m_stencilRef;
temp.m_volumeType = pFogVolume->m_volumeType;
temp.m_localAABB = pFogVolume->m_localAABB;
temp.m_matWSInv = pFogVolume->m_matWSInv;
temp.m_fogColor = pFogVolume->m_fogColor;
temp.m_globalDensity = pFogVolume->m_globalDensity;
temp.m_densityOffset = pFogVolume->m_densityOffset;
temp.m_softEdgesLerp = pFogVolume->m_softEdgesLerp;
temp.m_heightFallOffDirScaled = pFogVolume->m_heightFallOffDirScaled;
temp.m_heightFallOffBasePoint = pFogVolume->m_heightFallOffBasePoint;
temp.m_eyePosInOS = pFogVolume->m_eyePosInOS;
temp.m_rampParams = pFogVolume->m_rampParams;
temp.m_windOffset = pFogVolume->m_windOffset;
temp.m_noiseScale = pFogVolume->m_noiseScale;
temp.m_noiseFreq = pFogVolume->m_noiseFreq;
temp.m_noiseOffset = pFogVolume->m_noiseOffset;
temp.m_noiseElapsedTime = pFogVolume->m_noiseElapsedTime;
temp.m_scale = pFogVolume->m_scale;
array.Add(temp);
}
void CVolumetricFog::ClearFogVolumes()
{
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
if(gcpRendD3D->IsRenderToTextureActive())
{
return;
}
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
const uint32 nThreadID = gcpRendD3D->m_RP.m_nFillThreadID;
int32 nRecurseLevel = SRendItem::m_RecurseLevel[nThreadID];
if (0 <= nRecurseLevel && nRecurseLevel < MAX_REND_RECURSION_LEVELS)
{
for (uint32 i = 0; i < MaxNumFogVolumeType; ++i)
{
m_fogVolumeInfoArray[nThreadID][nRecurseLevel][i].SetUse(0);
}
}
}
void CVolumetricFog::ClearAllFogVolumes()
{
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
if(gcpRendD3D->IsRenderToTextureActive())
{
return;
}
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
for (int32 i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
for (int32 j = 0; j < MAX_REND_RECURSION_LEVELS; ++j)
{
for (uint32 k = 0; k < MaxNumFogVolumeType; ++k)
{
m_fogVolumeInfoArray[i][j][k].Free();
}
}
}
}
void CVolumetricFog::UpdateFrame()
{
int frameID = gcpRendD3D->GetFrameID(false);
if (m_frameID != frameID)
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
Matrix44 mViewProj = rd->m_ViewMatrix * rd->m_ProjMatrix;
Matrix44& mViewport = SD3DPostEffectsUtils::GetInstance().m_pScaleBias;
++m_tick;
m_frameID = frameID;
m_viewProj[m_tick % MaxFrameNum] = mViewProj * mViewport;
}
}
bool CVolumetricFog::IsViable() const
{
int nThreadID = gcpRendD3D->m_RP.m_nProcessThreadID;
int nRecurseLevel = SRendItem::m_RecurseLevel[nThreadID];
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
if ((gcpRendD3D->m_RP.m_TI[nThreadID].m_PersFlags & RBPF_RENDER_SCENE_TO_TEXTURE) != 0)
{
return false;
}
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
bool v = CD3D9Renderer::CV_r_VolumetricFog != 0 // IsEnableInFrame() and e_VolumetricFog are accumulated.
&& gcpRendD3D->m_RP.m_TI[nThreadID].m_FS.m_bEnable
&& nRecurseLevel == 0;
return v;
}
void CVolumetricFog::InjectInscatteringLight()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
SRenderPipeline& rp(rd->m_RP);
const int nThreadID = rp.m_nProcessThreadID;
// store state
const int32 prevState = rp.m_CurState;
const uint32 prevStateAnd = rp.m_StateAnd;
const uint32 prevStateOr = rp.m_StateOr;
const uint64 prevShaderRtFlags = rp.m_FlagsShader_RT;
const int prevPersFlags = rp.m_TI[nThreadID].m_PersFlags;
const uint32 nScreenWidth = m_InscatteringVolume->GetWidth();
const uint32 nScreenHeight = m_InscatteringVolume->GetHeight();
const uint32 volumeDepth = m_InscatteringVolume->GetDepth();
// calculate fog density and accumulate in-scattering lighting along view ray.
//PROFILE_LABEL_SCOPE( "INJECT_VOLUMETRIC_FOG_INSCATTERING" );
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 8, 8);
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 16, 8);
D3DUnorderedAccessView* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
// We are bypassing various texture shadow state caches by directly hitting the device manager for clearing texture slots here.
// CTexture::Apply can cache textures into CTexture::s_TexStages, which are not invalidated by the device manager and can lead CTexture to falsely believe
// a texture is still bound to the device when it has been cleared.
rd->RT_UnbindTMUs();
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
rd->FX_SetupShadowsForFog();
const int nStaticShadowMapSlot = 3;
SetupStaticShadowMap(nStaticShadowMapSlot);
rd->GetTiledShading().BindForwardShadingResources(NULL, eHWSC_Compute);
//// set debug flag
//if(CRenderer::CV_r_VolumetricFogDebug == 1)
//{
// rp.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG0];
//}
//else if(CRenderer::CV_r_VolumetricFogDebug == 2)
//{
// rp.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG1];
//}
//else if(CRenderer::CV_r_VolumetricFogDebug == 3)
//{
// rp.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG2];
//}
//else if(CRenderer::CV_r_VolumetricFogDebug == 4)
//{
// rp.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG3];
//}
// set sampling quality
const uint64 quality = g_HWSR_MaskBit[HWSR_SAMPLE4];
const uint64 quality1 = g_HWSR_MaskBit[HWSR_SAMPLE5];
rp.m_FlagsShader_RT &= ~(quality | quality1);
switch (CRenderer::CV_r_VolumetricFogSample)
{
case 1:
rp.m_FlagsShader_RT |= quality;
break;
case 2:
rp.m_FlagsShader_RT |= quality1;
break;
default:
break;
}
// set shadow quality
const uint64 shadowQuality = g_HWSR_MaskBit[HWSR_LIGHTVOLUME0];
const uint64 shadowQuality1 = g_HWSR_MaskBit[HWSR_LIGHTVOLUME1];
rp.m_FlagsShader_RT &= ~(shadowQuality | shadowQuality1);
switch (CRenderer::CV_r_VolumetricFogShadow)
{
case 1:
rp.m_FlagsShader_RT |= shadowQuality;
break;
case 2:
rp.m_FlagsShader_RT |= shadowQuality1;
break;
case 3:
rp.m_FlagsShader_RT |= shadowQuality | shadowQuality1;
break;
default:
break;
}
// set downscaled sun shadow maps
const uint64 shadowMode0 = g_HWSR_MaskBit[HWSR_SAMPLE0];
const uint64 shadowMode1 = g_HWSR_MaskBit[HWSR_SAMPLE1];
rp.m_FlagsShader_RT &= ~(shadowMode0 | shadowMode1);
if (CRenderer::CV_r_VolumetricFogDownscaledSunShadow == 1)
{
// replace first and second cascades
rp.m_FlagsShader_RT |= (CRenderer::CV_r_ShadowsCache > 0) ? shadowMode0 | shadowMode1 : shadowMode0;
}
else if (CRenderer::CV_r_VolumetricFogDownscaledSunShadow != 0)
{
// replace first, second, and third cascades
rp.m_FlagsShader_RT |= shadowMode1;
}
static CCryNameTSCRC shaderName("InjectVolumetricInscattering");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[1] = {
m_InscatteringVolume->GetDeviceUAV(),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
if (CRenderer::CV_r_VolumetricFogDownscaledSunShadow != 0)
{
D3DShaderResourceView* pDSMs[3] = {
m_downscaledShadow[0]->GetShaderResourceView(),
m_downscaledShadow[1]->GetShaderResourceView(),
m_downscaledShadow[2] ? m_downscaledShadow[2]->GetShaderResourceView() : NULL,
};
int count = (CRenderer::CV_r_VolumetricFogDownscaledSunShadow == 1) ? 2 : 3;
rd->m_DevMan.BindSRV(eHWSC_Compute, pDSMs, 5, count);
}
#ifdef ENABLE_VOLFOG_TEX_FORMAT_RGBA16F
D3DShaderResourceView* pSRVs[7] = {
m_lightGridBuf.GetShaderResourceView(),
m_lightCountBuf.GetShaderResourceView(),
m_MaxDepth->GetShaderResourceView(),
CTexture::s_ptexVolumetricClipVolumeStencil->GetShaderResourceView(),
m_LightShadeInfoBuf.GetShaderResourceView(),
CTexture::s_ptexVolumetricFogDensityColor->GetShaderResourceView(),
CTexture::s_ptexVolumetricFogDensity->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 8, 7);
#else
D3DShaderResourceView* pSRVs[6] = {
m_lightGridBuf.GetShaderResourceView(),
m_lightCountBuf.GetShaderResourceView(),
m_MaxDepth->GetShaderResourceView(),
CTexture::s_ptexVolumetricClipVolumeStencil->GetShaderResourceView(),
m_LightShadeInfoBuf.GetShaderResourceView(),
CTexture::s_ptexVolumetricFogDensityColor->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 8, 6);
#endif
//D3DSamplerState *pSamplers[2] = {
// (D3DSamplerState *)CTexture::s_TexStates[m_nTexStatePoint].m_pDeviceState,
// (D3DSamplerState *)CTexture::s_TexStates[m_nTexStateTriLinear].m_pDeviceState,
//};
//rd->m_DevMan.BindSampler( eHWSC_Compute, pSamplers, 0, 2 );
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
SD3DPostEffectsUtils::UpdateFrustumCorners();
static CCryNameR paramFrustumTL("FrustumTL");
Vec4 vParamFrustumTL(SD3DPostEffectsUtils::m_vLT.x, SD3DPostEffectsUtils::m_vLT.y, SD3DPostEffectsUtils::m_vLT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTL, &vParamFrustumTL, 1);
static CCryNameR paramFrustumTR("FrustumTR");
Vec4 vParamFrustumTR(SD3DPostEffectsUtils::m_vRT.x, SD3DPostEffectsUtils::m_vRT.y, SD3DPostEffectsUtils::m_vRT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTR, &vParamFrustumTR, 1);
static CCryNameR paramFrustumBL("FrustumBL");
Vec4 vParamFrustumBL(SD3DPostEffectsUtils::m_vLB.x, SD3DPostEffectsUtils::m_vLB.y, SD3DPostEffectsUtils::m_vLB.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumBL, &vParamFrustumBL, 1);
float octave = (CRenderer::CV_r_VolumetricFogReprojectionBlendFactor > 0.0f) ? -1.7f : 0.0f;
Vec3 sunDir = gEnv->p3DEngine->GetSunDirNormalized();
static CCryNameR paramSunDir("SunDir");
Vec4 vParamSunDir(sunDir.x, sunDir.y, sunDir.z, octave);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramSunDir, &vParamSunDir, 1);
Vec3 sunColor;
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_SUN_COLOR, sunColor);
static CCryNameR paramSunColor("SunColor");
Vec4 vParamSunColor(sunColor.x, sunColor.y, sunColor.z, 0.0f);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramSunColor, &vParamSunColor, 1);
Vec3 fogAlbedoColor;
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_VOLFOG2_COLOR, fogAlbedoColor);
static CCryNameR paramFogColor("ExponentialHeightFogColor");
Vec4 vParamFogColor(fogAlbedoColor.x, fogAlbedoColor.y, fogAlbedoColor.z, 0.0f);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFogColor, &vParamFogColor, 1);
Vec3 scatteringParam;
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_VOLFOG2_SCATTERING_PARAMS, scatteringParam);
static CCryNameR paramInjectInscattering("InjectInscatteringParams");
float k = scatteringParam.z;
bool bNegative = k < 0.0f ? true : false;
k = (abs(k) > 0.99999f) ? (bNegative ? -0.99999f : 0.99999f) : k;
Vec4 vParamInjectInscattering(k, 1.0f - k * k, 0.0f, 0.0f);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramInjectInscattering, &vParamInjectInscattering, 1);
const uint32 tileSizeX = 4;
const uint32 tileSizeY = 4;
const uint32 tileSizeZ = 4;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
uint32 dispatchSizeZ = (volumeDepth / tileSizeZ) + (volumeDepth % tileSizeZ > 0 ? 1 : 0);
static CCryNameR paramDispatchSize("DispatchSize");
Vec4 vParamDispatchSize((float)dispatchSizeX, (float)dispatchSizeY, (float)dispatchSizeZ, 0.0f);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramDispatchSize, &vParamDispatchSize, 1);
rd->FX_Commit();
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, dispatchSizeZ);
SD3DPostEffectsUtils::ShEndPass();
rd->GetTiledShading().UnbindForwardShadingResources(eHWSC_Compute);
//D3DUAV* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
D3DShaderResourceView* pSRVNull[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVNull, 0, 8);
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVNull, 8, 8);
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVNull, 16, 8);
// We are bypassing various texture shadow state caches by directly hitting the device manager for clearing texture slots here.
// CTexture::Apply can cache textures into CTexture::s_TexStages, which are not invalidated by the device manager and can lead CTexture to falsely believe
// a texture is still bound to the device when it has been cleared.
rd->RT_UnbindTMUs();
// restore state
rp.m_StateAnd = prevStateAnd;
rp.m_StateOr = prevStateOr;
rd->SetState(prevState);
rp.m_TI[nThreadID].m_PersFlags = prevPersFlags;
rp.m_FlagsShader_RT = prevShaderRtFlags;
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
void CVolumetricFog::BuildLightListGrid()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
SRenderPipeline& rp(rd->m_RP);
const int nThreadID = rp.m_nProcessThreadID;
// store state
const int32 prevState = rp.m_CurState;
const uint32 prevStateAnd = rp.m_StateAnd;
const uint32 prevStateOr = rp.m_StateOr;
const uint64 prevShaderRtFlags = rp.m_FlagsShader_RT;
const int prevPersFlags = rp.m_TI[nThreadID].m_PersFlags;
const uint32 nScreenWidth = m_InscatteringVolume->GetWidth();
const uint32 nScreenHeight = m_InscatteringVolume->GetHeight();
const uint32 volumeDepth = m_InscatteringVolume->GetDepth();
// calculate fog density and accumulate in-scattering lighting along view ray.
//PROFILE_LABEL_SCOPE( "BUILD_VOLUMETRIC_FOG_CLUSTERED_LIGHT_GRID" );
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 16, 8);
D3DUnorderedAccessView* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
rd->FX_Commit();
static CCryNameTSCRC shaderName("BuildLightListGrid");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[2] = {
m_lightGridBuf.GetUnorderedAccessView(),
m_lightCountBuf.GetUnorderedAccessView(),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 2);
D3DShaderResourceView* pSRV[1] = {
m_lightCullInfoBuf.GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRV, 0, 1);
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
SD3DPostEffectsUtils::UpdateFrustumCorners();
static CCryNameR paramFrustumTL("FrustumTL");
Vec4 vParamFrustumTL(SD3DPostEffectsUtils::m_vLT.x, SD3DPostEffectsUtils::m_vLT.y, SD3DPostEffectsUtils::m_vLT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTL, &vParamFrustumTL, 1);
static CCryNameR paramFrustumTR("FrustumTR");
Vec4 vParamFrustumTR(SD3DPostEffectsUtils::m_vRT.x, SD3DPostEffectsUtils::m_vRT.y, SD3DPostEffectsUtils::m_vRT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTR, &vParamFrustumTR, 1);
static CCryNameR paramFrustumBL("FrustumBL");
Vec4 vParamFrustumBL(SD3DPostEffectsUtils::m_vLB.x, SD3DPostEffectsUtils::m_vLB.y, SD3DPostEffectsUtils::m_vLB.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumBL, &vParamFrustumBL, 1);
const CameraViewParameters& rc = gcpRendD3D->GetViewParameters();
float yfov, xfov, aspect, ndist, fdist;
rc.GetPerspectiveParams(&yfov, &xfov, &aspect, &ndist, &fdist);
static CCryNameR paramNameScreenInfo("ScreenInfo");
Vec4 screenInfo(ndist, fdist, 0.0f, (float)volumeDepth);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramNameScreenInfo, &screenInfo, 1);
static CCryNameR paramProj("ProjParams");
Vec4 vParamProj(rd->m_ProjMatrix.m00, rd->m_ProjMatrix.m11, rd->m_ProjMatrix.m20, rd->m_ProjMatrix.m21);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramProj, &vParamProj, 1);
uint32 numTileLights = m_numTileLights;
const uint32 tileSizeX = 4;
const uint32 tileSizeY = 4;
const uint32 tileSizeZ = 4;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
uint32 dispatchSizeZ = (volumeDepth / tileSizeZ) + (volumeDepth % tileSizeZ > 0 ? 1 : 0);
static CCryNameR paramDispatchSize("DispatchSize");
Vec4 vParamDispatchSize((float)dispatchSizeX, (float)dispatchSizeY, (float)dispatchSizeZ, (float)numTileLights);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramDispatchSize, &vParamDispatchSize, 1);
rd->FX_Commit();
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, dispatchSizeZ);
SD3DPostEffectsUtils::ShEndPass();
//D3DUAV* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
D3DShaderResourceView* pSRVNull[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVNull, 0, 1);
//D3DSamplerState* pSampNull[2] = { NULL };
//rd->m_DevMan.BindSampler( eHWSC_Compute, pSampNull, 0, 2 );
// restore state
rp.m_StateAnd = prevStateAnd;
rp.m_StateOr = prevStateOr;
rd->SetState(prevState);
rp.m_TI[nThreadID].m_PersFlags = prevPersFlags;
rp.m_FlagsShader_RT = prevShaderRtFlags;
rd->FX_Commit();
}
void CVolumetricFog::RaymarchVolumetricFog()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
// Unbind the VolumetricFog SRV (used in the recursive pass). It gets
// implicitly unbound when used as a UAV. Without explicitly calling
// Unbind(), it may not get re-bound as an SRV for future shaders.
CTexture::s_ptexVolumetricFog->Unbind();
// store state
SRenderPipeline& rp(rd->m_RP);
const uint64 prevShaderRtFlags = rp.m_FlagsShader_RT;
const uint32 nScreenWidth = CTexture::s_ptexVolumetricFogDensity->GetWidth();
const uint32 nScreenHeight = CTexture::s_ptexVolumetricFogDensity->GetHeight();
const uint32 volumeDepth = CTexture::s_ptexVolumetricFogDensity->GetDepth();
//PROFILE_LABEL_SCOPE( "RAYMARCH_VOLUMETRIC_FOG" );
// accumulate in-scattering lighting along view ray.
static CCryNameTSCRC shaderName("RaymarchVolumetricFog");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[1] = {
CTexture::s_ptexVolumetricFog->GetDeviceUAV(),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
#ifdef ENABLE_VOLFOG_TEX_FORMAT_RGBA16F
D3DShaderResourceView* pSRVs[1] = {
(GetInscatterTex()->GetShaderResourceView()),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 1);
#else
D3DShaderResourceView* pSRVs[2] = {
(GetInscatterTex()->GetShaderResourceView()),
(GetDensityTex()->GetShaderResourceView()),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 2);
#endif
//D3DSamplerState *pSamplers[2] = {
// (D3DSamplerState *)CTexture::s_TexStates[m_nTexStatePoint].m_pDeviceState,
// (D3DSamplerState *)CTexture::s_TexStates[m_nTexStateTriLinear].m_pDeviceState,
//};
//rd->m_DevMan.BindSampler( eHWSC_Compute, pSamplers, 0, 2 );
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
SD3DPostEffectsUtils::UpdateFrustumCorners();
static CCryNameR paramFrustumTL("FrustumTL");
Vec4 vParamFrustumTL(SD3DPostEffectsUtils::m_vLT.x, SD3DPostEffectsUtils::m_vLT.y, SD3DPostEffectsUtils::m_vLT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTL, &vParamFrustumTL, 1);
static CCryNameR paramFrustumTR("FrustumTR");
Vec4 vParamFrustumTR(SD3DPostEffectsUtils::m_vRT.x, SD3DPostEffectsUtils::m_vRT.y, SD3DPostEffectsUtils::m_vRT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTR, &vParamFrustumTR, 1);
static CCryNameR paramFrustumBL("FrustumBL");
Vec4 vParamFrustumBL(SD3DPostEffectsUtils::m_vLB.x, SD3DPostEffectsUtils::m_vLB.y, SD3DPostEffectsUtils::m_vLB.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumBL, &vParamFrustumBL, 1);
const CameraViewParameters& rc = gcpRendD3D->GetViewParameters();
float yfov, xfov, aspect, ndist, fdist;
rc.GetPerspectiveParams(&yfov, &xfov, &aspect, &ndist, &fdist);
static CCryNameR paramNameScreenInfo("ScreenInfo");
Vec4 screenInfo(ndist, fdist, 0.0f, (float)volumeDepth);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramNameScreenInfo, &screenInfo, 1);
rd->FX_Commit();
const uint32 tileSizeX = 8;
const uint32 tileSizeY = 8;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, 1);
SD3DPostEffectsUtils::ShEndPass();
D3DUnorderedAccessView* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
D3DShaderResourceView* pSRVNull[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVNull, 0, 2);
D3DSamplerState* pSampNull[2] = { NULL };
rd->m_DevMan.BindSampler(eHWSC_Compute, pSampNull, 0, 2);
// restore state
rp.m_FlagsShader_RT = prevShaderRtFlags;
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
void CVolumetricFog::BlurInscatterVolume()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
const uint32 nScreenWidth = m_InscatteringVolume->GetWidth();
const uint32 nScreenHeight = m_InscatteringVolume->GetHeight();
const uint32 volumeDepth = m_InscatteringVolume->GetDepth();
// blur inscattering volume texture for removing jittering noise.
//PROFILE_LABEL_SCOPE( "VOLUMETRIC_FOG_BLUR" );
{
static CCryNameTSCRC shaderNameHorizontal("BlurHorizontalInscatteringVolume");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderNameHorizontal, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[1] = {
static_cast<D3DUnorderedAccessView*>(GetInscatterTex()->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
D3DShaderResourceView* pSRVs[2] = {
m_InscatteringVolume->GetShaderResourceView(),
m_MaxDepth->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 2);
D3DSamplerState* pSamplers[1] = {
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStateTriLinear].m_pDeviceState,
};
rd->m_DevMan.BindSampler(eHWSC_Compute, pSamplers, 0, 1);
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
const CameraViewParameters& rc = gcpRendD3D->GetViewParameters();
float yfov, xfov, aspect, ndist, fdist;
rc.GetPerspectiveParams(&yfov, &xfov, &aspect, &ndist, &fdist);
static CCryNameR paramNameScreenInfo("ScreenInfo");
Vec4 screenInfo(ndist, fdist, 0.0f, (float)volumeDepth);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramNameScreenInfo, &screenInfo, 1);
rd->FX_Commit();
const uint32 tileSizeX = 8;
const uint32 tileSizeY = 8;
const uint32 tileSizeZ = 1;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
uint32 dispatchSizeZ = (volumeDepth / tileSizeZ) + (volumeDepth % tileSizeZ > 0 ? 1 : 0);
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, dispatchSizeZ);
SD3DPostEffectsUtils::ShEndPass();
}
{
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
D3DUnorderedAccessView* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
{
static CCryNameTSCRC shaderNameVertical("BlurVerticalInscatteringVolume");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderNameVertical, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[1] = {
static_cast<D3DUnorderedAccessView*>(m_InscatteringVolume->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
D3DShaderResourceView* pSRVs[2] = {
(GetInscatterTex()->GetShaderResourceView()),
m_MaxDepth->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 2);
D3DSamplerState* pSamplers[1] = {
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStateTriLinear].m_pDeviceState,
};
rd->m_DevMan.BindSampler(eHWSC_Compute, pSamplers, 0, 1);
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
const CameraViewParameters& rc = gcpRendD3D->GetViewParameters();
float yfov, xfov, aspect, ndist, fdist;
rc.GetPerspectiveParams(&yfov, &xfov, &aspect, &ndist, &fdist);
static CCryNameR paramNameScreenInfo("ScreenInfo");
Vec4 screenInfo(ndist, fdist, 0.0f, (float)volumeDepth);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramNameScreenInfo, &screenInfo, 1);
rd->FX_Commit();
const uint32 tileSizeX = 8;
const uint32 tileSizeY = 8;
const uint32 tileSizeZ = 1;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
uint32 dispatchSizeZ = (volumeDepth / tileSizeZ) + (volumeDepth % tileSizeZ > 0 ? 1 : 0);
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, dispatchSizeZ);
SD3DPostEffectsUtils::ShEndPass();
}
D3DUnorderedAccessView* pUAVNull4[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull4, NULL, 0, 4);
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
D3DSamplerState* pSampNull[2] = { NULL };
rd->m_DevMan.BindSampler(eHWSC_Compute, pSampNull, 0, 2);
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
void CVolumetricFog::BlurDensityVolume()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
const uint32 nScreenWidth = CTexture::s_ptexVolumetricFogDensity->GetWidth();
const uint32 nScreenHeight = CTexture::s_ptexVolumetricFogDensity->GetHeight();
const uint32 volumeDepth = CTexture::s_ptexVolumetricFogDensity->GetDepth();
// blur density volume texture for removing jitter noise.
//PROFILE_LABEL_SCOPE( "VOLUMETRIC_FOG_BLUR_DENSITY" );
{
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
D3DUnorderedAccessView* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
{
static CCryNameTSCRC shaderNameHorizontal("BlurHorizontalDensityVolume");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderNameHorizontal, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[1] = {
static_cast<D3DUnorderedAccessView*>(GetDensityTex()->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
D3DShaderResourceView* pSRVs[2] = {
CTexture::s_ptexVolumetricFogDensity->GetShaderResourceView(),
m_MaxDepth->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 2);
D3DSamplerState* pSamplers[1] = {
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStateTriLinear].m_pDeviceState,
};
rd->m_DevMan.BindSampler(eHWSC_Compute, pSamplers, 0, 1);
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
const CameraViewParameters& rc = gcpRendD3D->GetViewParameters();
float yfov, xfov, aspect, ndist, fdist;
rc.GetPerspectiveParams(&yfov, &xfov, &aspect, &ndist, &fdist);
static CCryNameR paramNameScreenInfo("ScreenInfo");
Vec4 screenInfo(ndist, fdist, 0.0f, (float)volumeDepth);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramNameScreenInfo, &screenInfo, 1);
rd->FX_Commit();
const uint32 tileSizeX = 8;
const uint32 tileSizeY = 8;
const uint32 tileSizeZ = 1;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
uint32 dispatchSizeZ = (volumeDepth / tileSizeZ) + (volumeDepth % tileSizeZ > 0 ? 1 : 0);
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, dispatchSizeZ);
SD3DPostEffectsUtils::ShEndPass();
}
{
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
D3DUnorderedAccessView* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
{
static CCryNameTSCRC shaderNameVertical("BlurVerticalDensityVolume");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderNameVertical, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[1] = {
static_cast<D3DUnorderedAccessView*>(CTexture::s_ptexVolumetricFogDensity->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
D3DShaderResourceView* pSRVs[2] = {
(GetDensityTex()->GetShaderResourceView()),
m_MaxDepth->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 2);
D3DSamplerState* pSamplers[1] = {
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStateTriLinear].m_pDeviceState,
};
rd->m_DevMan.BindSampler(eHWSC_Compute, pSamplers, 0, 1);
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
const CameraViewParameters& rc = gcpRendD3D->GetViewParameters();
float yfov, xfov, aspect, ndist, fdist;
rc.GetPerspectiveParams(&yfov, &xfov, &aspect, &ndist, &fdist);
static CCryNameR paramNameScreenInfo("ScreenInfo");
Vec4 screenInfo(ndist, fdist, 0.0f, (float)volumeDepth);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramNameScreenInfo, &screenInfo, 1);
rd->FX_Commit();
const uint32 tileSizeX = 8;
const uint32 tileSizeY = 8;
const uint32 tileSizeZ = 1;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
uint32 dispatchSizeZ = (volumeDepth / tileSizeZ) + (volumeDepth % tileSizeZ > 0 ? 1 : 0);
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, dispatchSizeZ);
SD3DPostEffectsUtils::ShEndPass();
}
D3DUnorderedAccessView* pUAVNull4[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull4, NULL, 0, 4);
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
D3DSamplerState* pSampNull[2] = { NULL };
rd->m_DevMan.BindSampler(eHWSC_Compute, pSampNull, 0, 2);
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
void CVolumetricFog::ReprojectVolume()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
// store state
SRenderPipeline& rp(rd->m_RP);
const uint64 prevShaderRtFlags = rp.m_FlagsShader_RT;
const uint32 nScreenWidth = m_InscatteringVolume->GetWidth();
const uint32 nScreenHeight = m_InscatteringVolume->GetHeight();
const uint32 volumeDepth = m_InscatteringVolume->GetDepth();
//PROFILE_LABEL_SCOPE( "REPROJECT_VOLUMETRIC_FOG" );
// no reprojection in cleared frames
if (m_Cleared > 0)
{
#ifdef ENABLE_VOLFOG_TEX_FORMAT_RGBA16F
rd->GetDeviceContext().CopyResource(GetPrevInscatterTex()->GetDevTexture()->GetVolumeTexture(),
m_InscatteringVolume->GetDevTexture()->GetVolumeTexture());
#else
rd->GetDeviceContext().CopyResource(GetPrevInscatterTex()->GetDevTexture()->GetVolumeTexture(),
m_InscatteringVolume->GetDevTexture()->GetVolumeTexture());
rd->GetDeviceContext().CopyResource(GetPrevDensityTex()->GetDevTexture()->GetVolumeTexture(),
CTexture::s_ptexVolumetricFogDensity->GetDevTexture()->GetVolumeTexture());
#endif
}
{
// set reprojection mode
if (CRenderer::CV_r_VolumetricFogReprojectionMode != 0)
{
rp.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE5];
}
// accumulate in-scattering lighting along view ray.
static CCryNameTSCRC shaderName("ReprojectVolumetricFog");
bool valid = SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
#ifdef ENABLE_VOLFOG_TEX_FORMAT_RGBA16F
D3DUnorderedAccessView* pUAVs[1] = {
static_cast<D3DUnorderedAccessView*>(GetInscatterTex()->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
D3DShaderResourceView* pSRVs[3] = {
m_InscatteringVolume->GetShaderResourceView(),
(GetPrevInscatterTex()->GetShaderResourceView()),
m_MaxDepth->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 3);
#else
D3DUnorderedAccessView* pUAVs[2] = {
static_cast<D3DUnorderedAccessView*>(GetInscatterTex()->GetDeviceUAV()),
static_cast<D3DUnorderedAccessView*>(GetDensityTex()->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 2);
D3DShaderResourceView* pSRVs[5] = {
m_InscatteringVolume->GetShaderResourceView(),
(GetPrevInscatterTex()->GetShaderResourceView()),
CTexture::s_ptexVolumetricFogDensity->GetShaderResourceView(),
(GetPrevDensityTex()->GetShaderResourceView()),
m_MaxDepth->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 5);
#endif
D3DSamplerState* pSamplers[2] = {
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStateTriLinear].m_pDeviceState,
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStatePoint].m_pDeviceState,
};
rd->m_DevMan.BindSampler(eHWSC_Compute, pSamplers, 0, 2);
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
SD3DPostEffectsUtils::UpdateFrustumCorners();
static CCryNameR paramFrustumTL("FrustumTL");
Vec4 vParamFrustumTL(SD3DPostEffectsUtils::m_vLT.x, SD3DPostEffectsUtils::m_vLT.y, SD3DPostEffectsUtils::m_vLT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTL, &vParamFrustumTL, 1);
static CCryNameR paramFrustumTR("FrustumTR");
Vec4 vParamFrustumTR(SD3DPostEffectsUtils::m_vRT.x, SD3DPostEffectsUtils::m_vRT.y, SD3DPostEffectsUtils::m_vRT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTR, &vParamFrustumTR, 1);
static CCryNameR paramFrustumBL("FrustumBL");
Vec4 vParamFrustumBL(SD3DPostEffectsUtils::m_vLB.x, SD3DPostEffectsUtils::m_vLB.y, SD3DPostEffectsUtils::m_vLB.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumBL, &vParamFrustumBL, 1);
float reprojectionFactor = max(0.0f, min(1.0f, CRenderer::CV_r_VolumetricFogReprojectionBlendFactor));
const CameraViewParameters& rc = gcpRendD3D->GetViewParameters();
float yfov, xfov, aspect, ndist, fdist;
rc.GetPerspectiveParams(&yfov, &xfov, &aspect, &ndist, &fdist);
static CCryNameR paramNameScreenInfo("ScreenInfo");
Vec4 screenInfo(ndist, fdist, reprojectionFactor, (float)volumeDepth);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramNameScreenInfo, &screenInfo, 1);
static CCryNameR param1("PrevViewProjMatrix");
Vec4* temp = (Vec4*)m_viewProj[max(m_tick - (int32)rd->GetActiveGPUCount(), 0) % MaxFrameNum].GetData();
CShaderMan::s_shDeferredShading->FXSetCSFloat(param1, temp, 4);
rd->FX_Commit();
const uint32 tileSizeX = 4;
const uint32 tileSizeY = 4;
const uint32 tileSizeZ = 4;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
uint32 dispatchSizeZ = (volumeDepth / tileSizeZ) + (volumeDepth % tileSizeZ > 0 ? 1 : 0);
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, dispatchSizeZ);
SD3DPostEffectsUtils::ShEndPass();
if (valid)
{
m_Cleared = (m_Cleared > 0) ? (m_Cleared - 1) : 0;
}
}
D3DUnorderedAccessView* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
D3DShaderResourceView* pSRVNull[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVNull, 0, 5);
D3DSamplerState* pSampNull[2] = { NULL };
rd->m_DevMan.BindSampler(eHWSC_Compute, pSampNull, 0, 2);
// restore state
rp.m_FlagsShader_RT = prevShaderRtFlags;
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
CTexture* CVolumetricFog::GetInscatterTex() const
{
return ((m_tick / gcpRendD3D->GetActiveGPUCount()) & 0x1) ? m_fogInscatteringVolume[0] : m_fogInscatteringVolume[1];
}
CTexture* CVolumetricFog::GetPrevInscatterTex() const
{
return ((m_tick / gcpRendD3D->GetActiveGPUCount()) & 0x1) ? m_fogInscatteringVolume[1] : m_fogInscatteringVolume[0];
}
CTexture* CVolumetricFog::GetDensityTex() const
{
return ((m_tick / gcpRendD3D->GetActiveGPUCount()) & 0x1) ? m_fogDensityVolume[0] : m_fogDensityVolume[1];
}
CTexture* CVolumetricFog::GetPrevDensityTex() const
{
return ((m_tick / gcpRendD3D->GetActiveGPUCount()) & 0x1) ? m_fogDensityVolume[1] : m_fogDensityVolume[0];
}
void CVolumetricFog::RenderDownscaledDepth()
{
//PROFILE_LABEL_SCOPE( "VOLUMETRIC_FOG_DOWNSCALED_DEPTH" );
CD3D9Renderer* const __restrict rd = gcpRendD3D;
{
static CCryNameTSCRC shaderName("StoreDownscaledMaxDepthHorizontal");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[1] = {
static_cast<D3DUnorderedAccessView*>(m_MaxDepthTemp->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
D3DShaderResourceView* pSRVs[1] = {
CTexture::s_ptexZTargetScaled->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 1);
D3DSamplerState* pSamplers[1] = {
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStatePoint].m_pDeviceState,
};
rd->m_DevMan.BindSampler(eHWSC_Compute, pSamplers, 0, 1);
int nScreenWidth = m_MaxDepthTemp->GetWidth();
int nScreenHeight = m_MaxDepthTemp->GetHeight();
int nSrcTexWidth = CTexture::s_ptexZTargetScaled->GetWidth();
int nSrcTexHeight = CTexture::s_ptexZTargetScaled->GetHeight();
static CCryNameR paramDispatchParams("maxDepthDispatchParams");
float destW = (float)nScreenWidth;
float srcW = (float)nSrcTexWidth;
Vec4 vParamDispatchParams((srcW / destW), (destW / srcW), 0.0f, 0.0f);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramDispatchParams, &vParamDispatchParams, 1);
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
rd->FX_Commit();
const uint32 tileSizeX = 8;
const uint32 tileSizeY = 8;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, 1);
SD3DPostEffectsUtils::ShEndPass();
}
{
D3DShaderResourceView* pNullViews[1] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 1);
D3DUnorderedAccessView* pUAVNull[1] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 1);
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
{
static CCryNameTSCRC shaderName("StoreDownscaledMaxDepthVertical");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[1] = {
static_cast<D3DUnorderedAccessView*>(m_MaxDepth->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
D3DShaderResourceView* pSRVs[1] = {
m_MaxDepthTemp->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 0, 1);
D3DSamplerState* pSamplers[1] = {
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStatePoint].m_pDeviceState,
};
rd->m_DevMan.BindSampler(eHWSC_Compute, pSamplers, 0, 1);
int nScreenWidth = m_MaxDepth->GetWidth();
int nScreenHeight = m_MaxDepth->GetHeight();
int nSrcTexWidth = m_MaxDepthTemp->GetWidth();
int nSrcTexHeight = m_MaxDepthTemp->GetHeight();
static CCryNameR paramDispatchParams("maxDepthDispatchParams");
float destW = (float)nScreenWidth;
float srcW = (float)nSrcTexWidth;
Vec4 vParamDispatchParams((srcW / destW), (destW / srcW), 0.0f, 0.0f);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramDispatchParams, &vParamDispatchParams, 1);
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
rd->FX_Commit();
const uint32 tileSizeX = 8;
const uint32 tileSizeY = 8;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, 1);
SD3DPostEffectsUtils::ShEndPass();
}
{
D3DUnorderedAccessView* pUAVNull[1] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 1);
D3DShaderResourceView* pNullViews[1] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 1);
D3DSamplerState* pSampNull[1] = { NULL };
rd->m_DevMan.BindSampler(eHWSC_Compute, pSampNull, 0, 1);
}
}
void CVolumetricFog::ClearVolumeStencil()
{
if (!IsViable())
{
return;
}
PROFILE_LABEL_SCOPE("VOLUMETRIC_FOG_CLEAR_VOLUME_STENCIL");
gcpRendD3D->FX_ClearTarget((D3DDepthSurface*)CTexture::s_ptexVolumetricClipVolumeStencil->GetDeviceDepthStencilSurf(), CLEAR_STENCIL, Clr_Unused.r, 0);
}
void CVolumetricFog::RenderClipVolumeToVolumeStencil(int nClipAreaReservedStencilBit)
{
if (!IsViable())
{
return;
}
PROFILE_LABEL_SCOPE("VOLUMETRIC_FOG_CLIPVOLUMES TO STENCIL");
CD3D9Renderer* const __restrict rd = gcpRendD3D;
SRenderPipeline& rp(rd->m_RP);
const bool bReverseDepth = (rp.m_TI[rp.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) != 0;
int oldX, oldY;
int oldWidth, oldHeight;
rd->GetViewport(&oldX, &oldY, &oldWidth, &oldHeight);
// FOB_POINT_SPRITE prevents CD3D9Renderer::FX_SetVertexDeclaration function working correctly.
uint64 objFlags = rp.m_ObjFlags;
rp.m_ObjFlags &= ~FOB_POINT_SPRITE;
int targetWidth = CTexture::s_ptexVolumetricClipVolumeStencil->GetWidth();
int targetHeight = CTexture::s_ptexVolumetricClipVolumeStencil->GetHeight();
rd->RT_SetViewport(0, 0, targetWidth, targetHeight);
SDepthTexture D3dDepthSurface;
D3dDepthSurface.nWidth = targetWidth;
D3dDepthSurface.nHeight = targetHeight;
D3dDepthSurface.pSurf = nullptr;
D3dDepthSurface.pTex = nullptr;
D3dDepthSurface.pTarget = CTexture::s_ptexVolumetricClipVolumeStencil->GetDevTexture()->Get2DTexture();
int maxDepthCount = m_InscatteringVolume->GetDepth();
float a = 0.0f;
float b = 0.0f;
bool valid = true;
float d = (rp.m_TI[rp.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) ? 1.0f : 0.0f;
float raymarchDistance = gRenDev->m_cEF.m_PF.m_VolumetricFogDistanceParams.w;
if (m_Destroyed > 0)
{
float fFar = rd->GetViewParameters().fFar;
float fNear = rd->GetViewParameters().fNear;
float invMaxIndexMinusOne = 1.0f / (static_cast<f32>(maxDepthCount) - 1.0f);
a = fFar / (fFar - fNear);
b = fNear * -a;
// store values to observe the change.
m_ReverseDepthMode = CRenderer::CV_r_ReverseDepth;
m_raymarchDistance = raymarchDistance;
rd->FX_ClearTarget((D3DDepthSurface*)CTexture::s_ptexVolumetricClipVolumeStencil->GetDeviceDepthStencilSurf(), CLEAR_ZBUFFER, Clr_FarPlane_R.r, 0);
}
for (int i = 0; i < maxDepthCount; ++i)
{
// set separate DSV.
D3dDepthSurface.pSurf = (D3DDepthSurface*)m_ClipVolumeDSVArray[i];
rd->FX_PushRenderTarget(0, (CTexture*)NULL, &D3dDepthSurface);
// clear depth when it's needed.
if (m_Destroyed > 0)
{
// write jittering depth.
static CCryNameTSCRC shaderName("StoreJitteringDepthToClipVolumeDepth");
bool result = GetUtils().ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
valid = valid && result;
rd->FX_SetState(GS_DEPTHWRITE);
static CCryNameR paramDepth("ParamDepth");
Vec4 vParamDepth((float)i, b, a, d);
CShaderMan::s_shDeferredShading->FXSetPSFloat(paramDepth, &vParamDepth, 1);
GetUtils().DrawFullScreenTri(targetWidth, targetHeight);
GetUtils().ShEndPass();
}
CDeferredShading& pDS = CDeferredShading::Instance();
pDS.RenderClipVolumesToStencil(nClipAreaReservedStencilBit);
rd->FX_PopRenderTarget(0);
}
if (valid)
{
m_Destroyed = (m_Destroyed > 0) ? (m_Destroyed - 1) : 0;
if (m_ReverseDepthMode != CRenderer::CV_r_ReverseDepth
|| (0.2f < abs(m_raymarchDistance - raymarchDistance)))
{
// rewrite the depth if needed.
m_Destroyed = MaxFrameNum;
}
}
rd->RT_SetViewport(oldX, oldY, oldWidth, oldHeight);
rp.m_ObjFlags = objFlags;
}
void CVolumetricFog::InjectExponentialHeightFog()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
SRenderPipeline& rp(rd->m_RP);
const int nThreadID = rp.m_nProcessThreadID;
// store state
const int32 prevState = rp.m_CurState;
const uint32 prevStateAnd = rp.m_StateAnd;
const uint32 prevStateOr = rp.m_StateOr;
const uint64 prevShaderRtFlags = rp.m_FlagsShader_RT;
const int prevPersFlags = rp.m_TI[nThreadID].m_PersFlags;
// inject atmospheric fog into density volume texture.
{
const uint32 nScreenWidth = CTexture::s_ptexVolumetricFogDensity->GetWidth();
const uint32 nScreenHeight = CTexture::s_ptexVolumetricFogDensity->GetHeight();
const uint32 volumeDepth = CTexture::s_ptexVolumetricFogDensity->GetDepth();
//PROFILE_LABEL_SCOPE( "INJECT_ATMOSPHERIC_FOG" );
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
D3DUnorderedAccessView* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
rd->GetTiledShading().BindForwardShadingResources(NULL, eHWSC_Compute);
CShader* pShader = CShaderMan::s_shDeferredShading;
static CCryNameTSCRC shaderName("InjectExponentialHeightFog");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[1] = {
static_cast<D3DUnorderedAccessView*>(CTexture::s_ptexVolumetricFogDensity->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 1);
D3DSamplerState* pSamplers[1] = {
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStateTriLinear].m_pDeviceState,
};
rd->m_DevMan.BindSampler(eHWSC_Compute, pSamplers, 0, 1);
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
pShader->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
SD3DPostEffectsUtils::UpdateFrustumCorners();
static CCryNameR paramFrustumTL("FrustumTL");
Vec4 vParamFrustumTL(SD3DPostEffectsUtils::m_vLT.x, SD3DPostEffectsUtils::m_vLT.y, SD3DPostEffectsUtils::m_vLT.z, 0);
pShader->FXSetCSFloat(paramFrustumTL, &vParamFrustumTL, 1);
static CCryNameR paramFrustumTR("FrustumTR");
Vec4 vParamFrustumTR(SD3DPostEffectsUtils::m_vRT.x, SD3DPostEffectsUtils::m_vRT.y, SD3DPostEffectsUtils::m_vRT.z, 0);
pShader->FXSetCSFloat(paramFrustumTR, &vParamFrustumTR, 1);
static CCryNameR paramFrustumBL("FrustumBL");
Vec4 vParamFrustumBL(SD3DPostEffectsUtils::m_vLB.x, SD3DPostEffectsUtils::m_vLB.y, SD3DPostEffectsUtils::m_vLB.z, 0);
pShader->FXSetCSFloat(paramFrustumBL, &vParamFrustumBL, 1);
static CCryNameR paramInjectExponentialHeightFogParams("InjectExponentialHeightFogParams");
Vec4 vInjectExponentialHeightFogParams((float)volumeDepth, 0.0f, 0.0f, 0.0f);
pShader->FXSetCSFloat(paramInjectExponentialHeightFogParams, &vInjectExponentialHeightFogParams, 1);
rd->FX_Commit();
const uint32 tileSizeX = 4;
const uint32 tileSizeY = 4;
const uint32 tileSizeZ = 4;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
uint32 dispatchSizeZ = (volumeDepth / tileSizeZ) + (volumeDepth % tileSizeZ > 0 ? 1 : 0);
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, dispatchSizeZ);
SD3DPostEffectsUtils::ShEndPass();
rd->GetTiledShading().UnbindForwardShadingResources(eHWSC_Compute);
}
D3DUnorderedAccessView* pUAVNull4[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull4, NULL, 0, 4);
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
D3DSamplerState* pSampNull[2] = { NULL };
rd->m_DevMan.BindSampler(eHWSC_Compute, pSampNull, 0, 2);
// restore state
rp.m_StateAnd = prevStateAnd;
rp.m_StateOr = prevStateOr;
rd->SetState(prevState);
rp.m_TI[nThreadID].m_PersFlags = prevPersFlags;
rp.m_FlagsShader_RT = prevShaderRtFlags;
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
void CVolumetricFog::PrepareFogVolumeList()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
int nThreadID = rd->m_RP.m_nProcessThreadID;
int nRecurseLevel = SRendItem::m_RecurseLevel[nThreadID];
// Prepare view matrix with flipped z-axis
Matrix44A matView = rd->m_ViewMatrix;
matView.m02 *= -1;
matView.m12 *= -1;
matView.m22 *= -1;
matView.m32 *= -1;
vfInternal::SFogVolumeCullInfo cullInfoArray[vfInternal::MaxNumFogVolumes];
vfInternal::SFogVolumeInjectInfo injectInfoArray[vfInternal::MaxNumFogVolumes];
uint32 numFogVol = 0;
Vec3 volumetricFogRaymarchEnd(0.0f, 0.0f, 0.0f);
gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_VOLFOG2_CTRL_PARAMS, volumetricFogRaymarchEnd);
Vec3 cameraFront = rd->GetViewParameters().vZ;
cameraFront.Normalize();
Vec3 worldViewPos = rd->GetViewParameters().vOrigin;
AABB aabbInObj(1.0f);
for (uint32 type = 0; type < MaxNumFogVolumeType; ++type)
{
TArray<SFogVolumeInfo>& srcArray = m_fogVolumeInfoArray[nThreadID][nRecurseLevel][type];
uint num = srcArray.Num();
for (uint32 i = 0; i < num; ++i)
{
SFogVolumeInfo& fvol = srcArray[i];
// calculate depth bounds of FogVolume.
// reusing light depth bounds code from CDeferredShading::GetLightDepthBounds().
// This is not optimal for a box.
Matrix34 temp = fvol.m_matWSInv.GetInverted();
AABB aabbInWS = AABB::CreateTransformedAABB(temp, aabbInObj);
float fRadius = aabbInWS.GetRadius();
Vec3 pBounds = cameraFront * fRadius;
Vec3 pMin = fvol.m_center + pBounds;
float fMinW = rd->GetViewParameters().WorldToCamZ(pMin);
fMinW = max(-fMinW, 0.000001f);
// not needed to be injected when FogVolume is out of volume texture.
if (fMinW > volumetricFogRaymarchEnd.x)
{
continue;
}
vfInternal::SFogVolumeCullInfo& cullInfo = cullInfoArray[numFogVol];
vfInternal::SFogVolumeInjectInfo& injectInfo = injectInfoArray[numFogVol];
Vec4 posVS = Vec4(fvol.m_center, 1) * matView;
cullInfo.posRad = Vec4(posVS.x, posVS.y, posVS.z, fRadius);
Vec4 u0 = Vec4(temp.GetColumn0().GetNormalized(), 0) * matView;
Vec4 u1 = Vec4(temp.GetColumn1().GetNormalized(), 0) * matView;
Vec4 u2 = Vec4(temp.GetColumn2().GetNormalized(), 0) * matView;
Vec3 size = fvol.m_scale.CompMul(fvol.m_localAABB.GetSize() * 0.5f);
cullInfo.volumeParams0 = Vec4(u0.x, u0.y, u0.z, size.x);
cullInfo.volumeParams1 = Vec4(u1.x, u1.y, u1.z, size.y);
cullInfo.volumeParams2 = Vec4(u2.x, u2.y, u2.z, size.z);
uint32 nData = fvol.m_stencilRef + 1;// first ref value is reserved, see CDeferredShading::PrepareClipVolumeData function.
injectInfo.miscFlag = fvol.m_volumeType | ((nData & 0xFF) << 1) | (fvol.m_affectsThisAreaOnly << 9);
injectInfo.fogColor.x = fvol.m_fogColor.r;
injectInfo.fogColor.y = fvol.m_fogColor.g;
injectInfo.fogColor.z = fvol.m_fogColor.b;
float globalDensity = fvol.m_globalDensity * 0.1f;// scale density to volumetric fog.
injectInfo.globalDensity = globalDensity;
injectInfo.fogVolumePos = fvol.m_center;
injectInfo.heightFalloffBasePoint = fvol.m_heightFallOffBasePoint;
float softEdgeLerp = (fvol.m_softEdgesLerp.x > 0.0f) ? fvol.m_softEdgesLerp.x : 0.0001f;
injectInfo.invSoftEdgeLerp = 1.0f / softEdgeLerp;
const Vec3 cHeightFallOffDirScaledVec(fvol.m_heightFallOffDirScaled * 0.015625f); // scale fall off ramp to volumetric fog.
injectInfo.heightFallOffDirScaled = cHeightFallOffDirScaledVec;
injectInfo.densityOffset = fvol.m_densityOffset;
float rampDist = fvol.m_rampParams.y - fvol.m_rampParams.x;
rampDist = rampDist < 0.1f ? 0.1f : rampDist;
float invRampDist = 1.0f / rampDist;
const Vec4 cRampParams(invRampDist, -fvol.m_rampParams.x * invRampDist, fvol.m_rampParams.z, -fvol.m_rampParams.z + 1.0f);
injectInfo.rampParams = cRampParams;
injectInfo.windOffset = fvol.m_windOffset;
injectInfo.noiseElapsedTime = fvol.m_noiseElapsedTime;
injectInfo.noiseSpatialFrequency = fvol.m_noiseFreq;
const float normalizeFactor = (1.0f / (1.0f + 0.5f));
injectInfo.noiseScale = fvol.m_noiseScale * normalizeFactor;
injectInfo.eyePosInOS = fvol.m_eyePosInOS;
injectInfo.noiseOffset = fvol.m_noiseOffset;
injectInfo.worldToObjMatrix = fvol.m_matWSInv;
++numFogVol;
}
}
m_numFogVolumes = numFogVol;
m_fogVolumeCullInfoBuf.UpdateBufferContent(cullInfoArray, sizeof(vfInternal::SFogVolumeCullInfo) * vfInternal::MaxNumFogVolumes);
m_fogVolumeInjectInfoBuf.UpdateBufferContent(injectInfoArray, sizeof(vfInternal::SFogVolumeInjectInfo) * vfInternal::MaxNumFogVolumes);
}
void CVolumetricFog::InjectFogDensity()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
SRenderPipeline& rp(rd->m_RP);
const int nThreadID = rp.m_nProcessThreadID;
// store state
const int32 prevState = rp.m_CurState;
const uint32 prevStateAnd = rp.m_StateAnd;
const uint32 prevStateOr = rp.m_StateOr;
const uint64 prevShaderRtFlags = rp.m_FlagsShader_RT;
const int prevPersFlags = rp.m_TI[nThreadID].m_PersFlags;
{
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 8, 8);
D3DUnorderedAccessView* pUAVNull[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull, NULL, 0, 4);
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
// inject the density of atmospheric fog and FogVolume into volume texture.
{
rd->GetTiledShading().BindForwardShadingResources(NULL, eHWSC_Compute);
const uint32 nScreenWidth = CTexture::s_ptexVolumetricFogDensity->GetWidth();
const uint32 nScreenHeight = CTexture::s_ptexVolumetricFogDensity->GetHeight();
const uint32 volumeDepth = CTexture::s_ptexVolumetricFogDensity->GetDepth();
//PROFILE_LABEL_SCOPE( "INJECT_FOG_DENSITY" );
static CCryNameTSCRC shaderName("InjectFogDensity");
SD3DPostEffectsUtils::ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETSTATES);
D3DUnorderedAccessView* pUAVs[2] = {
(CTexture::s_ptexVolumetricFogDensity->GetDeviceUAV()),
(CTexture::s_ptexVolumetricFogDensityColor->GetDeviceUAV()),
};
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVs, NULL, 0, 2);
D3DShaderResourceView* pSRVs[3] = {
m_fogVolumeInjectInfoBuf.GetShaderResourceView(),
m_fogVolumeCullInfoBuf.GetShaderResourceView(),
m_MaxDepth->GetShaderResourceView(),
};
rd->m_DevMan.BindSRV(eHWSC_Compute, pSRVs, 8, 3);
//D3DSamplerState *pSamplers[1] = {
// (D3DSamplerState *)CTexture::s_TexStates[m_nTexStateTriLinear].m_pDeviceState,
// //(D3DSamplerState *)CTexture::s_TexStates[m_nTexStatePoint].m_pDeviceState,
//};
//rd->m_DevMan.BindSampler( eHWSC_Compute, pSamplers, 0, 1 );
static CCryNameR paramScreenSize("ScreenSize");
float fScreenWidth = (float)nScreenWidth;
float fScreenHeight = (float)nScreenHeight;
Vec4 vParamScreenSize(fScreenWidth, fScreenHeight, 1.0f / fScreenWidth, 1.0f / fScreenHeight);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramScreenSize, &vParamScreenSize, 1);
SD3DPostEffectsUtils::UpdateFrustumCorners();
static CCryNameR paramFrustumTL("FrustumTL");
Vec4 vParamFrustumTL(SD3DPostEffectsUtils::m_vLT.x, SD3DPostEffectsUtils::m_vLT.y, SD3DPostEffectsUtils::m_vLT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTL, &vParamFrustumTL, 1);
static CCryNameR paramFrustumTR("FrustumTR");
Vec4 vParamFrustumTR(SD3DPostEffectsUtils::m_vRT.x, SD3DPostEffectsUtils::m_vRT.y, SD3DPostEffectsUtils::m_vRT.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumTR, &vParamFrustumTR, 1);
static CCryNameR paramFrustumBL("FrustumBL");
Vec4 vParamFrustumBL(SD3DPostEffectsUtils::m_vLB.x, SD3DPostEffectsUtils::m_vLB.y, SD3DPostEffectsUtils::m_vLB.z, 0);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramFrustumBL, &vParamFrustumBL, 1);
float octave = (CRenderer::CV_r_VolumetricFogReprojectionBlendFactor > 0.0f) ? -1.7f : 0.0f;
static CCryNameR paramInjectExponentialHeightFogParams("InjectFogDensityParams");
Vec4 vInjectExponentialHeightFogParams((float)volumeDepth, (float)m_numFogVolumes, octave, 0.0f);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramInjectExponentialHeightFogParams, &vInjectExponentialHeightFogParams, 1);
static CCryNameR paramProj("ProjParams");
Vec4 vParamProj(rd->m_ProjMatrix.m00, rd->m_ProjMatrix.m11, rd->m_ProjMatrix.m20, rd->m_ProjMatrix.m21);
CShaderMan::s_shDeferredShading->FXSetCSFloat(paramProj, &vParamProj, 1);
const uint32 tileSizeX = 4;
const uint32 tileSizeY = 4;
const uint32 tileSizeZ = 4;
uint32 dispatchSizeX = (nScreenWidth / tileSizeX) + (nScreenWidth % tileSizeX > 0 ? 1 : 0);
uint32 dispatchSizeY = (nScreenHeight / tileSizeY) + (nScreenHeight % tileSizeY > 0 ? 1 : 0);
uint32 dispatchSizeZ = (volumeDepth / tileSizeZ) + (volumeDepth % tileSizeZ > 0 ? 1 : 0);
rd->FX_Commit();
rd->m_DevMan.Dispatch(dispatchSizeX, dispatchSizeY, dispatchSizeZ);
SD3DPostEffectsUtils::ShEndPass();
rd->GetTiledShading().UnbindForwardShadingResources(eHWSC_Compute);
}
D3DUnorderedAccessView* pUAVNull4[4] = { NULL };
rd->m_DevMan.BindUAV(eHWSC_Compute, pUAVNull4, NULL, 0, 4);
D3DShaderResourceView* pNullViews[8] = { NULL };
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 0, 8);
rd->m_DevMan.BindSRV(eHWSC_Compute, pNullViews, 8, 8);
//D3DSamplerState* pSampNull[2] = { NULL };
//rd->m_DevMan.BindSampler( eHWSC_Compute, pSampNull, 0, 2 );
// restore state
rp.m_StateAnd = prevStateAnd;
rp.m_StateOr = prevStateOr;
rd->SetState(prevState);
rp.m_TI[nThreadID].m_PersFlags = prevPersFlags;
rp.m_FlagsShader_RT = prevShaderRtFlags;
rd->FX_Commit();
rd->m_DevMan.CommitDeviceStates();
}
void CVolumetricFog::RenderDownscaledShadowmap()
{
if (!gcpRendD3D->m_bShadowsEnabled)
{
return;
}
if (CRenderer::CV_r_VolumetricFogDownscaledSunShadow == 0)
{
return;
}
//PROFILE_LABEL_SCOPE("DOWNSCALE_SHADOWMAP");
CD3D9Renderer* const __restrict rd = gcpRendD3D;
SRenderPipeline& rp(rd->m_RP);
// store state
int oldX, oldY;
int oldWidth, oldHeight;
rd->GetViewport(&oldX, &oldY, &oldWidth, &oldHeight);
const uint64 prevShaderRtFlags = rp.m_FlagsShader_RT;
rd->FX_SetupShadowsForFog();
SDepthTexture D3dDepthSurface;
static const int texStatePoint = CTexture::GetTexState(STexState(FILTER_POINT, true));
int count = (CRenderer::CV_r_VolumetricFogDownscaledSunShadow == 1) ? 2 : 3;
for (int i = 0; i < count; ++i)
{
{
const uint64 lv0 = g_HWSR_MaskBit[HWSR_LIGHTVOLUME0];
const uint64 lv1 = g_HWSR_MaskBit[HWSR_LIGHTVOLUME1];
rp.m_FlagsShader_RT &= ~(lv0 | lv1);
switch (i)
{
case 0:
rp.m_FlagsShader_RT |= lv0;
break;
case 1:
rp.m_FlagsShader_RT |= lv1;
break;
case 2:
rp.m_FlagsShader_RT |= lv0 | lv1;
break;
default:
break;
}
CTexture* target = NULL;
if (CRenderer::CV_r_VolumetricFogDownscaledSunShadowRatio == 0)
{
target = m_downscaledShadow[i];
}
else
{
target = m_downscaledShadowTemp;
}
int targetWidth = target->GetWidth();
int targetHeight = target->GetHeight();
D3dDepthSurface.nWidth = targetWidth;
D3dDepthSurface.nHeight = targetHeight;
D3dDepthSurface.pTex = target;
D3dDepthSurface.pSurf = (D3DDepthSurface*)target->GetDeviceDepthStencilSurf();
D3dDepthSurface.pTarget = target->GetDevTexture()->Get2DTexture();
rd->FX_PushRenderTarget(0, (CTexture*)NULL, &D3dDepthSurface);
rd->FX_SetActiveRenderTargets();
rd->FX_SetState(GS_COLMASK_NONE | GS_DEPTHWRITE | GS_DEPTHFUNC_NOTEQUAL);
static CCryNameTSCRC shaderName("RenderDownscaledShadowMap");
GetUtils().ShBeginPass(CShaderMan::s_shDeferredShading, shaderName, FEF_DONTSETSTATES);
D3DSamplerState* pSamplers[1] = {
(D3DSamplerState*)CTexture::s_TexStates[m_nTexStatePoint].m_pDeviceState,
};
rd->m_DevMan.BindSampler(eHWSC_Pixel, pSamplers, 0, 1);
GetUtils().DrawFullScreenTri(targetWidth, targetHeight);
GetUtils().ShEndPass();
rd->FX_PopRenderTarget(0);
rp.m_FlagsShader_RT = prevShaderRtFlags;
}
// additional downscale pass
if (CRenderer::CV_r_VolumetricFogDownscaledSunShadowRatio != 0)
{
CTexture* source = m_downscaledShadowTemp;
CTexture* target = m_downscaledShadow[i];
int targetWidth = target->GetWidth();
int targetHeight = target->GetHeight();
D3dDepthSurface.nWidth = targetWidth;
D3dDepthSurface.nHeight = targetHeight;
D3dDepthSurface.pTex = target;
D3dDepthSurface.pSurf = target->GetDeviceDepthStencilSurf();
D3dDepthSurface.pTarget = target->GetDevTexture()->Get2DTexture();
rd->FX_PushRenderTarget(0, (CTexture*)NULL, &D3dDepthSurface);
rd->FX_SetActiveRenderTargets();
rd->FX_SetState(GS_COLMASK_NONE | GS_DEPTHWRITE | GS_DEPTHFUNC_NOTEQUAL);
static CCryNameTSCRC shaderName0("DownscaleShadowMap2");
static CCryNameTSCRC shaderName1("DownscaleShadowMap4");
if (CRenderer::CV_r_VolumetricFogDownscaledSunShadowRatio == 1)
{
GetUtils().ShBeginPass(CShaderMan::s_shDeferredShading, shaderName0, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
}
else
{
GetUtils().ShBeginPass(CShaderMan::s_shDeferredShading, shaderName1, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
}
source->Apply(0, texStatePoint, EFTT_UNKNOWN, -1, SResourceView::DefaultView);
GetUtils().DrawFullScreenTri(targetWidth, targetHeight);
GetUtils().ShEndPass();
rd->FX_PopRenderTarget(0);
}
}
// restore pipeline state.
rd->RT_SetViewport(oldX, oldY, oldWidth, oldHeight);
rp.m_FlagsShader_RT = prevShaderRtFlags;
rd->FX_Commit();
}
void CVolumetricFog::SetupStaticShadowMap(int nSlot) const
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
SRenderPipeline& rp(rd->m_RP);
const int nThreadID = rp.m_nProcessThreadID;
const int nSunFrustumID = 0;
const int nStartIdx = SRendItem::m_StartFrust[nThreadID][nSunFrustumID];
const int nEndIdx = SRendItem::m_EndFrust[nThreadID][nSunFrustumID];
for (int i = nStartIdx; i < nEndIdx; ++i)
{
ShadowMapFrustum& fr = rp.m_SMFrustums[nThreadID][nSunFrustumID][i];
if (fr.m_eFrustumType == ShadowMapFrustum::e_GsmCached)
{
rd->ConfigShadowTexgen(nSlot, &fr, -1, true);
break;
}
}
}