1 /* Copyright (C) 2023 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "precompiled.h"
20 #include "renderer/TerrainRenderer.h"
22 #include "graphics/Camera.h"
23 #include "graphics/Canvas2D.h"
24 #include "graphics/Decal.h"
25 #include "graphics/GameView.h"
26 #include "graphics/LightEnv.h"
27 #include "graphics/LOSTexture.h"
28 #include "graphics/Patch.h"
29 #include "graphics/Model.h"
30 #include "graphics/ShaderManager.h"
31 #include "graphics/TerritoryTexture.h"
32 #include "graphics/TextRenderer.h"
33 #include "graphics/TextureManager.h"
34 #include "maths/MathUtil.h"
35 #include "maths/Vector2D.h"
36 #include "ps/CLogger.h"
37 #include "ps/CStrInternStatic.h"
38 #include "ps/Filesystem.h"
40 #include "ps/Profile.h"
42 #include "renderer/backend/IDevice.h"
43 #include "renderer/backend/PipelineState.h"
44 #include "renderer/DecalRData.h"
45 #include "renderer/PatchRData.h"
46 #include "renderer/Renderer.h"
47 #include "renderer/RenderingOptions.h"
48 #include "renderer/SceneRenderer.h"
49 #include "renderer/ShadowMap.h"
50 #include "renderer/SkyManager.h"
51 #include "renderer/VertexArray.h"
52 #include "renderer/WaterManager.h"
57 * TerrainRenderer keeps track of which phase it is in, to detect
58 * when Submit, PrepareForRendering etc. are called in the wrong order.
68 * Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class.
70 struct TerrainRendererInternals
72 /// Which phase (submitting or rendering patches) are we in right now?
75 /// Patches that were submitted for this frame
76 std::vector
<CPatchRData
*> visiblePatches
[CSceneRenderer::CULL_MAX
];
78 /// Decals that were submitted for this frame
79 std::vector
<CDecalRData
*> visibleDecals
[CSceneRenderer::CULL_MAX
];
81 /// Fancy water shader
82 CShaderTechniquePtr fancyWaterTech
;
84 CShaderTechniquePtr shaderTechniqueSolid
, shaderTechniqueSolidDepthTest
;
86 Renderer::Backend::IVertexInputLayout
* overlayVertexInputLayout
= nullptr;
87 Renderer::Backend::IVertexInputLayout
* decalsVertexInputLayout
= nullptr;
89 Renderer::Backend::IVertexInputLayout
* baseVertexInputLayout
= nullptr;
90 Renderer::Backend::IVertexInputLayout
* blendVertexInputLayout
= nullptr;
91 Renderer::Backend::IVertexInputLayout
* streamVertexInputLayout
= nullptr;
92 Renderer::Backend::IVertexInputLayout
* streamWithPositionAsTexCoordVertexInputLayout
= nullptr;
93 Renderer::Backend::IVertexInputLayout
* sideVertexInputLayout
= nullptr;
95 Renderer::Backend::IVertexInputLayout
* waterSurfaceVertexInputLayout
= nullptr;
96 Renderer::Backend::IVertexInputLayout
* waterSurfaceWithDataVertexInputLayout
= nullptr;
97 Renderer::Backend::IVertexInputLayout
* waterShoreVertexInputLayout
= nullptr;
99 CSimulation2
* simulation
;
104 ///////////////////////////////////////////////////////////////////
105 // Construction/Destruction
106 TerrainRenderer::TerrainRenderer()
108 m
= new TerrainRendererInternals();
109 m
->phase
= Phase_Submit
;
112 TerrainRenderer::~TerrainRenderer()
117 void TerrainRenderer::Initialize()
119 const std::array
<Renderer::Backend::SVertexAttributeFormat
, 2> overlayAttributes
{{
120 {Renderer::Backend::VertexAttributeStream::POSITION
,
121 Renderer::Backend::Format::R32G32B32_SFLOAT
, 0, sizeof(float) * 3,
122 Renderer::Backend::VertexAttributeRate::PER_VERTEX
, 0},
123 {Renderer::Backend::VertexAttributeStream::UV0
,
124 Renderer::Backend::Format::R32G32B32_SFLOAT
, 0, sizeof(float) * 3,
125 Renderer::Backend::VertexAttributeRate::PER_VERTEX
, 0}
127 m
->overlayVertexInputLayout
= g_Renderer
.GetVertexInputLayout(overlayAttributes
);
129 m
->decalsVertexInputLayout
= CDecalRData::GetVertexInputLayout();
131 m
->baseVertexInputLayout
= CPatchRData::GetBaseVertexInputLayout();
132 m
->blendVertexInputLayout
= CPatchRData::GetBlendVertexInputLayout();
133 m
->streamVertexInputLayout
= CPatchRData::GetStreamVertexInputLayout(false);
134 m
->streamWithPositionAsTexCoordVertexInputLayout
=
135 CPatchRData::GetStreamVertexInputLayout(true);
136 m
->sideVertexInputLayout
= CPatchRData::GetSideVertexInputLayout();
138 m
->waterSurfaceVertexInputLayout
= CPatchRData::GetWaterSurfaceVertexInputLayout(false);
139 m
->waterSurfaceWithDataVertexInputLayout
= CPatchRData::GetWaterSurfaceVertexInputLayout(true);
140 m
->waterShoreVertexInputLayout
= CPatchRData::GetWaterShoreVertexInputLayout();
143 void TerrainRenderer::SetSimulation(CSimulation2
* simulation
)
145 m
->simulation
= simulation
;
148 ///////////////////////////////////////////////////////////////////
149 // Submit a patch for rendering
150 void TerrainRenderer::Submit(int cullGroup
, CPatch
* patch
)
152 ENSURE(m
->phase
== Phase_Submit
);
154 CPatchRData
* data
= (CPatchRData
*)patch
->GetRenderData();
157 // no renderdata for patch, create it now
158 data
= new CPatchRData(patch
, m
->simulation
);
159 patch
->SetRenderData(data
);
161 data
->Update(m
->simulation
);
163 m
->visiblePatches
[cullGroup
].push_back(data
);
166 ///////////////////////////////////////////////////////////////////
167 // Submit a decal for rendering
168 void TerrainRenderer::Submit(int cullGroup
, CModelDecal
* decal
)
170 ENSURE(m
->phase
== Phase_Submit
);
172 CDecalRData
* data
= (CDecalRData
*)decal
->GetRenderData();
175 // no renderdata for decal, create it now
176 data
= new CDecalRData(decal
, m
->simulation
);
177 decal
->SetRenderData(data
);
179 data
->Update(m
->simulation
);
181 m
->visibleDecals
[cullGroup
].push_back(data
);
184 ///////////////////////////////////////////////////////////////////
185 // Prepare for rendering
186 void TerrainRenderer::PrepareForRendering()
188 ENSURE(m
->phase
== Phase_Submit
);
190 m
->phase
= Phase_Render
;
193 ///////////////////////////////////////////////////////////////////
194 // Clear submissions lists
195 void TerrainRenderer::EndFrame()
197 ENSURE(m
->phase
== Phase_Render
|| m
->phase
== Phase_Submit
);
199 for (int i
= 0; i
< CSceneRenderer::CULL_MAX
; ++i
)
201 m
->visiblePatches
[i
].clear();
202 m
->visibleDecals
[i
].clear();
205 m
->phase
= Phase_Submit
;
208 void TerrainRenderer::RenderTerrainOverlayTexture(
209 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
,
210 int cullGroup
, const CVector2D
& textureTransform
,
211 Renderer::Backend::ITexture
* texture
)
213 ENSURE(m
->phase
== Phase_Render
);
215 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
217 CShaderTechniquePtr debugOverlayTech
=
218 g_Renderer
.GetShaderManager().LoadEffect(str_debug_overlay
);
219 deviceCommandContext
->SetGraphicsPipelineState(
220 debugOverlayTech
->GetGraphicsPipelineState());
221 deviceCommandContext
->BeginPass();
222 Renderer::Backend::IShaderProgram
* debugOverlayShader
= debugOverlayTech
->GetShader();
224 deviceCommandContext
->SetTexture(
225 debugOverlayShader
->GetBindingSlot(str_baseTex
), texture
);
226 const CMatrix3D transform
=
227 g_Renderer
.GetSceneRenderer().GetViewCamera().GetViewProjection();
228 deviceCommandContext
->SetUniform(
229 debugOverlayShader
->GetBindingSlot(str_transform
), transform
.AsFloatArray());
230 deviceCommandContext
->SetUniform(
231 debugOverlayShader
->GetBindingSlot(str_textureTransform
), textureTransform
.AsFloatArray());
232 CPatchRData::RenderStreams(
233 deviceCommandContext
, m
->streamWithPositionAsTexCoordVertexInputLayout
, visiblePatches
);
235 // To make the overlay visible over water, render an additional map-sized
236 // water-height patch.
237 CBoundingBoxAligned waterBounds
;
238 for (CPatchRData
* data
: visiblePatches
)
239 waterBounds
+= data
->GetWaterBounds();
240 if (!waterBounds
.IsEmpty())
242 // Add a delta to avoid z-fighting.
243 const float height
= g_Renderer
.GetSceneRenderer().GetWaterManager().m_WaterHeight
+ 0.05f
;
244 const float waterPos
[] =
246 waterBounds
[0].X
, height
, waterBounds
[0].Z
,
247 waterBounds
[1].X
, height
, waterBounds
[0].Z
,
248 waterBounds
[1].X
, height
, waterBounds
[1].Z
,
249 waterBounds
[0].X
, height
, waterBounds
[0].Z
,
250 waterBounds
[1].X
, height
, waterBounds
[1].Z
,
251 waterBounds
[0].X
, height
, waterBounds
[1].Z
254 deviceCommandContext
->SetVertexInputLayout(m
->overlayVertexInputLayout
);
256 deviceCommandContext
->SetVertexBufferData(
257 0, waterPos
, std::size(waterPos
) * sizeof(waterPos
[0]));
259 deviceCommandContext
->Draw(0, 6);
262 deviceCommandContext
->EndPass();
266 ///////////////////////////////////////////////////////////////////
269 * Set up all the uniforms for a shader pass.
271 void TerrainRenderer::PrepareShader(
272 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
,
273 Renderer::Backend::IShaderProgram
* shader
, ShadowMap
* shadow
)
275 CSceneRenderer
& sceneRenderer
= g_Renderer
.GetSceneRenderer();
277 const CMatrix3D transform
= sceneRenderer
.GetViewCamera().GetViewProjection();
278 deviceCommandContext
->SetUniform(
279 shader
->GetBindingSlot(str_transform
), transform
.AsFloatArray());
280 deviceCommandContext
->SetUniform(
281 shader
->GetBindingSlot(str_cameraPos
),
282 sceneRenderer
.GetViewCamera().GetOrientation().GetTranslation().AsFloatArray());
284 const CLightEnv
& lightEnv
= sceneRenderer
.GetLightEnv();
287 shadow
->BindTo(deviceCommandContext
, shader
);
289 CLOSTexture
& los
= sceneRenderer
.GetScene().GetLOSTexture();
290 deviceCommandContext
->SetTexture(
291 shader
->GetBindingSlot(str_losTex
), los
.GetTextureSmooth());
292 deviceCommandContext
->SetUniform(
293 shader
->GetBindingSlot(str_losTransform
),
294 los
.GetTextureMatrix()[0], los
.GetTextureMatrix()[12]);
296 deviceCommandContext
->SetUniform(
297 shader
->GetBindingSlot(str_ambient
),
298 lightEnv
.m_AmbientColor
.AsFloatArray());
299 deviceCommandContext
->SetUniform(
300 shader
->GetBindingSlot(str_sunColor
),
301 lightEnv
.m_SunColor
.AsFloatArray());
302 deviceCommandContext
->SetUniform(
303 shader
->GetBindingSlot(str_sunDir
),
304 lightEnv
.GetSunDir().AsFloatArray());
306 deviceCommandContext
->SetUniform(
307 shader
->GetBindingSlot(str_fogColor
),
308 lightEnv
.m_FogColor
.AsFloatArray());
309 deviceCommandContext
->SetUniform(
310 shader
->GetBindingSlot(str_fogParams
),
311 lightEnv
.m_FogFactor
, lightEnv
.m_FogMax
);
314 void TerrainRenderer::RenderTerrainShader(
315 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
,
316 const CShaderDefines
& context
, int cullGroup
, ShadowMap
* shadow
)
318 ENSURE(m
->phase
== Phase_Render
);
320 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
321 std::vector
<CDecalRData
*>& visibleDecals
= m
->visibleDecals
[cullGroup
];
322 if (visiblePatches
.empty() && visibleDecals
.empty())
325 if (!m
->shaderTechniqueSolid
)
327 m
->shaderTechniqueSolid
= g_Renderer
.GetShaderManager().LoadEffect(
329 [](Renderer::Backend::SGraphicsPipelineStateDesc
& pipelineStateDesc
)
331 pipelineStateDesc
.rasterizationState
.cullMode
= Renderer::Backend::CullMode::NONE
;
335 // render the solid black sides of the map first
336 deviceCommandContext
->SetGraphicsPipelineState(
337 m
->shaderTechniqueSolid
->GetGraphicsPipelineState());
338 deviceCommandContext
->BeginPass();
340 Renderer::Backend::IShaderProgram
* shaderSolid
= m
->shaderTechniqueSolid
->GetShader();
341 const CMatrix3D transform
=
342 g_Renderer
.GetSceneRenderer().GetViewCamera().GetViewProjection();
343 deviceCommandContext
->SetUniform(
344 shaderSolid
->GetBindingSlot(str_transform
), transform
.AsFloatArray());
345 deviceCommandContext
->SetUniform(
346 shaderSolid
->GetBindingSlot(str_color
), 0.0f
, 0.0f
, 0.0f
, 1.0f
);
348 CPatchRData::RenderSides(
349 deviceCommandContext
, m
->sideVertexInputLayout
, visiblePatches
);
351 deviceCommandContext
->EndPass();
353 CPatchRData::RenderBases(
354 deviceCommandContext
, m
->baseVertexInputLayout
, visiblePatches
, context
, shadow
);
356 // render blend passes for each patch
357 CPatchRData::RenderBlends(
358 deviceCommandContext
, m
->blendVertexInputLayout
, visiblePatches
, context
, shadow
);
360 CDecalRData::RenderDecals(
361 deviceCommandContext
, m
->decalsVertexInputLayout
, visibleDecals
, context
, shadow
);
364 ///////////////////////////////////////////////////////////////////
365 // Render un-textured patches as polygons
366 void TerrainRenderer::RenderPatches(
367 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
,
368 int cullGroup
, const CShaderDefines
& defines
, const CColor
& color
)
370 ENSURE(m
->phase
== Phase_Render
);
372 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
373 if (visiblePatches
.empty())
376 GPU_SCOPED_LABEL(deviceCommandContext
, "Render terrain patches");
378 CShaderTechniquePtr solidTech
= g_Renderer
.GetShaderManager().LoadEffect(str_terrain_solid
, defines
);
379 deviceCommandContext
->SetGraphicsPipelineState(
380 solidTech
->GetGraphicsPipelineState());
381 deviceCommandContext
->BeginPass();
383 Renderer::Backend::IShaderProgram
* solidShader
= solidTech
->GetShader();
385 const CMatrix3D transform
=
386 g_Renderer
.GetSceneRenderer().GetViewCamera().GetViewProjection();
387 deviceCommandContext
->SetUniform(
388 solidShader
->GetBindingSlot(str_transform
), transform
.AsFloatArray());
389 deviceCommandContext
->SetUniform(
390 solidShader
->GetBindingSlot(str_color
), color
.AsFloatArray());
392 CPatchRData::RenderStreams(
393 deviceCommandContext
, m
->streamVertexInputLayout
, visiblePatches
);
394 deviceCommandContext
->EndPass();
398 ///////////////////////////////////////////////////////////////////
399 // Render outlines of submitted patches as lines
400 void TerrainRenderer::RenderOutlines(
401 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
,
404 ENSURE(m
->phase
== Phase_Render
);
406 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
407 if (visiblePatches
.empty())
410 GPU_SCOPED_LABEL(deviceCommandContext
, "Render terrain outlines");
412 for (size_t i
= 0; i
< visiblePatches
.size(); ++i
)
413 visiblePatches
[i
]->RenderOutline();
417 ///////////////////////////////////////////////////////////////////
418 // Scissor rectangle of water patches
419 CBoundingBoxAligned
TerrainRenderer::ScissorWater(int cullGroup
, const CCamera
& camera
)
421 CBoundingBoxAligned scissor
;
422 for (const CPatchRData
* data
: m
->visiblePatches
[cullGroup
])
424 const CBoundingBoxAligned
& waterBounds
= data
->GetWaterBounds();
425 if (waterBounds
.IsEmpty())
428 const CBoundingBoxAligned waterBoundsInViewPort
=
429 camera
.GetBoundsInViewPort(waterBounds
);
430 if (!waterBoundsInViewPort
.IsEmpty())
431 scissor
+= waterBoundsInViewPort
;
433 if (scissor
.IsEmpty())
435 return CBoundingBoxAligned(
436 CVector3D(Clamp(scissor
[0].X
, -1.0f
, 1.0f
), Clamp(scissor
[0].Y
, -1.0f
, 1.0f
), -1.0f
),
437 CVector3D(Clamp(scissor
[1].X
, -1.0f
, 1.0f
), Clamp(scissor
[1].Y
, -1.0f
, 1.0f
), 1.0f
));
440 // Render fancy water
441 bool TerrainRenderer::RenderFancyWater(
442 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
,
443 const CShaderDefines
& context
, int cullGroup
, ShadowMap
* shadow
)
445 PROFILE3_GPU("fancy water");
446 GPU_SCOPED_LABEL(deviceCommandContext
, "Render fancy water");
448 CSceneRenderer
& sceneRenderer
= g_Renderer
.GetSceneRenderer();
450 WaterManager
& waterManager
= sceneRenderer
.GetWaterManager();
451 CShaderDefines defines
= context
;
453 // If we're using fancy water, make sure its shader is loaded
454 if (!m
->fancyWaterTech
|| waterManager
.m_NeedsReloading
)
456 if (waterManager
.m_WaterRealDepth
)
457 defines
.Add(str_USE_REAL_DEPTH
, str_1
);
458 if (waterManager
.m_WaterFancyEffects
)
459 defines
.Add(str_USE_FANCY_EFFECTS
, str_1
);
460 if (waterManager
.m_WaterRefraction
)
461 defines
.Add(str_USE_REFRACTION
, str_1
);
462 if (waterManager
.m_WaterReflection
)
463 defines
.Add(str_USE_REFLECTION
, str_1
);
465 m
->fancyWaterTech
= g_Renderer
.GetShaderManager().LoadEffect(str_water_high
, defines
);
467 if (!m
->fancyWaterTech
)
469 LOGERROR("Failed to load water shader. Falling back to a simple water.\n");
470 waterManager
.m_RenderWater
= false;
473 waterManager
.m_NeedsReloading
= false;
476 CLOSTexture
& losTexture
= sceneRenderer
.GetScene().GetLOSTexture();
478 // Calculating the advanced informations about Foam and all if the quality calls for it.
479 /*if (WaterMgr->m_NeedInfoUpdate && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves))
481 WaterMgr->m_NeedInfoUpdate = false;
482 WaterMgr->CreateSuperfancyInfo();
485 const double time
= waterManager
.m_WaterTexTimer
;
486 const float repeatPeriod
= waterManager
.m_RepeatPeriod
;
488 deviceCommandContext
->SetGraphicsPipelineState(
489 m
->fancyWaterTech
->GetGraphicsPipelineState());
490 deviceCommandContext
->BeginPass();
491 Renderer::Backend::IShaderProgram
* fancyWaterShader
= m
->fancyWaterTech
->GetShader();
493 const CCamera
& camera
= g_Renderer
.GetSceneRenderer().GetViewCamera();
495 const double period
= 8.0;
496 // TODO: move uploading to a prepare function during loading.
497 const CTexturePtr
& currentNormalTexture
= waterManager
.m_NormalMap
[waterManager
.GetCurrentTextureIndex(period
)];
498 const CTexturePtr
& nextNormalTexture
= waterManager
.m_NormalMap
[waterManager
.GetNextTextureIndex(period
)];
500 currentNormalTexture
->UploadBackendTextureIfNeeded(deviceCommandContext
);
501 nextNormalTexture
->UploadBackendTextureIfNeeded(deviceCommandContext
);
503 deviceCommandContext
->SetTexture(
504 fancyWaterShader
->GetBindingSlot(str_normalMap
),
505 currentNormalTexture
->GetBackendTexture());
506 deviceCommandContext
->SetTexture(
507 fancyWaterShader
->GetBindingSlot(str_normalMap2
),
508 nextNormalTexture
->GetBackendTexture());
510 if (waterManager
.m_WaterFancyEffects
)
512 deviceCommandContext
->SetTexture(
513 fancyWaterShader
->GetBindingSlot(str_waterEffectsTex
),
514 waterManager
.m_FancyTexture
.get());
517 if (waterManager
.m_WaterRefraction
&& waterManager
.m_WaterRealDepth
)
519 deviceCommandContext
->SetTexture(
520 fancyWaterShader
->GetBindingSlot(str_depthTex
),
521 waterManager
.m_RefrFboDepthTexture
.get());
522 deviceCommandContext
->SetUniform(
523 fancyWaterShader
->GetBindingSlot(str_projInvTransform
),
524 waterManager
.m_RefractionProjInvMatrix
.AsFloatArray());
525 deviceCommandContext
->SetUniform(
526 fancyWaterShader
->GetBindingSlot(str_viewInvTransform
),
527 waterManager
.m_RefractionViewInvMatrix
.AsFloatArray());
530 if (waterManager
.m_WaterRefraction
)
532 deviceCommandContext
->SetTexture(
533 fancyWaterShader
->GetBindingSlot(str_refractionMap
),
534 waterManager
.m_RefractionTexture
.get());
536 if (waterManager
.m_WaterReflection
)
538 deviceCommandContext
->SetTexture(
539 fancyWaterShader
->GetBindingSlot(str_reflectionMap
),
540 waterManager
.m_ReflectionTexture
.get());
542 deviceCommandContext
->SetTexture(
543 fancyWaterShader
->GetBindingSlot(str_losTex
), losTexture
.GetTextureSmooth());
545 const CLightEnv
& lightEnv
= sceneRenderer
.GetLightEnv();
547 const CMatrix3D transform
= sceneRenderer
.GetViewCamera().GetViewProjection();
548 deviceCommandContext
->SetUniform(
549 fancyWaterShader
->GetBindingSlot(str_transform
), transform
.AsFloatArray());
551 deviceCommandContext
->SetTexture(
552 fancyWaterShader
->GetBindingSlot(str_skyCube
),
553 sceneRenderer
.GetSkyManager().GetSkyCube());
554 // TODO: check that this rotates in the right direction.
555 CMatrix3D skyBoxRotation
;
556 skyBoxRotation
.SetIdentity();
557 skyBoxRotation
.RotateY(M_PI
+ lightEnv
.GetRotation());
558 deviceCommandContext
->SetUniform(
559 fancyWaterShader
->GetBindingSlot(str_skyBoxRot
),
560 skyBoxRotation
.AsFloatArray());
562 if (waterManager
.m_WaterRefraction
)
564 deviceCommandContext
->SetUniform(
565 fancyWaterShader
->GetBindingSlot(str_refractionMatrix
),
566 waterManager
.m_RefractionMatrix
.AsFloatArray());
568 if (waterManager
.m_WaterReflection
)
570 deviceCommandContext
->SetUniform(
571 fancyWaterShader
->GetBindingSlot(str_reflectionMatrix
),
572 waterManager
.m_ReflectionMatrix
.AsFloatArray());
575 deviceCommandContext
->SetUniform(
576 fancyWaterShader
->GetBindingSlot(str_ambient
), lightEnv
.m_AmbientColor
.AsFloatArray());
577 deviceCommandContext
->SetUniform(
578 fancyWaterShader
->GetBindingSlot(str_sunDir
), lightEnv
.GetSunDir().AsFloatArray());
579 deviceCommandContext
->SetUniform(
580 fancyWaterShader
->GetBindingSlot(str_sunColor
), lightEnv
.m_SunColor
.AsFloatArray());
581 deviceCommandContext
->SetUniform(
582 fancyWaterShader
->GetBindingSlot(str_color
), waterManager
.m_WaterColor
.AsFloatArray());
583 deviceCommandContext
->SetUniform(
584 fancyWaterShader
->GetBindingSlot(str_tint
), waterManager
.m_WaterTint
.AsFloatArray());
585 deviceCommandContext
->SetUniform(
586 fancyWaterShader
->GetBindingSlot(str_waviness
), waterManager
.m_Waviness
);
587 deviceCommandContext
->SetUniform(
588 fancyWaterShader
->GetBindingSlot(str_murkiness
), waterManager
.m_Murkiness
);
589 deviceCommandContext
->SetUniform(
590 fancyWaterShader
->GetBindingSlot(str_windAngle
), waterManager
.m_WindAngle
);
591 deviceCommandContext
->SetUniform(
592 fancyWaterShader
->GetBindingSlot(str_repeatScale
), 1.0f
/ repeatPeriod
);
594 deviceCommandContext
->SetUniform(
595 fancyWaterShader
->GetBindingSlot(str_losTransform
),
596 losTexture
.GetTextureMatrix()[0], losTexture
.GetTextureMatrix()[12]);
597 deviceCommandContext
->SetUniform(
598 fancyWaterShader
->GetBindingSlot(str_cameraPos
),
599 camera
.GetOrientation().GetTranslation().AsFloatArray());
601 deviceCommandContext
->SetUniform(
602 fancyWaterShader
->GetBindingSlot(str_fogColor
),
603 lightEnv
.m_FogColor
.AsFloatArray());
604 deviceCommandContext
->SetUniform(
605 fancyWaterShader
->GetBindingSlot(str_fogParams
),
606 lightEnv
.m_FogFactor
, lightEnv
.m_FogMax
);
607 deviceCommandContext
->SetUniform(
608 fancyWaterShader
->GetBindingSlot(str_time
), static_cast<float>(time
));
609 deviceCommandContext
->SetUniform(
610 fancyWaterShader
->GetBindingSlot(str_screenSize
),
611 static_cast<float>(g_Renderer
.GetWidth()),
612 static_cast<float>(g_Renderer
.GetHeight()));
614 if (waterManager
.m_WaterType
== L
"clap")
616 deviceCommandContext
->SetUniform(
617 fancyWaterShader
->GetBindingSlot(str_waveParams1
),
618 30.0f
, 1.5f
, 20.0f
, 0.03f
);
619 deviceCommandContext
->SetUniform(
620 fancyWaterShader
->GetBindingSlot(str_waveParams2
),
621 0.5f
, 0.0f
, 0.0f
, 0.0f
);
623 else if (waterManager
.m_WaterType
== L
"lake")
625 deviceCommandContext
->SetUniform(
626 fancyWaterShader
->GetBindingSlot(str_waveParams1
),
627 8.5f
, 1.5f
, 15.0f
, 0.03f
);
628 deviceCommandContext
->SetUniform(
629 fancyWaterShader
->GetBindingSlot(str_waveParams2
),
630 0.2f
, 0.0f
, 0.0f
, 0.07f
);
634 deviceCommandContext
->SetUniform(
635 fancyWaterShader
->GetBindingSlot(str_waveParams1
),
636 15.0f
, 0.8f
, 10.0f
, 0.1f
);
637 deviceCommandContext
->SetUniform(
638 fancyWaterShader
->GetBindingSlot(str_waveParams2
),
639 0.3f
, 0.0f
, 0.1f
, 0.3f
);
643 shadow
->BindTo(deviceCommandContext
, fancyWaterShader
);
645 for (CPatchRData
* data
: m
->visiblePatches
[cullGroup
])
647 data
->RenderWaterSurface(
648 deviceCommandContext
, m
->waterSurfaceWithDataVertexInputLayout
);
649 if (waterManager
.m_WaterFancyEffects
)
650 data
->RenderWaterShore(deviceCommandContext
, m
->waterShoreVertexInputLayout
);
652 deviceCommandContext
->EndPass();
657 void TerrainRenderer::RenderSimpleWater(
658 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
,
661 PROFILE3_GPU("simple water");
662 GPU_SCOPED_LABEL(deviceCommandContext
, "Render Simple Water");
664 const WaterManager
& waterManager
= g_Renderer
.GetSceneRenderer().GetWaterManager();
665 CLOSTexture
& losTexture
= g_Renderer
.GetSceneRenderer().GetScene().GetLOSTexture();
667 const double time
= waterManager
.m_WaterTexTimer
;
669 CShaderDefines context
;
670 if (g_Renderer
.GetSceneRenderer().GetWaterRenderMode() == WIREFRAME
)
671 context
.Add(str_MODE_WIREFRAME
, str_1
);
673 CShaderTechniquePtr waterSimpleTech
=
674 g_Renderer
.GetShaderManager().LoadEffect(str_water_simple
, context
);
675 deviceCommandContext
->SetGraphicsPipelineState(
676 waterSimpleTech
->GetGraphicsPipelineState());
677 deviceCommandContext
->BeginPass();
678 Renderer::Backend::IShaderProgram
* waterSimpleShader
= waterSimpleTech
->GetShader();
680 const CTexturePtr
& waterTexture
= waterManager
.m_WaterTexture
[waterManager
.GetCurrentTextureIndex(1.6)];
681 waterTexture
->UploadBackendTextureIfNeeded(deviceCommandContext
);
683 deviceCommandContext
->SetTexture(
684 waterSimpleShader
->GetBindingSlot(str_baseTex
), waterTexture
->GetBackendTexture());
685 deviceCommandContext
->SetTexture(
686 waterSimpleShader
->GetBindingSlot(str_losTex
), losTexture
.GetTextureSmooth());
688 const CMatrix3D transform
=
689 g_Renderer
.GetSceneRenderer().GetViewCamera().GetViewProjection();
690 deviceCommandContext
->SetUniform(
691 waterSimpleShader
->GetBindingSlot(str_transform
), transform
.AsFloatArray());
693 deviceCommandContext
->SetUniform(
694 waterSimpleShader
->GetBindingSlot(str_losTransform
),
695 losTexture
.GetTextureMatrix()[0], losTexture
.GetTextureMatrix()[12]);
696 deviceCommandContext
->SetUniform(
697 waterSimpleShader
->GetBindingSlot(str_time
), static_cast<float>(time
));
698 deviceCommandContext
->SetUniform(
699 waterSimpleShader
->GetBindingSlot(str_color
), waterManager
.m_WaterColor
.AsFloatArray());
701 for (CPatchRData
* data
: m
->visiblePatches
[cullGroup
])
703 data
->RenderWaterSurface(
704 deviceCommandContext
, m
->waterSurfaceVertexInputLayout
);
707 deviceCommandContext
->EndPass();
710 ///////////////////////////////////////////////////////////////////
711 // Render water that is part of the terrain
712 void TerrainRenderer::RenderWater(
713 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
,
714 const CShaderDefines
& context
, int cullGroup
, ShadowMap
* shadow
)
716 const WaterManager
& waterManager
= g_Renderer
.GetSceneRenderer().GetWaterManager();
718 if (!waterManager
.WillRenderFancyWater())
719 RenderSimpleWater(deviceCommandContext
, cullGroup
);
721 RenderFancyWater(deviceCommandContext
, context
, cullGroup
, shadow
);
724 void TerrainRenderer::RenderWaterFoamOccluders(
725 Renderer::Backend::IDeviceCommandContext
* deviceCommandContext
,
728 CSceneRenderer
& sceneRenderer
= g_Renderer
.GetSceneRenderer();
729 const WaterManager
& waterManager
= sceneRenderer
.GetWaterManager();
730 if (!waterManager
.WillRenderFancyWater())
733 if (!m
->shaderTechniqueSolidDepthTest
)
735 m
->shaderTechniqueSolidDepthTest
= g_Renderer
.GetShaderManager().LoadEffect(
737 [](Renderer::Backend::SGraphicsPipelineStateDesc
& pipelineStateDesc
)
739 pipelineStateDesc
.depthStencilState
.depthTestEnabled
= true;
740 pipelineStateDesc
.rasterizationState
.cullMode
= Renderer::Backend::CullMode::NONE
;
744 GPU_SCOPED_LABEL(deviceCommandContext
, "Render water foam occluders");
746 Renderer::Backend::IFramebuffer
* framebuffer
=
747 waterManager
.m_FancyEffectsOccludersFramebuffer
.get();
748 deviceCommandContext
->BeginFramebufferPass(framebuffer
);
749 Renderer::Backend::IDeviceCommandContext::Rect viewportRect
{};
750 viewportRect
.width
= framebuffer
->GetWidth();
751 viewportRect
.height
= framebuffer
->GetHeight();
752 deviceCommandContext
->SetViewports(1, &viewportRect
);
754 // Overwrite waves that would be behind the ground.
755 deviceCommandContext
->SetGraphicsPipelineState(
756 m
->shaderTechniqueSolidDepthTest
->GetGraphicsPipelineState());
757 deviceCommandContext
->BeginPass();
759 Renderer::Backend::IShaderProgram
* dummyShader
= m
->shaderTechniqueSolidDepthTest
->GetShader();
761 const CMatrix3D transform
= sceneRenderer
.GetViewCamera().GetViewProjection();
762 deviceCommandContext
->SetUniform(
763 dummyShader
->GetBindingSlot(str_transform
), transform
.AsFloatArray());
764 deviceCommandContext
->SetUniform(
765 dummyShader
->GetBindingSlot(str_color
), 0.0f
, 0.0f
, 0.0f
, 0.0f
);
767 for (CPatchRData
* data
: m
->visiblePatches
[cullGroup
])
768 data
->RenderWaterShore(deviceCommandContext
, m
->waterShoreVertexInputLayout
);
770 deviceCommandContext
->EndPass();
772 deviceCommandContext
->EndFramebufferPass();
775 void TerrainRenderer::RenderPriorities(CCanvas2D
& canvas
, int cullGroup
)
777 PROFILE("priorities");
779 ENSURE(m
->phase
== Phase_Render
);
781 CTextRenderer textRenderer
;
782 textRenderer
.SetCurrentFont(CStrIntern("mono-stroke-10"));
783 textRenderer
.SetCurrentColor(CColor(1.0f
, 1.0f
, 0.0f
, 1.0f
));
785 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
786 for (size_t i
= 0; i
< visiblePatches
.size(); ++i
)
787 visiblePatches
[i
]->RenderPriorities(textRenderer
);
789 canvas
.DrawText(textRenderer
);