2 // Copyright (c) Microsoft. All rights reserved.
3 // This code is licensed under the MIT License (MIT).
4 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
5 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
6 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
7 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
9 // Developed by Minigraph
11 // Author(s): Alex Nankervis
16 #include "GraphicsCore.h"
17 #include "CameraController.h"
18 #include "BufferManager.h"
21 #include "GpuBuffer.h"
22 #include "CommandContext.h"
23 #include "SamplerManager.h"
24 #include "TemporalEffects.h"
25 #include "MotionBlur.h"
26 #include "DepthOfField.h"
27 #include "PostEffects.h"
30 #include "SystemTime.h"
31 #include "TextRenderer.h"
32 #include "ShadowCamera.h"
33 #include "ParticleEffectManager.h"
34 #include "GameInput.h"
35 #include "./ForwardPlusLighting.h"
37 // To enable wave intrinsics, uncomment this macro and #define DXIL in Core/GraphcisCore.cpp.
38 // Run CompileSM6Test.bat to compile the relevant shaders with DXC.
41 #include "compiled_shaders/DepthViewerVS.h"
42 #include "compiled_shaders/DepthViewerPS.h"
43 #include "compiled_shaders/ModelViewerVS.h"
44 #include "compiled_shaders/ModelViewerPS.h"
46 #include "compiled_shaders/DepthViewerVS_SM6.h"
47 #include "compiled_shaders/ModelViewerVS_SM6.h"
48 #include "compiled_shaders/ModelViewerPS_SM6.h"
50 #include "compiled_shaders/WaveTileCountPS.h"
52 using namespace GameCore
;
54 using namespace Graphics
;
56 class ModelViewer
: public GameCore::IGameApp
60 ModelViewer( void ) {}
62 virtual void Startup( void ) override
;
63 virtual void Cleanup( void ) override
;
65 virtual void Update( float deltaT
) override
;
66 virtual void RenderScene( void ) override
;
70 void RenderLightShadows(GraphicsContext
& gfxContext
);
72 enum eObjectFilter
{ kOpaque
= 0x1, kCutout
= 0x2, kTransparent
= 0x4, kAll
= 0xF, kNone
= 0x0 };
73 void RenderObjects( GraphicsContext
& Context
, const Matrix4
& ViewProjMat
, eObjectFilter Filter
= kAll
);
74 void CreateParticleEffects();
76 std::auto_ptr
<CameraController
> m_CameraController
;
77 Matrix4 m_ViewProjMatrix
;
78 D3D12_VIEWPORT m_MainViewport
;
79 D3D12_RECT m_MainScissor
;
81 RootSignature m_RootSig
;
82 GraphicsPSO m_DepthPSO
;
83 GraphicsPSO m_CutoutDepthPSO
;
84 GraphicsPSO m_ModelPSO
;
86 GraphicsPSO m_DepthWaveOpsPSO
;
87 GraphicsPSO m_ModelWaveOpsPSO
;
89 GraphicsPSO m_CutoutModelPSO
;
90 GraphicsPSO m_ShadowPSO
;
91 GraphicsPSO m_CutoutShadowPSO
;
92 GraphicsPSO m_WaveTileCountPSO
;
94 D3D12_CPU_DESCRIPTOR_HANDLE m_DefaultSampler
;
95 D3D12_CPU_DESCRIPTOR_HANDLE m_ShadowSampler
;
96 D3D12_CPU_DESCRIPTOR_HANDLE m_BiasedDefaultSampler
;
98 D3D12_CPU_DESCRIPTOR_HANDLE m_ExtraTextures
[6];
100 std::vector
<bool> m_pMaterialIsCutout
;
102 Vector3 m_SunDirection
;
103 ShadowCamera m_SunShadow
;
106 CREATE_APPLICATION( ModelViewer
)
108 ExpVar
m_SunLightIntensity("Application/Lighting/Sun Light Intensity", 4.0f
, 0.0f
, 16.0f
, 0.1f
);
109 ExpVar
m_AmbientIntensity("Application/Lighting/Ambient Intensity", 0.1f
, -16.0f
, 16.0f
, 0.1f
);
110 NumVar
m_SunOrientation("Application/Lighting/Sun Orientation", -0.5f
, -100.0f
, 100.0f
, 0.1f
);
111 NumVar
m_SunInclination("Application/Lighting/Sun Inclination", 0.75f
, 0.0f
, 1.0f
, 0.01f
);
112 NumVar
ShadowDimX("Application/Lighting/Shadow Dim X", 5000, 1000, 10000, 100 );
113 NumVar
ShadowDimY("Application/Lighting/Shadow Dim Y", 3000, 1000, 10000, 100 );
114 NumVar
ShadowDimZ("Application/Lighting/Shadow Dim Z", 3000, 1000, 10000, 100 );
116 BoolVar
ShowWaveTileCounts("Application/Forward+/Show Wave Tile Counts", false);
118 BoolVar
EnableWaveOps("Application/Forward+/Enable Wave Ops", true);
121 void ModelViewer::Startup( void )
123 SamplerDesc DefaultSamplerDesc
;
124 DefaultSamplerDesc
.MaxAnisotropy
= 8;
126 m_RootSig
.Reset(5, 2);
127 m_RootSig
.InitStaticSampler(0, DefaultSamplerDesc
, D3D12_SHADER_VISIBILITY_PIXEL
);
128 m_RootSig
.InitStaticSampler(1, SamplerShadowDesc
, D3D12_SHADER_VISIBILITY_PIXEL
);
129 m_RootSig
[0].InitAsConstantBuffer(0, D3D12_SHADER_VISIBILITY_VERTEX
);
130 m_RootSig
[1].InitAsConstantBuffer(0, D3D12_SHADER_VISIBILITY_PIXEL
);
131 m_RootSig
[2].InitAsDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV
, 0, 6, D3D12_SHADER_VISIBILITY_PIXEL
);
132 m_RootSig
[3].InitAsDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV
, 64, 6, D3D12_SHADER_VISIBILITY_PIXEL
);
133 m_RootSig
[4].InitAsConstants(1, 2, D3D12_SHADER_VISIBILITY_VERTEX
);
134 m_RootSig
.Finalize(L
"ModelViewer", D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
);
136 DXGI_FORMAT ColorFormat
= g_SceneColorBuffer
.GetFormat();
137 DXGI_FORMAT DepthFormat
= g_SceneDepthBuffer
.GetFormat();
139 D3D12_INPUT_ELEMENT_DESC vertElem
[] =
141 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, D3D12_APPEND_ALIGNED_ELEMENT
, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA
, 0 },
142 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT
, 0, D3D12_APPEND_ALIGNED_ELEMENT
, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA
, 0 },
143 { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, D3D12_APPEND_ALIGNED_ELEMENT
, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA
, 0 },
144 { "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, D3D12_APPEND_ALIGNED_ELEMENT
, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA
, 0 },
145 { "BITANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT
, 0, D3D12_APPEND_ALIGNED_ELEMENT
, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA
, 0 }
148 // Depth-only (2x rate)
149 m_DepthPSO
.SetRootSignature(m_RootSig
);
150 m_DepthPSO
.SetRasterizerState(RasterizerDefault
);
151 m_DepthPSO
.SetBlendState(BlendNoColorWrite
);
152 m_DepthPSO
.SetDepthStencilState(DepthStateReadWrite
);
153 m_DepthPSO
.SetInputLayout(_countof(vertElem
), vertElem
);
154 m_DepthPSO
.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE
);
155 m_DepthPSO
.SetRenderTargetFormats(0, nullptr, DepthFormat
);
156 m_DepthPSO
.SetVertexShader(g_pDepthViewerVS
, sizeof(g_pDepthViewerVS
));
157 m_DepthPSO
.Finalize();
159 // Depth-only shading but with alpha testing
160 m_CutoutDepthPSO
= m_DepthPSO
;
161 m_CutoutDepthPSO
.SetPixelShader(g_pDepthViewerPS
, sizeof(g_pDepthViewerPS
));
162 m_CutoutDepthPSO
.SetRasterizerState(RasterizerTwoSided
);
163 m_CutoutDepthPSO
.Finalize();
165 // Depth-only but with a depth bias and/or render only backfaces
166 m_ShadowPSO
= m_DepthPSO
;
167 m_ShadowPSO
.SetRasterizerState(RasterizerShadow
);
168 m_ShadowPSO
.SetRenderTargetFormats(0, nullptr, g_ShadowBuffer
.GetFormat());
169 m_ShadowPSO
.Finalize();
171 // Shadows with alpha testing
172 m_CutoutShadowPSO
= m_ShadowPSO
;
173 m_CutoutShadowPSO
.SetPixelShader(g_pDepthViewerPS
, sizeof(g_pDepthViewerPS
));
174 m_CutoutShadowPSO
.SetRasterizerState(RasterizerShadowTwoSided
);
175 m_CutoutShadowPSO
.Finalize();
178 m_ModelPSO
= m_DepthPSO
;
179 m_ModelPSO
.SetBlendState(BlendDisable
);
180 m_ModelPSO
.SetDepthStencilState(DepthStateTestEqual
);
181 m_ModelPSO
.SetRenderTargetFormats(1, &ColorFormat
, DepthFormat
);
182 m_ModelPSO
.SetVertexShader( g_pModelViewerVS
, sizeof(g_pModelViewerVS
) );
183 m_ModelPSO
.SetPixelShader( g_pModelViewerPS
, sizeof(g_pModelViewerPS
) );
184 m_ModelPSO
.Finalize();
187 m_DepthWaveOpsPSO
= m_DepthPSO
;
188 m_DepthWaveOpsPSO
.SetVertexShader( g_pDepthViewerVS_SM6
, sizeof(g_pDepthViewerVS_SM6
) );
189 m_DepthWaveOpsPSO
.Finalize();
191 m_ModelWaveOpsPSO
= m_ModelPSO
;
192 m_ModelWaveOpsPSO
.SetVertexShader( g_pModelViewerVS_SM6
, sizeof(g_pModelViewerVS_SM6
) );
193 m_ModelWaveOpsPSO
.SetPixelShader( g_pModelViewerPS_SM6
, sizeof(g_pModelViewerPS_SM6
) );
194 m_ModelWaveOpsPSO
.Finalize();
197 m_CutoutModelPSO
= m_ModelPSO
;
198 m_CutoutModelPSO
.SetRasterizerState(RasterizerTwoSided
);
199 m_CutoutModelPSO
.Finalize();
201 // A debug shader for counting lights in a tile
202 m_WaveTileCountPSO
= m_ModelPSO
;
203 m_WaveTileCountPSO
.SetPixelShader(g_pWaveTileCountPS
, sizeof(g_pWaveTileCountPS
));
204 m_WaveTileCountPSO
.Finalize();
206 Lighting::InitializeResources();
208 m_ExtraTextures
[0] = g_SSAOFullScreen
.GetSRV();
209 m_ExtraTextures
[1] = g_ShadowBuffer
.GetSRV();
211 TextureManager::Initialize(MODELVIEWER_DATADIR
"/textures/");
212 ASSERT(m_Model
.Load(MODELVIEWER_DATADIR
"/models/sponza.h3d"), "Failed to load model");
213 ASSERT(m_Model
.m_Header
.meshCount
> 0, "Model contains no meshes");
215 // The caller of this function can override which materials are considered cutouts
216 m_pMaterialIsCutout
.resize(m_Model
.m_Header
.materialCount
);
217 for (uint32_t i
= 0; i
< m_Model
.m_Header
.materialCount
; ++i
)
219 const Model::Material
& mat
= m_Model
.m_pMaterial
[i
];
220 if (std::string(mat
.texDiffusePath
).find("thorn") != std::string::npos
||
221 std::string(mat
.texDiffusePath
).find("plant") != std::string::npos
||
222 std::string(mat
.texDiffusePath
).find("chain") != std::string::npos
)
224 m_pMaterialIsCutout
[i
] = true;
228 m_pMaterialIsCutout
[i
] = false;
232 CreateParticleEffects();
234 float modelRadius
= Length(m_Model
.m_Header
.boundingBox
.max
- m_Model
.m_Header
.boundingBox
.min
) * .5f
;
235 const Vector3 eye
= (m_Model
.m_Header
.boundingBox
.min
+ m_Model
.m_Header
.boundingBox
.max
) * .5f
+ Vector3(modelRadius
* .5f
, 0.0f
, 0.0f
);
236 m_Camera
.SetEyeAtUp( eye
, Vector3(kZero
), Vector3(kYUnitVector
) );
237 m_Camera
.SetZRange( 1.0f
, 10000.0f
);
238 m_CameraController
.reset(new CameraController(m_Camera
, Vector3(kYUnitVector
)));
240 MotionBlur::Enable
= true;
241 TemporalEffects::EnableTAA
= true;
242 FXAA::Enable
= false;
243 PostEffects::EnableHDR
= true;
244 PostEffects::EnableAdaptation
= true;
247 Lighting::CreateRandomLights(m_Model
.GetBoundingBox().min
, m_Model
.GetBoundingBox().max
);
249 m_ExtraTextures
[2] = Lighting::m_LightBuffer
.GetSRV();
250 m_ExtraTextures
[3] = Lighting::m_LightShadowArray
.GetSRV();
251 m_ExtraTextures
[4] = Lighting::m_LightGrid
.GetSRV();
252 m_ExtraTextures
[5] = Lighting::m_LightGridBitMask
.GetSRV();
255 void ModelViewer::Cleanup( void )
262 extern EnumVar DebugZoom
;
265 void ModelViewer::Update( float deltaT
)
267 ScopedTimer
_prof(L
"Update State");
269 if (GameInput::IsFirstPressed(GameInput::kLShoulder
))
270 DebugZoom
.Decrement();
271 else if (GameInput::IsFirstPressed(GameInput::kRShoulder
))
272 DebugZoom
.Increment();
274 m_CameraController
->Update(deltaT
);
275 m_ViewProjMatrix
= m_Camera
.GetViewProjMatrix();
277 float costheta
= cosf(m_SunOrientation
);
278 float sintheta
= sinf(m_SunOrientation
);
279 float cosphi
= cosf(m_SunInclination
* 3.14159f
* 0.5f
);
280 float sinphi
= sinf(m_SunInclination
* 3.14159f
* 0.5f
);
281 m_SunDirection
= Normalize(Vector3( costheta
* cosphi
, sinphi
, sintheta
* cosphi
));
283 // We use viewport offsets to jitter sample positions from frame to frame (for TAA.)
284 // D3D has a design quirk with fractional offsets such that the implicit scissor
285 // region of a viewport is floor(TopLeftXY) and floor(TopLeftXY + WidthHeight), so
286 // having a negative fractional top left, e.g. (-0.25, -0.25) would also shift the
287 // BottomRight corner up by a whole integer. One solution is to pad your viewport
288 // dimensions with an extra pixel. My solution is to only use positive fractional offsets,
289 // but that means that the average sample position is +0.5, which I use when I disable
291 TemporalEffects::GetJitterOffset(m_MainViewport
.TopLeftX
, m_MainViewport
.TopLeftY
);
293 m_MainViewport
.Width
= (float)g_SceneColorBuffer
.GetWidth();
294 m_MainViewport
.Height
= (float)g_SceneColorBuffer
.GetHeight();
295 m_MainViewport
.MinDepth
= 0.0f
;
296 m_MainViewport
.MaxDepth
= 1.0f
;
298 m_MainScissor
.left
= 0;
299 m_MainScissor
.top
= 0;
300 m_MainScissor
.right
= (LONG
)g_SceneColorBuffer
.GetWidth();
301 m_MainScissor
.bottom
= (LONG
)g_SceneColorBuffer
.GetHeight();
304 void ModelViewer::RenderObjects( GraphicsContext
& gfxContext
, const Matrix4
& ViewProjMat
, eObjectFilter Filter
)
308 Matrix4 modelToProjection
;
309 Matrix4 modelToShadow
;
312 vsConstants
.modelToProjection
= ViewProjMat
;
313 vsConstants
.modelToShadow
= m_SunShadow
.GetShadowMatrix();
314 XMStoreFloat3(&vsConstants
.viewerPos
, m_Camera
.GetPosition());
316 gfxContext
.SetDynamicConstantBufferView(0, sizeof(vsConstants
), &vsConstants
);
318 uint32_t materialIdx
= 0xFFFFFFFFul
;
320 uint32_t VertexStride
= m_Model
.m_VertexStride
;
322 for (uint32_t meshIndex
= 0; meshIndex
< m_Model
.m_Header
.meshCount
; meshIndex
++)
324 const Model::Mesh
& mesh
= m_Model
.m_pMesh
[meshIndex
];
326 uint32_t indexCount
= mesh
.indexCount
;
327 uint32_t startIndex
= mesh
.indexDataByteOffset
/ sizeof(uint16_t);
328 uint32_t baseVertex
= mesh
.vertexDataByteOffset
/ VertexStride
;
330 if (mesh
.materialIndex
!= materialIdx
)
332 if ((m_pMaterialIsCutout
[mesh
.materialIndex
] && !(Filter
& kCutout
))
333 || (!m_pMaterialIsCutout
[mesh
.materialIndex
] && !(Filter
& kOpaque
)))
336 materialIdx
= mesh
.materialIndex
;
337 gfxContext
.SetDynamicDescriptors(2, 0, 6, m_Model
.GetSRVs(materialIdx
) );
340 gfxContext
.SetConstants(4, baseVertex
, materialIdx
);
342 gfxContext
.DrawIndexed(indexCount
, startIndex
, baseVertex
);
346 void ModelViewer::RenderLightShadows(GraphicsContext
& gfxContext
)
348 using namespace Lighting
;
350 ScopedTimer
_prof(L
"RenderLightShadows", gfxContext
);
352 static uint32_t LightIndex
= 0;
353 if (LightIndex
>= MaxLights
)
356 m_LightShadowTempBuffer
.BeginRendering(gfxContext
);
358 gfxContext
.SetPipelineState(m_ShadowPSO
);
359 RenderObjects(gfxContext
, m_LightShadowMatrix
[LightIndex
], kOpaque
);
360 gfxContext
.SetPipelineState(m_CutoutShadowPSO
);
361 RenderObjects(gfxContext
, m_LightShadowMatrix
[LightIndex
], kCutout
);
363 m_LightShadowTempBuffer
.EndRendering(gfxContext
);
365 gfxContext
.TransitionResource(m_LightShadowTempBuffer
, D3D12_RESOURCE_STATE_GENERIC_READ
);
366 gfxContext
.TransitionResource(m_LightShadowArray
, D3D12_RESOURCE_STATE_COPY_DEST
);
368 gfxContext
.CopySubresource(m_LightShadowArray
, LightIndex
, m_LightShadowTempBuffer
, 0);
370 gfxContext
.TransitionResource(m_LightShadowArray
, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
);
375 void ModelViewer::RenderScene( void )
377 static bool s_ShowLightCounts
= false;
378 if (ShowWaveTileCounts
!= s_ShowLightCounts
)
380 static bool EnableHDR
;
381 if (ShowWaveTileCounts
)
383 EnableHDR
= PostEffects::EnableHDR
;
384 PostEffects::EnableHDR
= false;
388 PostEffects::EnableHDR
= EnableHDR
;
390 s_ShowLightCounts
= ShowWaveTileCounts
;
393 GraphicsContext
& gfxContext
= GraphicsContext::Begin(L
"Scene Render");
395 ParticleEffects::Update(gfxContext
.GetComputeContext(), Graphics::GetFrameTime());
397 uint32_t FrameIndex
= TemporalEffects::GetFrameIndexMod2();
399 struct DECLSPEC_ALIGN(16)
401 Vector3 sunDirection
;
403 Vector3 ambientLight
;
404 float ShadowTexelSize
[4];
407 uint32_t TileCount
[4];
408 uint32_t FirstLightIndex
[4];
409 uint32_t FrameIndexMod2
;
412 psConstants
.sunDirection
= m_SunDirection
;
413 psConstants
.sunLight
= Vector3(1.0f
, 1.0f
, 1.0f
) * m_SunLightIntensity
;
414 psConstants
.ambientLight
= Vector3(1.0f
, 1.0f
, 1.0f
) * m_AmbientIntensity
;
415 psConstants
.ShadowTexelSize
[0] = 1.0f
/ g_ShadowBuffer
.GetWidth();
416 psConstants
.InvTileDim
[0] = 1.0f
/ Lighting::LightGridDim
;
417 psConstants
.InvTileDim
[1] = 1.0f
/ Lighting::LightGridDim
;
418 psConstants
.TileCount
[0] = Math::DivideByMultiple(g_SceneColorBuffer
.GetWidth(), Lighting::LightGridDim
);
419 psConstants
.TileCount
[1] = Math::DivideByMultiple(g_SceneColorBuffer
.GetHeight(), Lighting::LightGridDim
);
420 psConstants
.FirstLightIndex
[0] = Lighting::m_FirstConeLight
;
421 psConstants
.FirstLightIndex
[1] = Lighting::m_FirstConeShadowedLight
;
422 psConstants
.FrameIndexMod2
= FrameIndex
;
424 // Set the default state for command lists
425 auto pfnSetupGraphicsState
= [&](void)
427 gfxContext
.SetRootSignature(m_RootSig
);
428 gfxContext
.SetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST
);
429 gfxContext
.SetIndexBuffer(m_Model
.m_IndexBuffer
.IndexBufferView());
430 gfxContext
.SetVertexBuffer(0, m_Model
.m_VertexBuffer
.VertexBufferView());
433 pfnSetupGraphicsState();
435 RenderLightShadows(gfxContext
);
438 ScopedTimer
_prof(L
"Z PrePass", gfxContext
);
440 gfxContext
.SetDynamicConstantBufferView(1, sizeof(psConstants
), &psConstants
);
443 ScopedTimer
_prof(L
"Opaque", gfxContext
);
444 gfxContext
.TransitionResource(g_SceneDepthBuffer
, D3D12_RESOURCE_STATE_DEPTH_WRITE
, true);
445 gfxContext
.ClearDepth(g_SceneDepthBuffer
);
448 gfxContext
.SetPipelineState(EnableWaveOps
? m_DepthWaveOpsPSO
: m_DepthPSO
);
450 gfxContext
.SetPipelineState(m_DepthPSO
);
452 gfxContext
.SetDepthStencilTarget(g_SceneDepthBuffer
.GetDSV());
453 gfxContext
.SetViewportAndScissor(m_MainViewport
, m_MainScissor
);
454 RenderObjects(gfxContext
, m_ViewProjMatrix
, kOpaque
);
458 ScopedTimer
_prof(L
"Cutout", gfxContext
);
459 gfxContext
.SetPipelineState(m_CutoutDepthPSO
);
460 RenderObjects(gfxContext
, m_ViewProjMatrix
, kCutout
);
464 SSAO::Render(gfxContext
, m_Camera
);
466 Lighting::FillLightGrid(gfxContext
, m_Camera
);
468 if (!SSAO::DebugDraw
)
470 ScopedTimer
_prof(L
"Main Render", gfxContext
);
472 gfxContext
.TransitionResource(g_SceneColorBuffer
, D3D12_RESOURCE_STATE_RENDER_TARGET
, true);
473 gfxContext
.ClearColor(g_SceneColorBuffer
);
475 pfnSetupGraphicsState();
478 ScopedTimer
_prof(L
"Render Shadow Map", gfxContext
);
480 m_SunShadow
.UpdateMatrix(-m_SunDirection
, Vector3(0, -500.0f
, 0), Vector3(ShadowDimX
, ShadowDimY
, ShadowDimZ
),
481 (uint32_t)g_ShadowBuffer
.GetWidth(), (uint32_t)g_ShadowBuffer
.GetHeight(), 16);
483 g_ShadowBuffer
.BeginRendering(gfxContext
);
484 gfxContext
.SetPipelineState(m_ShadowPSO
);
485 RenderObjects(gfxContext
, m_SunShadow
.GetViewProjMatrix(), kOpaque
);
486 gfxContext
.SetPipelineState(m_CutoutShadowPSO
);
487 RenderObjects(gfxContext
, m_SunShadow
.GetViewProjMatrix(), kCutout
);
488 g_ShadowBuffer
.EndRendering(gfxContext
);
491 if (SSAO::AsyncCompute
)
494 pfnSetupGraphicsState();
496 // Make the 3D queue wait for the Compute queue to finish SSAO
497 g_CommandManager
.GetGraphicsQueue().StallForProducer(g_CommandManager
.GetComputeQueue());
501 ScopedTimer
_prof(L
"Render Color", gfxContext
);
503 gfxContext
.TransitionResource(g_SSAOFullScreen
, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
);
505 gfxContext
.SetDynamicDescriptors(3, 0, _countof(m_ExtraTextures
), m_ExtraTextures
);
506 gfxContext
.SetDynamicConstantBufferView(1, sizeof(psConstants
), &psConstants
);
508 gfxContext
.SetPipelineState(EnableWaveOps
? m_ModelWaveOpsPSO
: m_ModelPSO
);
510 gfxContext
.SetPipelineState(ShowWaveTileCounts
? m_WaveTileCountPSO
: m_ModelPSO
);
512 gfxContext
.TransitionResource(g_SceneDepthBuffer
, D3D12_RESOURCE_STATE_DEPTH_READ
);
513 gfxContext
.SetRenderTarget(g_SceneColorBuffer
.GetRTV(), g_SceneDepthBuffer
.GetDSV_DepthReadOnly());
514 gfxContext
.SetViewportAndScissor(m_MainViewport
, m_MainScissor
);
516 RenderObjects( gfxContext
, m_ViewProjMatrix
, kOpaque
);
518 if (!ShowWaveTileCounts
)
520 gfxContext
.SetPipelineState(m_CutoutModelPSO
);
521 RenderObjects( gfxContext
, m_ViewProjMatrix
, kCutout
);
527 // Some systems generate a per-pixel velocity buffer to better track dynamic and skinned meshes. Everything
528 // is static in our scene, so we generate velocity from camera motion and the depth buffer. A velocity buffer
529 // is necessary for all temporal effects (and motion blur).
530 MotionBlur::GenerateCameraVelocityBuffer(gfxContext
, m_Camera
, true);
532 TemporalEffects::ResolveImage(gfxContext
);
534 ParticleEffects::Render(gfxContext
, m_Camera
, g_SceneColorBuffer
, g_SceneDepthBuffer
, g_LinearDepth
[FrameIndex
]);
536 // Until I work out how to couple these two, it's "either-or".
537 if (DepthOfField::Enable
)
538 DepthOfField::Render(gfxContext
, m_Camera
.GetNearClip(), m_Camera
.GetFarClip());
540 MotionBlur::RenderObjectBlur(gfxContext
, g_VelocityBuffer
);
545 void ModelViewer::CreateParticleEffects()
547 ParticleEffectProperties Effect
= ParticleEffectProperties();
548 Effect
.MinStartColor
= Effect
.MaxStartColor
= Effect
.MinEndColor
= Effect
.MaxEndColor
= Color(1.0f
, 1.0f
, 1.0f
, 0.0f
);
549 Effect
.TexturePath
= "spark_tex.dds";
551 Effect
.TotalActiveLifetime
= FLT_MAX
;
552 Effect
.Size
= Vector4(4.0f
, 8.0f
, 4.0f
, 8.0f
);
553 Effect
.Velocity
= Vector4(20.0f
, 200.0f
, 50.0f
, 180.0f
);
554 Effect
.LifeMinMax
= XMFLOAT2(1.0f
, 3.0f
);
555 Effect
.MassMinMax
= XMFLOAT2(4.5f
, 15.0f
);
556 Effect
.EmitProperties
.Gravity
= XMFLOAT3(0.0f
, -100.0f
, 0.0f
);
557 Effect
.EmitProperties
.FloorHeight
= -0.5f
;
558 Effect
.EmitProperties
.EmitPosW
= Effect
.EmitProperties
.LastEmitPosW
= XMFLOAT3(-1200.0f
, 185.0f
, -445.0f
);
559 Effect
.EmitProperties
.MaxParticles
= 800;
560 Effect
.EmitRate
= 64.0f
;
561 Effect
.Spread
.x
= 20.0f
;
562 Effect
.Spread
.y
= 50.0f
;
563 ParticleEffects::InstantiateEffect( Effect
);
565 ParticleEffectProperties Smoke
= ParticleEffectProperties();
566 Smoke
.TexturePath
= "smoke.dds";
568 Smoke
.TotalActiveLifetime
= FLT_MAX
;
569 Smoke
.EmitProperties
.MaxParticles
= 25;
570 Smoke
.EmitProperties
.EmitPosW
= Smoke
.EmitProperties
.LastEmitPosW
= XMFLOAT3(1120.0f
, 185.0f
, -445.0f
);
571 Smoke
.EmitRate
= 64.0f
;
572 Smoke
.LifeMinMax
= XMFLOAT2(2.5f
, 4.0f
);
573 Smoke
.Size
= Vector4(60.0f
, 108.0f
, 30.0f
, 208.0f
);
574 Smoke
.Velocity
= Vector4(30.0f
, 30.0f
, 10.0f
, 40.0f
);
575 Smoke
.MassMinMax
= XMFLOAT2(1.0, 3.5);
576 Smoke
.Spread
.x
= 60.0f
;
577 Smoke
.Spread
.y
= 70.0f
;
578 Smoke
.Spread
.z
= 20.0f
;
579 ParticleEffects::InstantiateEffect( Smoke
);
581 ParticleEffectProperties Fire
= ParticleEffectProperties();
582 Fire
.MinStartColor
= Fire
.MaxStartColor
= Fire
.MinEndColor
= Fire
.MaxEndColor
= Color(8.0f
, 8.0f
, 8.0f
, 0.0f
);
583 Fire
.TexturePath
= "fire.dds";
585 Fire
.TotalActiveLifetime
= FLT_MAX
;
586 Fire
.Size
= Vector4(54.0f
, 68.0f
, 0.1f
, 0.3f
);
587 Fire
.Velocity
= Vector4 (10.0f
, 30.0f
, 50.0f
, 50.0f
);
588 Fire
.LifeMinMax
= XMFLOAT2(1.0f
, 3.0f
);
589 Fire
.MassMinMax
= XMFLOAT2(10.5f
, 14.0f
);
590 Fire
.EmitProperties
.Gravity
= XMFLOAT3(0.0f
, 1.0f
, 0.0f
);
591 Fire
.EmitProperties
.EmitPosW
= Fire
.EmitProperties
.LastEmitPosW
= XMFLOAT3(1120.0f
, 125.0f
, 405.0f
);
592 Fire
.EmitProperties
.MaxParticles
= 25;
593 Fire
.EmitRate
= 64.0f
;
594 Fire
.Spread
.x
= 1.0f
;
595 Fire
.Spread
.y
= 60.0f
;
596 ParticleEffects::InstantiateEffect( Fire
);