1 // Copyright 2001-2015 Crytek GmbH. All rights reserved.
4 #include "ClipVolumes.h"
6 #include "VolumetricFog.h"
8 struct SPrimitiveConstants
10 Matrix44 transformMatrix
;
11 Vec4 projRatioScreenScale
;
16 struct SPrimitiveVolFogConstants
18 Matrix44 transformMatrix
;
22 CClipVolumesStage::CClipVolumesStage()
23 : m_nShaderParamCount(0)
24 , m_pBlendValuesRT(nullptr)
25 , m_pDepthTarget(nullptr)
26 , m_pClipVolumeStencilVolumeTex(nullptr)
27 , m_cleared(MAX_GPU_NUM
)
29 , m_raymarchDistance(0.0f
)
30 , m_bClipVolumesValid(false)
31 , m_bBlendPassReady(false)
32 , m_bOutdoorVisible(false)
34 ZeroArray(m_clipVolumeShaderParams
);
35 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
36 memset(&m_depthTargetVolFog
, 0, sizeof(m_depthTargetVolFog
));
40 CClipVolumesStage::~CClipVolumesStage()
42 SAFE_RELEASE(m_pClipVolumeStencilVolumeTex
);
43 #ifndef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
44 for (auto& pTex
: m_pClipVolumeStencilVolumeTexArray
)
51 void CClipVolumesStage::Init()
53 m_stencilPass
.SetFlags(CPrimitiveRenderPass::ePassFlags_VrProjectionPass
);
54 m_blendValuesPass
.SetFlags(CPrimitiveRenderPass::ePassFlags_VrProjectionPass
);
55 m_stencilResolvePass
.SetFlags(CPrimitiveRenderPass::ePassFlags_VrProjectionPass
);
57 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
58 m_volumetricStencilPass
.SetFlags(CPrimitiveRenderPass::ePassFlags_None
);
61 for (int i
= 0; i
< MaxDeferredClipVolumes
; ++i
)
63 // Stencil pass: two primitives per clip volume, both share the same constant buffer
65 CConstantBufferPtr pCB
= gcpRendD3D
->m_DevBufMan
.CreateConstantBuffer(sizeof(SPrimitiveConstants
));
67 m_stencilPrimitives
[2 * i
+ 0].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch
, pCB
, EShaderStage_Vertex
);
68 m_stencilPrimitives
[2 * i
+ 1].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch
, pCB
, EShaderStage_Vertex
);
70 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
71 pCB
= gcpRendD3D
->m_DevBufMan
.CreateConstantBuffer(sizeof(SPrimitiveVolFogConstants
));
72 m_stencilPrimitivesVolFog
[2 * i
+ 0].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch
, pCB
, EShaderStage_Geometry
| EShaderStage_Vertex
);
73 m_stencilPrimitivesVolFog
[2 * i
+ 1].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch
, pCB
, EShaderStage_Geometry
| EShaderStage_Vertex
);
77 // Blend values pass: one primitive per clip volume, shared CB for vertex and pixel shader
79 CConstantBufferPtr pCB
= gcpRendD3D
->m_DevBufMan
.CreateConstantBuffer(sizeof(SPrimitiveConstants
));
81 m_blendPrimitives
[i
].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch
, pCB
, EShaderStage_Pixel
| EShaderStage_Vertex
);
86 // TODO: move this texture to intra-view-shared data structure after removing old graphics pipeline.
87 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
88 const uint32 flags
= FT_NOMIPS
| FT_DONT_STREAM
| FT_USAGE_DEPTHSTENCIL
;
90 const uint32 flags
= FT_NOMIPS
| FT_DONT_STREAM
| FT_USAGE_RENDERTARGET
;
92 CRY_ASSERT(m_pClipVolumeStencilVolumeTex
== nullptr);
93 m_pClipVolumeStencilVolumeTex
= CTexture::GetOrCreateTextureObject("$VolFogClipVolumeStencil", 0, 0, 0, eTT_2D
, flags
, eTF_Unknown
);
96 void CClipVolumesStage::Prepare(CRenderView
* pRenderView
)
98 m_nShaderParamCount
= 0;
99 m_bClipVolumesValid
= false;
100 m_bOutdoorVisible
= false;
102 m_pBlendValuesRT
= CTexture::s_ptexVelocity
;
103 m_pDepthTarget
= gcpRendD3D
->m_pZTexture
;
105 D3DViewPort viewport
;
106 viewport
.TopLeftX
= viewport
.TopLeftY
= 0.0f
;
107 viewport
.Width
= (float)m_pBlendValuesRT
->GetWidth();
108 viewport
.Height
= (float)m_pBlendValuesRT
->GetHeight();
109 viewport
.MinDepth
= 0.0f
;
110 viewport
.MaxDepth
= 1.0f
;
112 m_stencilPass
.SetDepthTarget(m_pDepthTarget
);
113 m_stencilPass
.SetViewport(viewport
);
114 m_stencilPass
.BeginAddingPrimitives();
116 m_blendValuesPass
.SetRenderTarget(0, m_pBlendValuesRT
);
117 m_blendValuesPass
.SetDepthTarget(m_pDepthTarget
);
118 m_blendValuesPass
.SetViewport(viewport
);
119 m_blendValuesPass
.BeginAddingPrimitives();
121 PrepareVolumetricFog();
122 if (gcpRendD3D
->m_bVolumetricFogEnabled
)
124 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
125 m_volumetricStencilPass
.BeginAddingPrimitives();
127 for (auto& pass
: m_volumetricStencilPassArray
)
128 pass
->BeginAddingPrimitives();
132 const uint32 StencilStateInitialMarkup
=
133 STENC_FUNC(FSS_STENCFUNC_GEQUAL
) |
134 STENCOP_FAIL(FSS_STENCOP_KEEP
) |
135 STENCOP_ZFAIL(FSS_STENCOP_REPLACE
) |
136 STENCOP_PASS(FSS_STENCOP_KEEP
);
138 const uint32 StencilStateInsideOutsideMarkup
=
139 STENC_FUNC(FSS_STENCFUNC_GEQUAL
) |
140 STENCOP_FAIL(FSS_STENCOP_KEEP
) |
141 STENCOP_ZFAIL(FSS_STENCOP_INVERT
) |
142 STENCOP_PASS(FSS_STENCOP_KEEP
);
144 const uint32 StencilStateTest
=
145 STENC_FUNC(FSS_STENCFUNC_EQUAL
) |
146 STENCOP_FAIL(FSS_STENCOP_KEEP
) |
147 STENCOP_ZFAIL(FSS_STENCOP_KEEP
) |
148 STENCOP_PASS(FSS_STENCOP_KEEP
);
150 const uint8 StencilReadWriteMask
= 0xFF & ~BIT_STENCIL_RESERVED
;
152 static CCryNameTSCRC techStencil
= "ClipVolumeStencil";
153 static CCryNameTSCRC techPortalBlend
= "ClipVolumeBlendValue";
155 static ICVar
* pPortalsBlendCVar
= iConsole
->GetCVar("e_PortalsBlend");
156 const bool bRenderPortalBlendValues
= pPortalsBlendCVar
->GetIVal() > 0;
157 const bool bRenderVisAreas
= CRenderer::CV_r_VisAreaClipLightsPerPixel
> 0;
159 const auto& clipVolumes
= pRenderView
->GetClipVolumes();
160 CStandardGraphicsPipeline::SViewInfo viewInfo
[2];
161 int viewInfoCount
= gcpRendD3D
->GetGraphicsPipeline().GetViewInfo(viewInfo
);
162 const CRenderCamera
& rc
= *(viewInfo
[0].pRenderCamera
);
163 const bool bReverseDepth
= (viewInfo
[0].flags
& CStandardGraphicsPipeline::SViewInfo::eFlags_ReverseDepth
) != 0;
168 projRatio
.x
= bReverseDepth
? zn
/ (zn
- zf
) : zf
/ (zf
- zn
);
169 projRatio
.y
= bReverseDepth
? zn
/ (zf
- zn
) : zn
/ (zn
- zf
);
171 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
172 static CCryNameTSCRC techStencilVolFog
= "ClipVolumeStencilVolFog";
173 const Vec3 cameraFrontVec
= rc
.vZ
;
174 SCGParamsPF
& PF
= gcpRendD3D
->m_cEF
.m_PF
[gcpRendD3D
->m_RP
.m_nProcessThreadID
];
175 const float raymarchStart
= PF
.pVolumetricFogSamplingParams
.x
;
176 const float invRaymarchDistance
= PF
.pVolumetricFogSamplingParams
.y
;
177 const int32 volFogDepthNum
= CVolumetricFogStage::GetVolumeTextureDepthSize();
178 const float fVolFogDepthNum
= static_cast<float>(volFogDepthNum
);
179 const int32 maxDepthSliceNum
= 64; // this must exactly match to ClipVolumeVolFogGS shader's limitation.
182 m_nShaderParamCount
= 0;
183 for (int i
= 0; i
< VisAreasOutdoorStencilOffset
; ++i
)
185 uint32 nFlags
= IClipVolume::eClipVolumeConnectedToOutdoor
| IClipVolume::eClipVolumeAffectedBySun
;
186 m_clipVolumeShaderParams
[m_nShaderParamCount
++] = Vec4(gEnv
->p3DEngine
->GetSkyColor() * gcpRendD3D
->m_fAdaptedSceneScaleLBuffer
, alias_cast
<float>(nFlags
));
189 for (const auto& volume
: clipVolumes
)
191 // Update shader params
192 const uint32 paramIndex
= volume
.nStencilRef
+ 1;
193 CRY_ASSERT(paramIndex
>= VisAreasOutdoorStencilOffset
);
195 if (paramIndex
< MaxDeferredClipVolumes
)
198 (volume
.blendInfo
[1].blendID
+ 1) << 24 |
199 (volume
.blendInfo
[0].blendID
+ 1) << 16 |
202 m_clipVolumeShaderParams
[paramIndex
] = Vec4(0, 0, 0, alias_cast
<float>(nData
));
203 m_bOutdoorVisible
|= volume
.nFlags
& IClipVolume::eClipVolumeConnectedToOutdoor
? true : false;
205 m_nShaderParamCount
= max(m_nShaderParamCount
, paramIndex
+ 1);
209 // Create stencil and blend pass primitives
210 for (int i
= clipVolumes
.size() - 1; i
>= 0; --i
)
212 const SDeferredClipVolume
& volume
= clipVolumes
[i
];
213 if (volume
.m_pRenderMesh
&& volume
.nStencilRef
< MaxDeferredClipVolumes
)
215 if ((volume
.nFlags
& IClipVolume::eClipVolumeIsVisArea
) != 0 && !bRenderVisAreas
)
218 CRY_ASSERT(((volume
.nStencilRef
+ 1) & (BIT_STENCIL_RESERVED
| BIT_STENCIL_INSIDE_CLIPVOLUME
)) == 0);
219 const int stencilRef
= ~(volume
.nStencilRef
+ 1) & ~(BIT_STENCIL_RESERVED
| BIT_STENCIL_INSIDE_CLIPVOLUME
);
221 buffer_handle_t hVertexStream
= ~0u;
222 buffer_handle_t hIndexStream
= ~0u;
223 CRenderMesh
* pRenderMesh
= nullptr;
225 if (pRenderMesh
= reinterpret_cast<CRenderMesh
*>(volume
.m_pRenderMesh
.get()))
227 hVertexStream
= pRenderMesh
->_GetVBStream(VSF_GENERAL
);
228 hIndexStream
= pRenderMesh
->_GetIBStream();
230 if (hVertexStream
!= ~0u && hIndexStream
!= ~0u)
233 CRenderPrimitive
& primInit
= m_stencilPrimitives
[2 * i
+ 0];
234 primInit
.SetTechnique(CShaderMan::s_shDeferredShading
, techStencil
, 0);
235 primInit
.SetRenderState((bReverseDepth
? GS_DEPTHFUNC_GEQUAL
: GS_DEPTHFUNC_LEQUAL
) | GS_STENCIL
);
236 primInit
.SetCustomVertexStream(hVertexStream
, pRenderMesh
->_GetVertexFormat(), pRenderMesh
->GetStreamStride(VSF_GENERAL
));
237 primInit
.SetCustomIndexStream(hIndexStream
, (sizeof(vtx_idx
) == 2 ? Index16
: Index32
));
238 primInit
.SetCullMode(eCULL_Front
);
239 primInit
.SetStencilState(StencilStateInitialMarkup
, stencilRef
, StencilReadWriteMask
, StencilReadWriteMask
);
240 primInit
.SetDrawInfo(eptTriangleList
, 0, 0, pRenderMesh
->_GetNumInds());
241 primInit
.Compile(m_stencilPass
);
243 // Update constant buffer. NOTE: buffer is assigned to preallocated primitives
244 auto& constantManager
= primInit
.GetConstantManager();
246 auto constants
= constantManager
.BeginTypedConstantUpdate
<SPrimitiveConstants
>(eConstantBufferShaderSlot_PerBatch
, EShaderStage_Vertex
);
247 constants
->transformMatrix
= Matrix44(volume
.mWorldTM
.GetTransposed()) * viewInfo
[0].cameraProjMatrix
;
249 if (viewInfoCount
> 1)
251 constants
.BeginStereoOverride();
252 constants
->transformMatrix
= Matrix44(volume
.mWorldTM
.GetTransposed()) * viewInfo
[1].cameraProjMatrix
;
255 constantManager
.EndTypedConstantUpdate(constants
);
257 // Inside/outside test
258 CRenderPrimitive
& primMarkup
= m_stencilPrimitives
[2 * i
+ 1];
259 primMarkup
.SetTechnique(CShaderMan::s_shDeferredShading
, techStencil
, 0);
260 primMarkup
.SetRenderState((bReverseDepth
? GS_DEPTHFUNC_GEQUAL
: GS_DEPTHFUNC_LEQUAL
) | GS_STENCIL
);
261 primMarkup
.SetCustomVertexStream(hVertexStream
, pRenderMesh
->_GetVertexFormat(), pRenderMesh
->GetStreamStride(VSF_GENERAL
));
262 primMarkup
.SetCustomIndexStream(hIndexStream
, (sizeof(vtx_idx
) == 2 ? Index16
: Index32
));
263 primMarkup
.SetCullMode(eCULL_None
);
264 primMarkup
.SetStencilState(StencilStateInsideOutsideMarkup
, ~stencilRef
, StencilReadWriteMask
, StencilReadWriteMask
);
265 primMarkup
.SetDrawInfo(eptTriangleList
, 0, 0, pRenderMesh
->_GetNumInds());
266 primMarkup
.Compile(m_stencilPass
);
268 m_stencilPass
.AddPrimitive(&primInit
);
269 m_stencilPass
.AddPrimitive(&primMarkup
);
271 if (gcpRendD3D
->m_bVolumetricFogEnabled
)
273 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
274 // calculate min depth index of volumetric fog coordinate.
275 const float radius
= volume
.mAABB
.GetRadius();
276 const float distToCenter
= -rc
.WorldToCamZ(volume
.mAABB
.GetCenter());
277 const float minW
= max(distToCenter
- radius
, 0.0f
);
278 float fMinDepthIndex
= fVolFogDepthNum
* CVolumetricFogStage::GetDepthTexcoordFromLinearDepthScaled(minW
, raymarchStart
, invRaymarchDistance
, fVolFogDepthNum
);
279 fMinDepthIndex
= max(0.0f
, floorf(fMinDepthIndex
));
280 int32 minDepthIndex
= static_cast<int32
>(fMinDepthIndex
);
281 minDepthIndex
= max(min(minDepthIndex
, volFogDepthNum
- 1), 0);
283 // prepare primitive for volumetric fog when it's in the range of volumetric fog.
284 if (minDepthIndex
< volFogDepthNum
)
287 CRenderPrimitive
& primInit
= m_stencilPrimitivesVolFog
[2 * i
+ 0];
288 primInit
.SetTechnique(CShaderMan::s_shDeferredShading
, techStencilVolFog
, 0);
289 primInit
.SetRenderState((bReverseDepth
? GS_DEPTHFUNC_GEQUAL
: GS_DEPTHFUNC_LEQUAL
) | GS_STENCIL
);
290 primInit
.SetCustomVertexStream(hVertexStream
, pRenderMesh
->_GetVertexFormat(), pRenderMesh
->GetStreamStride(VSF_GENERAL
));
291 primInit
.SetCustomIndexStream(hIndexStream
, (sizeof(vtx_idx
) == 2 ? Index16
: Index32
));
292 primInit
.SetCullMode(eCULL_Front
);
293 primInit
.SetStencilState(StencilStateInitialMarkup
, stencilRef
, StencilReadWriteMask
, StencilReadWriteMask
);
294 primInit
.SetDrawInfo(eptTriangleList
, 0, 0, pRenderMesh
->_GetNumInds());
295 primInit
.Compile(m_volumetricStencilPass
);
297 // Update constant buffer. NOTE: buffer is assigned to preallocated primitives
298 auto& constantManager
= primInit
.GetConstantManager();
300 auto constants
= constantManager
.BeginTypedConstantUpdate
<SPrimitiveVolFogConstants
>(eConstantBufferShaderSlot_PerBatch
, EShaderStage_Geometry
| EShaderStage_Vertex
);
301 constants
->transformMatrix
= Matrix44(volume
.mWorldTM
.GetTransposed()) * viewInfo
[0].cameraProjMatrix
;
303 // calculate max depth index of volumetric fog coordinate.
304 const float maxW
= max(distToCenter
+ radius
, 0.0f
);
305 float fMaxDepthIndex
= fVolFogDepthNum
* CVolumetricFogStage::GetDepthTexcoordFromLinearDepthScaled(maxW
, raymarchStart
, invRaymarchDistance
, fVolFogDepthNum
);
306 fMaxDepthIndex
= max(0.0f
, ceilf(fMaxDepthIndex
));
307 int32 maxDepthIndex
= static_cast<int32
>(fMaxDepthIndex
);
309 maxDepthIndex
= max(maxDepthIndex
, 0);
310 maxDepthIndex
= min(maxDepthIndex
, minDepthIndex
+ maxDepthSliceNum
);
311 maxDepthIndex
= min(maxDepthIndex
, volFogDepthNum
);
313 constants
->sliceIndex
[0] = minDepthIndex
;
314 constants
->sliceIndex
[1] = maxDepthIndex
;
316 if (viewInfoCount
> 1)
318 constants
.BeginStereoOverride();
319 constants
->transformMatrix
= Matrix44(volume
.mWorldTM
.GetTransposed()) * viewInfo
[1].cameraProjMatrix
;
320 constants
->sliceIndex
[0] = minDepthIndex
;
321 constants
->sliceIndex
[1] = maxDepthIndex
;
324 constantManager
.EndTypedConstantUpdate(constants
);
326 // Inside/outside test
327 CRenderPrimitive
& primMarkup
= m_stencilPrimitivesVolFog
[2 * i
+ 1];
328 primMarkup
.SetTechnique(CShaderMan::s_shDeferredShading
, techStencilVolFog
, 0);
329 primMarkup
.SetRenderState((bReverseDepth
? GS_DEPTHFUNC_GEQUAL
: GS_DEPTHFUNC_LEQUAL
) | GS_STENCIL
);
330 primMarkup
.SetCustomVertexStream(hVertexStream
, pRenderMesh
->_GetVertexFormat(), pRenderMesh
->GetStreamStride(VSF_GENERAL
));
331 primMarkup
.SetCustomIndexStream(hIndexStream
, (sizeof(vtx_idx
) == 2 ? Index16
: Index32
));
332 primMarkup
.SetCullMode(eCULL_None
);
333 primMarkup
.SetStencilState(StencilStateInsideOutsideMarkup
, ~stencilRef
, StencilReadWriteMask
, StencilReadWriteMask
);
334 primMarkup
.SetDrawInfo(eptTriangleList
, 0, 0, pRenderMesh
->_GetNumInds());
335 primMarkup
.Compile(m_volumetricStencilPass
);
337 m_volumetricStencilPass
.AddPrimitive(&primInit
);
338 m_volumetricStencilPass
.AddPrimitive(&primMarkup
);
341 for (auto& pass
: m_volumetricStencilPassArray
)
343 pass
->AddPrimitive(&primInit
);
344 pass
->AddPrimitive(&primMarkup
);
352 if (bRenderPortalBlendValues
&& (volume
.nFlags
& IClipVolume::eClipVolumeBlend
))
354 const int stencilTestRef
= BIT_STENCIL_INSIDE_CLIPVOLUME
+ volume
.nStencilRef
+ 1;
356 CRenderPrimitive
& primBlend
= m_blendPrimitives
[i
];
357 primBlend
.SetTechnique(CShaderMan::s_shDeferredShading
, techPortalBlend
, CVrProjectionManager::Instance()->GetRTFlags());
358 primBlend
.SetRenderState(GS_STENCIL
| GS_NODEPTHTEST
| GS_NOCOLMASK_R
| GS_NOCOLMASK_B
| GS_NOCOLMASK_A
);
359 primBlend
.SetTexture(3, CTexture::s_ptexZTarget
);
360 primBlend
.SetCullMode(eCULL_Front
);
361 primBlend
.SetStencilState(StencilStateTest
, stencilTestRef
, StencilReadWriteMask
, StencilReadWriteMask
);
362 primBlend
.Compile(m_blendValuesPass
);
364 auto& constantManager
= primBlend
.GetConstantManager();
365 auto constants
= constantManager
.BeginTypedConstantUpdate
<SPrimitiveConstants
>(eConstantBufferShaderSlot_PerBatch
, EShaderStage_Pixel
| EShaderStage_Vertex
);
367 constants
->projRatioScreenScale
= Vec4(projRatio
.x
, projRatio
.y
, 1.0f
/ m_pBlendValuesRT
->GetWidth(), 1.0f
/ m_pBlendValuesRT
->GetHeight());
368 constants
->blendPlane0
= viewInfo
[0].invCameraProjMatrix
* volume
.blendInfo
[0].blendPlane
;
369 constants
->blendPlane1
= viewInfo
[0].invCameraProjMatrix
* volume
.blendInfo
[1].blendPlane
;
371 if (hVertexStream
!= ~0u && hIndexStream
!= ~0u)
373 constants
->transformMatrix
= Matrix44(volume
.mWorldTM
.GetTransposed()) * viewInfo
[0].cameraProjMatrix
;
375 primBlend
.SetCustomVertexStream(hVertexStream
, pRenderMesh
->_GetVertexFormat(), pRenderMesh
->GetStreamStride(VSF_GENERAL
));
376 primBlend
.SetCustomIndexStream(hIndexStream
, (sizeof(vtx_idx
) == 2 ? Index16
: Index32
));
377 primBlend
.SetDrawInfo(eptTriangleList
, 0, 0, pRenderMesh
->_GetNumInds());
381 constants
->transformMatrix
= Matrix44(IDENTITY
);
383 primBlend
.SetPrimitiveType(CRenderPrimitive::ePrim_Triangle
);
384 primBlend
.SetDrawInfo(eptTriangleList
, 0, 0, 3);
387 if (viewInfoCount
> 1)
389 constants
.BeginStereoOverride();
390 constants
->blendPlane0
= viewInfo
[1].invCameraProjMatrix
* volume
.blendInfo
[0].blendPlane
;
391 constants
->blendPlane1
= viewInfo
[1].invCameraProjMatrix
* volume
.blendInfo
[1].blendPlane
;
393 if (hVertexStream
!= ~0u && hIndexStream
!= ~0u)
394 constants
->transformMatrix
= Matrix44(volume
.mWorldTM
.GetTransposed()) * viewInfo
[1].cameraProjMatrix
;
398 constantManager
.EndTypedConstantUpdate(constants
);
400 m_blendValuesPass
.AddPrimitive(&primBlend
);
406 void CClipVolumesStage::Execute()
408 PROFILE_LABEL_SCOPE("CLIPVOLUMES");
410 // Render clip volumes to stencil
411 m_stencilPass
.Execute();
413 // Render portal blend values
414 m_blendValuesPass
.Execute();
416 // Resolve final stencil buffer
418 static CCryNameTSCRC
techResolveStencil("ResolveStencil");
420 m_stencilResolvePass
.SetPrimitiveFlags(CRenderPrimitive::eFlags_None
);
421 m_stencilResolvePass
.SetTechnique(CShaderMan::s_shDeferredShading
, techResolveStencil
, 0);
422 m_stencilResolvePass
.SetRenderTarget(0, m_pBlendValuesRT
);
423 m_stencilResolvePass
.SetState(GS_NODEPTHTEST
| GS_NOCOLMASK_G
| GS_NOCOLMASK_B
| GS_NOCOLMASK_A
);
424 m_stencilResolvePass
.SetTexture(4, m_pDepthTarget
, EDefaultResourceViews::StencilOnly
);
425 m_stencilResolvePass
.BeginConstantUpdate();
426 m_stencilResolvePass
.Execute();
429 ExecuteVolumetricFog();
431 m_bClipVolumesValid
= true;
434 CTexture
* CClipVolumesStage::GetClipVolumeStencilVolumeTexture() const
436 return m_pClipVolumeStencilVolumeTex
;
439 void CClipVolumesStage::PrepareVolumetricFog()
441 if (gcpRendD3D
->m_bVolumetricFogEnabled
)
443 const int32 screenWidth
= gcpRendD3D
->GetWidth();
444 const int32 screenHeight
= gcpRendD3D
->GetHeight();
446 // size for view frustum aligned volume texture.
447 const int32 scaledWidth
= CVolumetricFogStage::GetVolumeTextureSize(screenWidth
, CRenderer::CV_r_VolumetricFogTexScale
);
448 const int32 scaledHeight
= CVolumetricFogStage::GetVolumeTextureSize(screenHeight
, CRenderer::CV_r_VolumetricFogTexScale
);
449 const int32 depth
= CVolumetricFogStage::GetVolumeTextureDepthSize();
451 D3DViewPort viewport
;
452 viewport
.TopLeftX
= viewport
.TopLeftY
= 0.0f
;
453 viewport
.Width
= static_cast<float>(scaledWidth
);
454 viewport
.Height
= static_cast<float>(scaledHeight
);
455 viewport
.MinDepth
= 0.0f
;
456 viewport
.MaxDepth
= 1.0f
;
458 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
459 CRY_ASSERT(m_pClipVolumeStencilVolumeTex
);
460 if (m_pClipVolumeStencilVolumeTex
461 && (m_pClipVolumeStencilVolumeTex
->GetWidth() != scaledWidth
462 || m_pClipVolumeStencilVolumeTex
->GetHeight() != scaledHeight
463 || !CTexture::IsTextureExist(m_pClipVolumeStencilVolumeTex
))
464 || m_depthTargetArrayVolFog
.empty()
465 || m_depthTargetArrayVolFog
.size() != depth
)
467 m_volumetricStencilPass
.SetViewport(viewport
);
469 // create jittered depth passes
471 for (int32 i
= 0; i
< m_jitteredDepthPassArray
.size(); ++i
)
473 m_jitteredDepthPassArray
[i
].reset();
476 m_jitteredDepthPassArray
.resize(depth
);
478 for (int32 i
= 0; i
< depth
; ++i
)
480 m_jitteredDepthPassArray
[i
] = stl::make_unique
<CFullscreenPass
>();
481 m_jitteredDepthPassArray
[i
]->SetViewport(viewport
);
482 m_jitteredDepthPassArray
[i
]->SetFlags(CPrimitiveRenderPass::ePassFlags_None
);
486 m_depthTargetArrayVolFog
.clear();
487 m_depthTargetArrayVolFog
.resize(depth
);
489 const uint32 commonFlags
= FT_NOMIPS
| FT_DONT_STREAM
| FT_DONT_RELEASE
;
490 const uint32 rtFlags
= commonFlags
| FT_USAGE_RENDERTARGET
;
491 const uint32 dsFlags
= commonFlags
| FT_USAGE_DEPTHSTENCIL
;
492 const int32 w
= scaledWidth
;
493 const int32 h
= scaledHeight
;
494 const int32 d
= depth
;
495 ETEX_Format format
= eTF_D24S8
;
496 CTexture
* pTex
= CTexture::GetOrCreateTextureArray("$VolFogClipVolumeStencil", w
, h
, d
, 1, eTT_2DArray
, dsFlags
, format
);
499 || m_pClipVolumeStencilVolumeTex
!= pTex
// texture name must exactly match the name when creating texture object.
500 || pTex
->GetFlags() & FT_FAILED
)
502 CryFatalError("Couldn't allocate texture.");
505 // DSV to clear stencil buffer.
506 m_depthTargetVolFog
= m_pClipVolumeStencilVolumeTex
;
508 // separate DSVs to write jittering depth.
509 for (int32 i
= 0; i
< m_depthTargetArrayVolFog
.size(); ++i
)
511 SResourceView sliceView
= SResourceView::DepthStencilView(DeviceFormats::ConvertFromTexFormat(m_depthTargetVolFog
->GetDstFormat()), i
, 1, 0);
512 m_depthTargetArrayVolFog
[i
] = m_depthTargetVolFog
->GetDevTexture()->GetOrCreateResourceViewHandle(sliceView
); // separate DSV
515 // set depth target before AddPrimitive() is called.
516 m_volumetricStencilPass
.SetDepthTarget(m_depthTargetVolFog
);
518 // this buffer is managed explicitly on multi GPU.
519 m_pClipVolumeStencilVolumeTex
->DisableMgpuSync();
521 // need to clear depth buffer.
522 const int32 safeMargin
= 2; // workaround: shader isn't activated in initial several frames.
523 m_cleared
= gcpRendD3D
->GetActiveGPUCount() + safeMargin
;
526 CRY_ASSERT(m_pClipVolumeStencilVolumeTex
);
527 if (m_pClipVolumeStencilVolumeTex
528 && (m_pClipVolumeStencilVolumeTex
->GetWidth() != scaledWidth
529 || m_pClipVolumeStencilVolumeTex
->GetHeight() != scaledHeight
530 || !CTexture::IsTextureExist(m_pClipVolumeStencilVolumeTex
))
531 || m_depthTargetArrayVolFog
.empty()
532 || m_depthTargetArrayVolFog
.size() != depth
)
534 // create volume stencil passes
536 for (int32 i
= 0; i
< m_volumetricStencilPassArray
.size(); ++i
)
538 m_volumetricStencilPassArray
[i
].reset();
541 m_volumetricStencilPassArray
.resize(depth
);
543 for (int32 i
= 0; i
< depth
; ++i
)
545 m_volumetricStencilPassArray
[i
] = stl::make_unique
<CFullscreenPass
>();
546 m_volumetricStencilPassArray
[i
]->SetViewport(viewport
);
547 m_volumetricStencilPassArray
[i
]->SetFlags(CPrimitiveRenderPass::ePassFlags_None
);
551 // create stencil resolve passes
553 for (int32 i
= 0; i
< m_resolveVolumetricStencilPassArray
.size(); ++i
)
555 m_resolveVolumetricStencilPassArray
[i
].reset();
558 m_resolveVolumetricStencilPassArray
.resize(depth
);
560 for (int32 i
= 0; i
< depth
; ++i
)
562 m_resolveVolumetricStencilPassArray
[i
] = stl::make_unique
<CFullscreenPass
>();
563 m_resolveVolumetricStencilPassArray
[i
]->SetViewport(viewport
);
564 m_resolveVolumetricStencilPassArray
[i
]->SetFlags(CPrimitiveRenderPass::ePassFlags_None
);
568 // create jittered depth passes
570 for (int32 i
= 0; i
< m_jitteredDepthPassArray
.size(); ++i
)
572 m_jitteredDepthPassArray
[i
].reset();
575 m_jitteredDepthPassArray
.resize(depth
);
577 for (int32 i
= 0; i
< depth
; ++i
)
579 m_jitteredDepthPassArray
[i
] = stl::make_unique
<CFullscreenPass
>();
580 m_jitteredDepthPassArray
[i
]->SetViewport(viewport
);
581 m_jitteredDepthPassArray
[i
]->SetFlags(CPrimitiveRenderPass::ePassFlags_None
);
585 const int32 w
= scaledWidth
;
586 const int32 h
= scaledHeight
;
587 const int32 d
= depth
;
589 // create depth stencil textures
591 const uint32 commonFlags
= FT_NOMIPS
| FT_DONT_STREAM
| FT_DONT_RELEASE
;
592 const uint32 rtFlags
= commonFlags
| FT_USAGE_RENDERTARGET
;
593 ETEX_Format format
= eTF_R8
;
595 CTexture
* pTex
= CTexture::GetOrCreateTextureArray("$VolFogClipVolumeStencil", w
, h
, d
, 1, eTT_2D
, rtFlags
, format
);
598 || m_pClipVolumeStencilVolumeTex
!= pTex
// texture name must exactly match the name when creating texture object.
599 || pTex
->GetFlags() & FT_FAILED
)
601 CryFatalError("Couldn't allocate texture.");
604 size_t size
= m_pClipVolumeStencilVolumeTexArray
.size();
606 for (uint32 i
= 0; i
< size
; ++i
)
608 SAFE_RELEASE(m_pClipVolumeStencilVolumeTexArray
[i
]);
611 m_pClipVolumeStencilVolumeTexArray
.resize(depth
);
613 const uint32 dsFlags
= commonFlags
| FT_USAGE_RENDERTARGET
| FT_USAGE_DEPTHSTENCIL
;
614 ETEX_Format depthFormat
= eTF_D24S8
;
616 for (uint32 i
= 0; i
< depth
; ++i
)
618 CTexture
* pTex
= new CTexture(dsFlags
);
619 if (!(pTex
->Create2DTexture(w
, h
, 1, dsFlags
, nullptr, depthFormat
)))
621 CryFatalError("Couldn't allocate texture.");
624 m_pClipVolumeStencilVolumeTexArray
[i
] = pTex
;
628 // create depth targets
630 m_depthTargetArrayVolFog
.clear();
631 m_depthTargetArrayVolFog
.resize(depth
);
633 for (int32 i
= 0; i
< m_depthTargetArrayVolFog
.size(); ++i
)
635 auto& depthTarget
= m_depthTargetArrayVolFog
[i
];
636 CTexture
* pTex
= m_pClipVolumeStencilVolumeTexArray
[i
];
638 // this buffer is managed explicitly on multi GPU.
639 pTex
->DisableMgpuSync();
641 // set depth target before AddPrimitive() is called.
642 m_volumetricStencilPassArray
[i
]->SetDepthTarget(pTex
);
646 // need to clear depth buffer.
647 const int32 safeMargin
= 2; // workaround: shader isn't activated in initial several frames.
648 m_cleared
= gcpRendD3D
->GetActiveGPUCount() + safeMargin
;
654 void CClipVolumesStage::ExecuteVolumetricFog()
656 CD3D9Renderer
* const __restrict rd
= gcpRendD3D
;
657 SRenderPipeline
& rp(rd
->m_RP
);
658 auto nThreadID
= rp
.m_nProcessThreadID
;
660 if (rd
->m_bVolumetricFogEnabled
&& rp
.m_TI
[nThreadID
].m_FS
.m_bEnable
)
662 PROFILE_LABEL_SCOPE("CLIPVOLUMES FOR VOLUMETRIC FOG");
664 const bool bReverseDepth
= (rp
.m_TI
[rp
.m_nProcessThreadID
].m_PersFlags
& RBPF_REVERSE_DEPTH
) != 0;
665 const float nearDepth
= bReverseDepth
? 1.0f
: 0.0f
;
666 const float raymarchDistance
= gRenDev
->m_cEF
.m_PF
[rp
.m_nProcessThreadID
].pVolumetricFogDistanceParams
.w
;
668 if (m_nearDepth
!= nearDepth
669 || (0.25f
< abs(m_raymarchDistance
- raymarchDistance
)))
671 // store values to observe the change.
672 m_nearDepth
= nearDepth
;
673 m_raymarchDistance
= raymarchDistance
;
675 // need to clear depth buffer.
676 m_cleared
= (m_cleared
> 0) ? m_cleared
: rd
->GetActiveGPUCount();
679 auto maxDSVCount
= m_depthTargetArrayVolFog
.size();
680 const float fFar
= rd
->GetRCamera().fFar
;
681 const float fNear
= rd
->GetRCamera().fNear
;
682 const float factor0
= fFar
/ (fFar
- fNear
);
683 const float factor1
= fNear
* -factor0
;
686 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
689 rd
->FX_ClearTarget(m_depthTargetVolFog
->GetDevTexture()->LookupDSV(EDefaultResourceViews::DepthStencil
), CLEAR_STENCIL
| CLEAR_ZBUFFER
, 0.0f
, 0);
691 // write jittering depth.
692 for (int32 i
= 0; i
< maxDSVCount
; ++i
)
695 auto& depthTargetView
= m_depthTargetArrayVolFog
[i
];
696 auto& pass
= m_jitteredDepthPassArray
[i
];
698 static CCryNameTSCRC
shaderName("StoreJitteringDepthToClipVolumeDepth");
699 pass
->SetPrimitiveFlags(CRenderPrimitive::eFlags_ReflectShaderConstants_PS
);
700 pass
->SetTechnique(CShaderMan::s_shDeferredShading
, shaderName
, 0);
701 pass
->SetState(GS_DEPTHWRITE
| GS_DEPTHFUNC_NOTEQUAL
);
702 pass
->SetDepthTarget(m_depthTargetVolFog
, depthTargetView
);
704 pass
->BeginConstantUpdate();
706 static CCryNameR
paramDepth("ParamDepth");
707 const Vec4
vParamDepth(static_cast<float>(i
), factor1
, factor0
, nearDepth
);
708 pass
->SetConstant(paramDepth
, vParamDepth
, eHWSC_Pixel
);
710 bool success
= pass
->Execute();
712 valid
= valid
&& success
;
717 rd
->FX_ClearTarget(m_depthTargetVolFog
->GetDevTexture()->LookupDSV(EDefaultResourceViews::DepthStencil
), CLEAR_STENCIL
, 0.0f
, 0);
720 // Render clip volumes to single DSV for depth stencil texture array.
721 m_volumetricStencilPass
.Execute();
725 for (int32 i
= 0; i
< maxDSVCount
; ++i
)
727 CTexture
* const pTex
= m_pClipVolumeStencilVolumeTexArray
[i
];
728 auto& depthTarget
= m_depthTargetArrayVolFog
[i
];
730 D3DDepthSurface
* pDSV
= pTex
->GetDevTexture()->LookupDSV(depthTarget
);
731 rd
->FX_ClearTarget(pDSV
, CLEAR_STENCIL
| CLEAR_ZBUFFER
, 0.0f
, 0);
733 auto& pass
= m_jitteredDepthPassArray
[i
];
735 // write jittering depth.
736 static CCryNameTSCRC
shaderName("StoreJitteringDepthToClipVolumeDepth");
737 pass
->SetPrimitiveFlags(CRenderPrimitive::eFlags_ReflectShaderConstants_PS
);
738 pass
->SetTechnique(CShaderMan::s_shDeferredShading
, shaderName
, 0);
739 pass
->SetState(GS_DEPTHWRITE
| GS_DEPTHFUNC_NOTEQUAL
);
740 pass
->SetDepthTarget(pTex
, depthTarget
);
742 pass
->BeginConstantUpdate();
744 static CCryNameR
paramDepth("ParamDepth");
745 const Vec4
vParamDepth(static_cast<float>(i
), factor1
, factor0
, nearDepth
);
746 pass
->SetConstant(paramDepth
, vParamDepth
, eHWSC_Pixel
);
748 bool success
= pass
->Execute();
750 valid
= valid
&& success
;
755 for (int32 i
= 0; i
< maxDSVCount
; ++i
)
757 CTexture
* const pTex
= m_pClipVolumeStencilVolumeTexArray
[i
];
758 auto& depthTarget
= m_depthTargetArrayVolFog
[i
];
760 D3DDepthSurface
* pDSV
= pTex
->GetDevTexture()->LookupDSV(depthTarget
);
761 rd
->FX_ClearTarget(pDSV
, CLEAR_STENCIL
, 0.0f
, 0);
765 // Render clip volumes.
766 for (int32 i
= 0; i
< maxDSVCount
; ++i
)
768 CTexture
* const pTex
= m_pClipVolumeStencilVolumeTexArray
[i
];
769 auto& depthTarget
= m_depthTargetArrayVolFog
[i
];
770 auto& pass
= m_volumetricStencilPassArray
[i
];
772 pass
->SetDepthTarget(pTex
, depthTarget
);
777 static CCryNameTSCRC
techResolveStencil("ResolveStencilVolFog");
778 for (int32 i
= 0; i
< maxDSVCount
; ++i
)
780 auto renderTargetView
= SResourceView::RenderTargetView(DeviceFormats::ConvertFromTexFormat(m_pClipVolumeStencilVolumeTex
->GetDstFormat()), i
, 1, 0, false);
781 ResourceViewHandle rtvHandle
= m_pClipVolumeStencilVolumeTex
->GetDevTexture()->GetOrCreateResourceViewHandle(renderTargetView
);
783 CTexture
* const pTex
= m_pClipVolumeStencilVolumeTexArray
[i
];
784 auto stencilOnlyView
= SResourceView::ShaderResourceView(DeviceFormats::ConvertFromTexFormat(pTex
->GetDstFormat()),
785 0, -1, 0, -1, false, false, SResourceView::eSRV_StencilOnly
);
786 ResourceViewHandle srvHandle
= pTex
->GetDevTexture()->GetOrCreateResourceViewHandle(stencilOnlyView
);
788 auto& pPass
= m_resolveVolumetricStencilPassArray
[i
];
789 pPass
->SetPrimitiveFlags(CRenderPrimitive::eFlags_None
);
790 pPass
->SetTechnique(CShaderMan::s_shDeferredShading
, techResolveStencil
, 0);
791 pPass
->SetRenderTarget(0, m_pClipVolumeStencilVolumeTex
, rtvHandle
);
792 pPass
->SetState(GS_NODEPTHTEST
);
793 pPass
->SetTexture(4, pTex
, srvHandle
);
794 pPass
->BeginConstantUpdate();
801 m_cleared
= (m_cleared
> 0) ? (m_cleared
- 1) : 0;