Merge 'remotes/trunk'
[0ad.git] / source / renderer / TerrainRenderer.cpp
blob414d7378022ce713c6d38c7aa62aa6a1dab24c67
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"
39 #include "ps/Game.h"
40 #include "ps/Profile.h"
41 #include "ps/World.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"
54 #include <memory>
56 /**
57 * TerrainRenderer keeps track of which phase it is in, to detect
58 * when Submit, PrepareForRendering etc. are called in the wrong order.
60 enum Phase
62 Phase_Submit,
63 Phase_Render
67 /**
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?
73 Phase phase;
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()
114 delete m;
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();
155 if (data == 0)
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();
173 if (data == 0)
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();
286 if (shadow)
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())
323 return;
325 if (!m->shaderTechniqueSolid)
327 m->shaderTechniqueSolid = g_Renderer.GetShaderManager().LoadEffect(
328 str_solid, {},
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())
374 return;
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,
402 int cullGroup)
404 ENSURE(m->phase == Phase_Render);
406 std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
407 if (visiblePatches.empty())
408 return;
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())
426 continue;
428 const CBoundingBoxAligned waterBoundsInViewPort =
429 camera.GetBoundsInViewPort(waterBounds);
430 if (!waterBoundsInViewPort.IsEmpty())
431 scissor += waterBoundsInViewPort;
433 if (scissor.IsEmpty())
434 return scissor;
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;
471 return 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);
632 else
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);
642 if (shadow)
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();
654 return true;
657 void TerrainRenderer::RenderSimpleWater(
658 Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
659 int cullGroup)
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);
720 else
721 RenderFancyWater(deviceCommandContext, context, cullGroup, shadow);
724 void TerrainRenderer::RenderWaterFoamOccluders(
725 Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
726 int cullGroup)
728 CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer();
729 const WaterManager& waterManager = sceneRenderer.GetWaterManager();
730 if (!waterManager.WillRenderFancyWater())
731 return;
733 if (!m->shaderTechniqueSolidDepthTest)
735 m->shaderTechniqueSolidDepthTest = g_Renderer.GetShaderManager().LoadEffect(
736 str_solid, {},
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);