2025-12-21 03:57:42 -08:00
|
|
|
/* Copyright (C) 2026 Wildfire Games.
|
2023-12-02 16:30:12 -08:00
|
|
|
* This file is part of 0 A.D.
|
2009-04-18 10:00:33 -07:00
|
|
|
*
|
2023-12-02 16:30:12 -08:00
|
|
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
2009-04-18 10:00:33 -07:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
2023-12-02 16:30:12 -08:00
|
|
|
* 0 A.D. is distributed in the hope that it will be useful,
|
2009-04-18 10:00:33 -07:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2023-12-02 16:30:12 -08:00
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
2009-04-18 10:00:33 -07:00
|
|
|
*/
|
|
|
|
|
|
2006-01-06 17:04:26 -08:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
|
2021-05-01 09:59:42 -07:00
|
|
|
#include "renderer/TerrainRenderer.h"
|
|
|
|
|
|
2006-01-06 17:04:26 -08:00
|
|
|
#include "graphics/Camera.h"
|
2021-05-30 12:10:10 -07:00
|
|
|
#include "graphics/Canvas2D.h"
|
2011-03-13 12:22:05 -07:00
|
|
|
#include "graphics/Decal.h"
|
2011-02-02 17:12:24 -08:00
|
|
|
#include "graphics/LOSTexture.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "graphics/LightEnv.h"
|
2006-01-06 17:04:26 -08:00
|
|
|
#include "graphics/Patch.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "graphics/ShaderDefines.h"
|
2011-03-26 13:17:21 -07:00
|
|
|
#include "graphics/ShaderManager.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "graphics/ShaderTechnique.h"
|
|
|
|
|
#include "graphics/ShaderTechniquePtr.h"
|
2012-02-12 12:45:31 -08:00
|
|
|
#include "graphics/TextRenderer.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "graphics/Texture.h"
|
2022-02-13 11:30:28 -08:00
|
|
|
#include "graphics/TextureManager.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "lib/debug.h"
|
|
|
|
|
#include "maths/BoundingBoxAligned.h"
|
2006-01-06 17:04:26 -08:00
|
|
|
#include "maths/MathUtil.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "maths/Matrix3D.h"
|
2022-11-06 11:40:47 -08:00
|
|
|
#include "maths/Vector2D.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "maths/Vector3D.h"
|
2009-03-24 14:00:41 -07:00
|
|
|
#include "ps/CLogger.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "ps/CStrIntern.h"
|
2021-05-18 04:09:54 -07:00
|
|
|
#include "ps/CStrInternStatic.h"
|
2006-01-06 17:04:26 -08:00
|
|
|
#include "ps/Profile.h"
|
2011-03-13 12:22:05 -07:00
|
|
|
#include "renderer/DecalRData.h"
|
2006-01-06 17:04:26 -08:00
|
|
|
#include "renderer/PatchRData.h"
|
2024-10-07 10:26:48 -07:00
|
|
|
#include "renderer/PostprocManager.h"
|
2006-01-06 17:04:26 -08:00
|
|
|
#include "renderer/Renderer.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "renderer/Scene.h"
|
2022-01-04 05:29:01 -08:00
|
|
|
#include "renderer/SceneRenderer.h"
|
2006-02-11 10:04:32 -08:00
|
|
|
#include "renderer/ShadowMap.h"
|
2021-05-01 09:59:42 -07:00
|
|
|
#include "renderer/SkyManager.h"
|
2006-01-06 17:04:26 -08:00
|
|
|
#include "renderer/WaterManager.h"
|
2025-07-06 11:15:27 -07:00
|
|
|
#include "renderer/backend/Format.h"
|
|
|
|
|
#include "renderer/backend/IDeviceCommandContext.h"
|
|
|
|
|
#include "renderer/backend/IFramebuffer.h"
|
|
|
|
|
#include "renderer/backend/IShaderProgram.h"
|
|
|
|
|
#include "renderer/backend/PipelineState.h"
|
2006-01-06 17:04:26 -08:00
|
|
|
|
2025-07-06 11:15:27 -07:00
|
|
|
#include <array>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <iterator>
|
2022-12-31 10:29:44 -08:00
|
|
|
#include <memory>
|
2025-07-06 11:15:27 -07:00
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
2022-12-31 10:29:44 -08:00
|
|
|
|
2026-05-10 14:57:20 -07:00
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
|
2006-01-06 17:04:26 -08:00
|
|
|
/**
|
|
|
|
|
* TerrainRenderer keeps track of which phase it is in, to detect
|
|
|
|
|
* when Submit, PrepareForRendering etc. are called in the wrong order.
|
|
|
|
|
*/
|
2022-01-06 14:44:54 -08:00
|
|
|
enum Phase
|
|
|
|
|
{
|
2006-01-06 17:04:26 -08:00
|
|
|
Phase_Submit,
|
|
|
|
|
Phase_Render
|
|
|
|
|
};
|
|
|
|
|
|
2026-05-10 14:57:20 -07:00
|
|
|
CMaterial::Pass GetMaterialPassFromCullGroup(const int cullGroup, const bool wireframe)
|
|
|
|
|
{
|
|
|
|
|
if (wireframe)
|
|
|
|
|
return CMaterial::Pass::WIREFRAME;
|
|
|
|
|
|
|
|
|
|
return cullGroup == CSceneRenderer::CULL_REFLECTIONS
|
|
|
|
|
? CMaterial::Pass::REFLECTIONS
|
|
|
|
|
: CMaterial::Pass::MAIN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2006-01-06 17:04:26 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class.
|
|
|
|
|
*/
|
|
|
|
|
struct TerrainRendererInternals
|
|
|
|
|
{
|
|
|
|
|
/// Which phase (submitting or rendering patches) are we in right now?
|
|
|
|
|
Phase phase;
|
|
|
|
|
|
2011-03-13 12:22:05 -07:00
|
|
|
/// Patches that were submitted for this frame
|
2022-01-04 05:29:01 -08:00
|
|
|
std::vector<CPatchRData*> visiblePatches[CSceneRenderer::CULL_MAX];
|
2011-03-13 12:22:05 -07:00
|
|
|
|
|
|
|
|
/// Decals that were submitted for this frame
|
2022-01-04 05:29:01 -08:00
|
|
|
std::vector<CDecalRData*> visibleDecals[CSceneRenderer::CULL_MAX];
|
2006-05-24 22:46:17 -07:00
|
|
|
|
|
|
|
|
/// Fancy water shader
|
2021-11-27 07:01:14 -08:00
|
|
|
CShaderTechniquePtr fancyWaterTech;
|
2012-09-28 11:20:36 -07:00
|
|
|
|
2026-05-10 14:57:20 -07:00
|
|
|
CShaderTechniquePtr shadowCasterTech, silhouettteOccluderTech, wireframeTech;
|
2026-05-10 14:56:57 -07:00
|
|
|
|
2022-12-31 10:29:44 -08:00
|
|
|
CShaderTechniquePtr shaderTechniqueSolid, shaderTechniqueSolidDepthTest;
|
|
|
|
|
|
2023-01-05 16:39:25 -08:00
|
|
|
Renderer::Backend::IVertexInputLayout* overlayVertexInputLayout = nullptr;
|
|
|
|
|
Renderer::Backend::IVertexInputLayout* decalsVertexInputLayout = nullptr;
|
|
|
|
|
|
|
|
|
|
Renderer::Backend::IVertexInputLayout* baseVertexInputLayout = nullptr;
|
|
|
|
|
Renderer::Backend::IVertexInputLayout* blendVertexInputLayout = nullptr;
|
|
|
|
|
Renderer::Backend::IVertexInputLayout* streamVertexInputLayout = nullptr;
|
|
|
|
|
Renderer::Backend::IVertexInputLayout* streamWithPositionAsTexCoordVertexInputLayout = nullptr;
|
|
|
|
|
Renderer::Backend::IVertexInputLayout* sideVertexInputLayout = nullptr;
|
|
|
|
|
|
|
|
|
|
Renderer::Backend::IVertexInputLayout* waterSurfaceVertexInputLayout = nullptr;
|
|
|
|
|
Renderer::Backend::IVertexInputLayout* waterSurfaceWithDataVertexInputLayout = nullptr;
|
|
|
|
|
Renderer::Backend::IVertexInputLayout* waterShoreVertexInputLayout = nullptr;
|
|
|
|
|
|
2012-09-28 11:20:36 -07:00
|
|
|
CSimulation2* simulation;
|
2006-01-06 17:04:26 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
// Construction/Destruction
|
|
|
|
|
TerrainRenderer::TerrainRenderer()
|
|
|
|
|
{
|
|
|
|
|
m = new TerrainRendererInternals();
|
|
|
|
|
m->phase = Phase_Submit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TerrainRenderer::~TerrainRenderer()
|
|
|
|
|
{
|
|
|
|
|
delete m;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-05 16:39:25 -08:00
|
|
|
void TerrainRenderer::Initialize()
|
|
|
|
|
{
|
|
|
|
|
const std::array<Renderer::Backend::SVertexAttributeFormat, 2> overlayAttributes{{
|
|
|
|
|
{Renderer::Backend::VertexAttributeStream::POSITION,
|
|
|
|
|
Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3,
|
|
|
|
|
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
|
|
|
|
|
{Renderer::Backend::VertexAttributeStream::UV0,
|
|
|
|
|
Renderer::Backend::Format::R32G32B32_SFLOAT, 0, sizeof(float) * 3,
|
|
|
|
|
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0}
|
|
|
|
|
}};
|
|
|
|
|
m->overlayVertexInputLayout = g_Renderer.GetVertexInputLayout(overlayAttributes);
|
|
|
|
|
|
|
|
|
|
m->decalsVertexInputLayout = CDecalRData::GetVertexInputLayout();
|
|
|
|
|
|
|
|
|
|
m->baseVertexInputLayout = CPatchRData::GetBaseVertexInputLayout();
|
|
|
|
|
m->blendVertexInputLayout = CPatchRData::GetBlendVertexInputLayout();
|
|
|
|
|
m->streamVertexInputLayout = CPatchRData::GetStreamVertexInputLayout(false);
|
|
|
|
|
m->streamWithPositionAsTexCoordVertexInputLayout =
|
|
|
|
|
CPatchRData::GetStreamVertexInputLayout(true);
|
|
|
|
|
m->sideVertexInputLayout = CPatchRData::GetSideVertexInputLayout();
|
|
|
|
|
|
|
|
|
|
m->waterSurfaceVertexInputLayout = CPatchRData::GetWaterSurfaceVertexInputLayout(false);
|
|
|
|
|
m->waterSurfaceWithDataVertexInputLayout = CPatchRData::GetWaterSurfaceVertexInputLayout(true);
|
|
|
|
|
m->waterShoreVertexInputLayout = CPatchRData::GetWaterShoreVertexInputLayout();
|
2026-05-10 14:56:57 -07:00
|
|
|
|
|
|
|
|
CShaderManager& shaderManager{g_Renderer.GetShaderManager()};
|
|
|
|
|
m->shadowCasterTech = shaderManager.LoadEffect(str_terrain_shadow_caster);
|
|
|
|
|
m->silhouettteOccluderTech = shaderManager.LoadEffect(str_terrain_silhouette_occluder);
|
2026-05-10 14:57:20 -07:00
|
|
|
m->wireframeTech = shaderManager.LoadEffect(str_terrain_wireframe);
|
2023-01-05 16:39:25 -08:00
|
|
|
}
|
|
|
|
|
|
2012-09-28 11:20:36 -07:00
|
|
|
void TerrainRenderer::SetSimulation(CSimulation2* simulation)
|
|
|
|
|
{
|
|
|
|
|
m->simulation = simulation;
|
|
|
|
|
}
|
2006-01-06 17:04:26 -08:00
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
// Submit a patch for rendering
|
2014-06-24 18:11:10 -07:00
|
|
|
void TerrainRenderer::Submit(int cullGroup, CPatch* patch)
|
2006-01-06 17:04:26 -08:00
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m->phase == Phase_Submit);
|
2006-01-06 17:04:26 -08:00
|
|
|
|
2011-03-13 12:22:05 -07:00
|
|
|
CPatchRData* data = (CPatchRData*)patch->GetRenderData();
|
2006-01-06 17:04:26 -08:00
|
|
|
if (data == 0)
|
|
|
|
|
{
|
|
|
|
|
// no renderdata for patch, create it now
|
2012-09-28 11:20:36 -07:00
|
|
|
data = new CPatchRData(patch, m->simulation);
|
2006-01-06 17:04:26 -08:00
|
|
|
patch->SetRenderData(data);
|
|
|
|
|
}
|
2012-09-28 11:20:36 -07:00
|
|
|
data->Update(m->simulation);
|
2006-01-06 17:04:26 -08:00
|
|
|
|
2014-06-24 18:11:10 -07:00
|
|
|
m->visiblePatches[cullGroup].push_back(data);
|
2006-01-06 17:04:26 -08:00
|
|
|
}
|
|
|
|
|
|
2011-03-13 12:22:05 -07:00
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
// Submit a decal for rendering
|
2014-06-24 18:11:10 -07:00
|
|
|
void TerrainRenderer::Submit(int cullGroup, CModelDecal* decal)
|
2011-03-13 12:22:05 -07:00
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m->phase == Phase_Submit);
|
2011-03-13 12:22:05 -07:00
|
|
|
|
|
|
|
|
CDecalRData* data = (CDecalRData*)decal->GetRenderData();
|
|
|
|
|
if (data == 0)
|
|
|
|
|
{
|
|
|
|
|
// no renderdata for decal, create it now
|
2012-09-28 11:20:36 -07:00
|
|
|
data = new CDecalRData(decal, m->simulation);
|
2011-03-13 12:22:05 -07:00
|
|
|
decal->SetRenderData(data);
|
|
|
|
|
}
|
2012-09-28 11:20:36 -07:00
|
|
|
data->Update(m->simulation);
|
2011-03-13 12:22:05 -07:00
|
|
|
|
2014-06-24 18:11:10 -07:00
|
|
|
m->visibleDecals[cullGroup].push_back(data);
|
2011-03-13 12:22:05 -07:00
|
|
|
}
|
2006-01-06 17:04:26 -08:00
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
// Prepare for rendering
|
|
|
|
|
void TerrainRenderer::PrepareForRendering()
|
|
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m->phase == Phase_Submit);
|
2006-01-06 17:04:26 -08:00
|
|
|
|
|
|
|
|
m->phase = Phase_Render;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
// Clear submissions lists
|
|
|
|
|
void TerrainRenderer::EndFrame()
|
|
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m->phase == Phase_Render || m->phase == Phase_Submit);
|
2006-01-06 17:04:26 -08:00
|
|
|
|
2022-01-04 05:29:01 -08:00
|
|
|
for (int i = 0; i < CSceneRenderer::CULL_MAX; ++i)
|
2011-07-12 16:48:05 -07:00
|
|
|
{
|
2014-06-24 18:11:10 -07:00
|
|
|
m->visiblePatches[i].clear();
|
|
|
|
|
m->visibleDecals[i].clear();
|
2011-07-12 16:48:05 -07:00
|
|
|
}
|
|
|
|
|
|
2014-06-24 18:11:10 -07:00
|
|
|
m->phase = Phase_Submit;
|
2011-07-12 16:48:05 -07:00
|
|
|
}
|
|
|
|
|
|
2022-01-19 09:28:47 -08:00
|
|
|
void TerrainRenderer::RenderTerrainOverlayTexture(
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
2022-11-06 11:40:47 -08:00
|
|
|
int cullGroup, const CVector2D& textureTransform,
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::ITexture* texture)
|
2012-04-24 09:46:32 -07:00
|
|
|
{
|
|
|
|
|
ENSURE(m->phase == Phase_Render);
|
|
|
|
|
|
2014-06-24 18:11:10 -07:00
|
|
|
std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
|
2012-04-24 09:46:32 -07:00
|
|
|
|
2020-11-09 10:50:40 -08:00
|
|
|
CShaderTechniquePtr debugOverlayTech =
|
|
|
|
|
g_Renderer.GetShaderManager().LoadEffect(str_debug_overlay);
|
2022-01-19 09:28:47 -08:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(
|
2022-12-31 10:29:44 -08:00
|
|
|
debugOverlayTech->GetGraphicsPipelineState());
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->BeginPass();
|
2022-05-02 13:57:22 -07:00
|
|
|
Renderer::Backend::IShaderProgram* debugOverlayShader = debugOverlayTech->GetShader();
|
|
|
|
|
|
|
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
debugOverlayShader->GetBindingSlot(str_baseTex), texture);
|
|
|
|
|
const CMatrix3D transform =
|
|
|
|
|
g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection();
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
debugOverlayShader->GetBindingSlot(str_transform), transform.AsFloatArray());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
2022-11-06 11:40:47 -08:00
|
|
|
debugOverlayShader->GetBindingSlot(str_textureTransform), textureTransform.AsFloatArray());
|
2023-01-05 16:39:25 -08:00
|
|
|
CPatchRData::RenderStreams(
|
|
|
|
|
deviceCommandContext, m->streamWithPositionAsTexCoordVertexInputLayout, visiblePatches);
|
2012-04-24 09:46:32 -07:00
|
|
|
|
|
|
|
|
// To make the overlay visible over water, render an additional map-sized
|
2020-11-09 10:50:40 -08:00
|
|
|
// water-height patch.
|
2012-04-24 09:46:32 -07:00
|
|
|
CBoundingBoxAligned waterBounds;
|
2020-11-09 10:50:40 -08:00
|
|
|
for (CPatchRData* data : visiblePatches)
|
2012-04-24 09:46:32 -07:00
|
|
|
waterBounds += data->GetWaterBounds();
|
|
|
|
|
if (!waterBounds.IsEmpty())
|
|
|
|
|
{
|
2020-11-09 10:50:40 -08:00
|
|
|
// Add a delta to avoid z-fighting.
|
2022-01-04 05:29:01 -08:00
|
|
|
const float height = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight + 0.05f;
|
2022-02-25 16:37:27 -08:00
|
|
|
const float waterPos[] =
|
|
|
|
|
{
|
2020-11-09 10:50:40 -08:00
|
|
|
waterBounds[0].X, height, waterBounds[0].Z,
|
|
|
|
|
waterBounds[1].X, height, waterBounds[0].Z,
|
2022-02-25 16:37:27 -08:00
|
|
|
waterBounds[1].X, height, waterBounds[1].Z,
|
|
|
|
|
waterBounds[0].X, height, waterBounds[0].Z,
|
|
|
|
|
waterBounds[1].X, height, waterBounds[1].Z,
|
|
|
|
|
waterBounds[0].X, height, waterBounds[1].Z
|
2012-04-24 09:46:32 -07:00
|
|
|
};
|
2020-11-09 10:50:40 -08:00
|
|
|
|
2023-01-05 16:39:25 -08:00
|
|
|
deviceCommandContext->SetVertexInputLayout(m->overlayVertexInputLayout);
|
2022-04-23 13:11:14 -07:00
|
|
|
|
2022-05-24 00:11:23 -07:00
|
|
|
deviceCommandContext->SetVertexBufferData(
|
|
|
|
|
0, waterPos, std::size(waterPos) * sizeof(waterPos[0]));
|
2020-11-09 10:50:40 -08:00
|
|
|
|
2022-03-02 23:09:59 -08:00
|
|
|
deviceCommandContext->Draw(0, 6);
|
2012-04-24 09:46:32 -07:00
|
|
|
}
|
|
|
|
|
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->EndPass();
|
2012-04-24 09:46:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-03-26 13:17:21 -07:00
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set up all the uniforms for a shader pass.
|
|
|
|
|
*/
|
2022-05-02 13:57:22 -07:00
|
|
|
void TerrainRenderer::PrepareShader(
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
2022-05-02 13:57:22 -07:00
|
|
|
Renderer::Backend::IShaderProgram* shader, ShadowMap* shadow)
|
2011-03-26 13:17:21 -07:00
|
|
|
{
|
2022-01-04 05:29:01 -08:00
|
|
|
CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer();
|
2012-02-13 06:02:14 -08:00
|
|
|
|
2022-05-02 13:57:22 -07:00
|
|
|
const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection();
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
shader->GetBindingSlot(str_transform), transform.AsFloatArray());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
shader->GetBindingSlot(str_cameraPos),
|
|
|
|
|
sceneRenderer.GetViewCamera().GetOrientation().GetTranslation().AsFloatArray());
|
2022-01-04 05:29:01 -08:00
|
|
|
|
|
|
|
|
const CLightEnv& lightEnv = sceneRenderer.GetLightEnv();
|
2011-03-26 13:17:21 -07:00
|
|
|
|
|
|
|
|
if (shadow)
|
2022-05-02 13:57:22 -07:00
|
|
|
shadow->BindTo(deviceCommandContext, shader);
|
2011-03-26 13:17:21 -07:00
|
|
|
|
2022-01-04 05:29:01 -08:00
|
|
|
CLOSTexture& los = sceneRenderer.GetScene().GetLOSTexture();
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
shader->GetBindingSlot(str_losTex), los.GetTextureSmooth());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
shader->GetBindingSlot(str_losTransform),
|
|
|
|
|
los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]);
|
|
|
|
|
|
2025-10-10 23:11:35 -07:00
|
|
|
lightEnv.Bind(deviceCommandContext, shader);
|
2011-03-26 13:17:21 -07:00
|
|
|
}
|
|
|
|
|
|
2022-01-19 09:28:47 -08:00
|
|
|
void TerrainRenderer::RenderTerrainShader(
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
2026-05-10 14:57:20 -07:00
|
|
|
const CShaderDefines& context, int cullGroup, ShadowMap* shadow,
|
|
|
|
|
const bool wireframe)
|
2011-03-26 13:17:21 -07:00
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m->phase == Phase_Render);
|
2011-03-26 13:17:21 -07:00
|
|
|
|
2014-06-24 18:11:10 -07:00
|
|
|
std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
|
|
|
|
|
std::vector<CDecalRData*>& visibleDecals = m->visibleDecals[cullGroup];
|
2011-07-12 16:48:05 -07:00
|
|
|
if (visiblePatches.empty() && visibleDecals.empty())
|
|
|
|
|
return;
|
|
|
|
|
|
2022-12-31 10:29:44 -08:00
|
|
|
if (!m->shaderTechniqueSolid)
|
|
|
|
|
{
|
|
|
|
|
m->shaderTechniqueSolid = g_Renderer.GetShaderManager().LoadEffect(
|
|
|
|
|
str_solid, {},
|
|
|
|
|
[](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc)
|
|
|
|
|
{
|
|
|
|
|
pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-26 13:17:21 -07:00
|
|
|
// render the solid black sides of the map first
|
2022-12-31 10:29:44 -08:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(
|
|
|
|
|
m->shaderTechniqueSolid->GetGraphicsPipelineState());
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->BeginPass();
|
2022-01-19 09:28:47 -08:00
|
|
|
|
2022-12-31 10:29:44 -08:00
|
|
|
Renderer::Backend::IShaderProgram* shaderSolid = m->shaderTechniqueSolid->GetShader();
|
2022-05-02 13:57:22 -07:00
|
|
|
const CMatrix3D transform =
|
|
|
|
|
g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection();
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
shaderSolid->GetBindingSlot(str_transform), transform.AsFloatArray());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
shaderSolid->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 1.0f);
|
2012-02-13 06:02:14 -08:00
|
|
|
|
2023-01-05 16:39:25 -08:00
|
|
|
CPatchRData::RenderSides(
|
|
|
|
|
deviceCommandContext, m->sideVertexInputLayout, visiblePatches);
|
2011-03-26 13:17:21 -07:00
|
|
|
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->EndPass();
|
2011-03-26 13:17:21 -07:00
|
|
|
|
2026-05-10 14:57:20 -07:00
|
|
|
const CMaterial::Pass materialPass{GetMaterialPassFromCullGroup(cullGroup, wireframe)};
|
|
|
|
|
|
2023-01-05 16:39:25 -08:00
|
|
|
CPatchRData::RenderBases(
|
2026-05-10 14:57:20 -07:00
|
|
|
deviceCommandContext, m->baseVertexInputLayout, visiblePatches, context, shadow, materialPass);
|
2011-03-26 13:17:21 -07:00
|
|
|
|
|
|
|
|
// render blend passes for each patch
|
2023-01-05 16:39:25 -08:00
|
|
|
CPatchRData::RenderBlends(
|
2026-05-10 14:57:20 -07:00
|
|
|
deviceCommandContext, m->blendVertexInputLayout, visiblePatches, context, shadow, materialPass);
|
2011-03-26 13:17:21 -07:00
|
|
|
|
2023-01-05 16:39:25 -08:00
|
|
|
CDecalRData::RenderDecals(
|
2026-05-10 14:57:20 -07:00
|
|
|
deviceCommandContext, m->decalsVertexInputLayout, visibleDecals, context, shadow, materialPass);
|
2006-01-06 17:04:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
// Render un-textured patches as polygons
|
2022-01-19 09:28:47 -08:00
|
|
|
void TerrainRenderer::RenderPatches(
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
2026-05-10 14:57:20 -07:00
|
|
|
int cullGroup, const CShaderDefines& defines, const CColor& color,
|
|
|
|
|
const bool wireframe)
|
2006-01-06 17:04:26 -08:00
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m->phase == Phase_Render);
|
2006-01-06 17:04:26 -08:00
|
|
|
|
2014-06-24 18:11:10 -07:00
|
|
|
std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
|
2011-07-12 16:48:05 -07:00
|
|
|
if (visiblePatches.empty())
|
|
|
|
|
return;
|
|
|
|
|
|
2022-02-25 14:05:06 -08:00
|
|
|
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain patches");
|
|
|
|
|
|
2026-05-10 14:56:57 -07:00
|
|
|
CShaderTechniquePtr solidTech;
|
2026-05-10 14:57:20 -07:00
|
|
|
if (wireframe)
|
2026-05-10 14:56:57 -07:00
|
|
|
{
|
2026-05-10 14:57:20 -07:00
|
|
|
solidTech = m->wireframeTech;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (cullGroup)
|
|
|
|
|
{
|
|
|
|
|
case CSceneRenderer::CULL_SHADOWS_CASCADE_0: [[fallthrough]];
|
|
|
|
|
case CSceneRenderer::CULL_SHADOWS_CASCADE_1: [[fallthrough]];
|
|
|
|
|
case CSceneRenderer::CULL_SHADOWS_CASCADE_2: [[fallthrough]];
|
|
|
|
|
case CSceneRenderer::CULL_SHADOWS_CASCADE_3:
|
|
|
|
|
ENSURE(defines.GetMap().empty());
|
|
|
|
|
solidTech = m->shadowCasterTech;
|
|
|
|
|
break;
|
|
|
|
|
case CSceneRenderer::CULL_SILHOUETTE_OCCLUDER:
|
|
|
|
|
ENSURE(defines.GetMap().empty());
|
|
|
|
|
solidTech = m->silhouettteOccluderTech;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
solidTech = g_Renderer.GetShaderManager().LoadEffect(str_terrain_solid, defines);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-05-10 14:56:57 -07:00
|
|
|
}
|
2022-01-19 09:28:47 -08:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(
|
2022-12-31 10:29:44 -08:00
|
|
|
solidTech->GetGraphicsPipelineState());
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->BeginPass();
|
2022-01-19 09:28:47 -08:00
|
|
|
|
2022-05-02 13:57:22 -07:00
|
|
|
Renderer::Backend::IShaderProgram* solidShader = solidTech->GetShader();
|
|
|
|
|
|
|
|
|
|
const CMatrix3D transform =
|
|
|
|
|
g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection();
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
solidShader->GetBindingSlot(str_transform), transform.AsFloatArray());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
solidShader->GetBindingSlot(str_color), color.AsFloatArray());
|
2012-02-13 06:02:14 -08:00
|
|
|
|
2023-01-05 16:39:25 -08:00
|
|
|
CPatchRData::RenderStreams(
|
|
|
|
|
deviceCommandContext, m->streamVertexInputLayout, visiblePatches);
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->EndPass();
|
2006-01-06 17:04:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
// Render outlines of submitted patches as lines
|
2022-02-25 14:05:06 -08:00
|
|
|
void TerrainRenderer::RenderOutlines(
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
2022-02-25 14:05:06 -08:00
|
|
|
int cullGroup)
|
2006-01-06 17:04:26 -08:00
|
|
|
{
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m->phase == Phase_Render);
|
2011-01-29 18:14:44 -08:00
|
|
|
|
2014-06-24 18:11:10 -07:00
|
|
|
std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
|
2011-07-12 16:48:05 -07:00
|
|
|
if (visiblePatches.empty())
|
|
|
|
|
return;
|
|
|
|
|
|
2022-02-25 14:05:06 -08:00
|
|
|
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain outlines");
|
|
|
|
|
|
2011-07-12 16:48:05 -07:00
|
|
|
for (size_t i = 0; i < visiblePatches.size(); ++i)
|
2025-12-21 03:57:42 -08:00
|
|
|
visiblePatches[i]->RenderOutline(*deviceCommandContext);
|
2006-01-06 17:04:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
2011-07-12 16:48:05 -07:00
|
|
|
// Scissor rectangle of water patches
|
2021-05-01 09:59:42 -07:00
|
|
|
CBoundingBoxAligned TerrainRenderer::ScissorWater(int cullGroup, const CCamera& camera)
|
2006-01-06 17:04:26 -08:00
|
|
|
{
|
2011-11-24 22:36:13 -08:00
|
|
|
CBoundingBoxAligned scissor;
|
2021-05-01 09:59:42 -07:00
|
|
|
for (const CPatchRData* data : m->visiblePatches[cullGroup])
|
2011-07-12 16:48:05 -07:00
|
|
|
{
|
2011-11-24 22:36:13 -08:00
|
|
|
const CBoundingBoxAligned& waterBounds = data->GetWaterBounds();
|
2011-07-12 16:48:05 -07:00
|
|
|
if (waterBounds.IsEmpty())
|
|
|
|
|
continue;
|
|
|
|
|
|
2021-05-01 09:59:42 -07:00
|
|
|
const CBoundingBoxAligned waterBoundsInViewPort =
|
|
|
|
|
camera.GetBoundsInViewPort(waterBounds);
|
|
|
|
|
if (!waterBoundsInViewPort.IsEmpty())
|
|
|
|
|
scissor += waterBoundsInViewPort;
|
2011-07-12 16:48:05 -07:00
|
|
|
}
|
2022-05-24 12:15:26 -07:00
|
|
|
if (scissor.IsEmpty())
|
|
|
|
|
return scissor;
|
2021-05-01 09:59:42 -07:00
|
|
|
return CBoundingBoxAligned(
|
|
|
|
|
CVector3D(Clamp(scissor[0].X, -1.0f, 1.0f), Clamp(scissor[0].Y, -1.0f, 1.0f), -1.0f),
|
|
|
|
|
CVector3D(Clamp(scissor[1].X, -1.0f, 1.0f), Clamp(scissor[1].Y, -1.0f, 1.0f), 1.0f));
|
2011-07-12 16:48:05 -07:00
|
|
|
}
|
2010-03-21 07:18:15 -07:00
|
|
|
|
2011-07-12 16:48:05 -07:00
|
|
|
// Render fancy water
|
2022-01-19 09:28:47 -08:00
|
|
|
bool TerrainRenderer::RenderFancyWater(
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
2022-01-19 09:28:47 -08:00
|
|
|
const CShaderDefines& context, int cullGroup, ShadowMap* shadow)
|
2011-07-12 16:48:05 -07:00
|
|
|
{
|
2025-04-16 13:38:34 -07:00
|
|
|
PROFILE3("fancy water");
|
2022-02-18 14:38:45 -08:00
|
|
|
GPU_SCOPED_LABEL(deviceCommandContext, "Render fancy water");
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2022-01-04 05:29:01 -08:00
|
|
|
CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer();
|
|
|
|
|
|
|
|
|
|
WaterManager& waterManager = sceneRenderer.GetWaterManager();
|
2012-10-31 11:42:17 -07:00
|
|
|
CShaderDefines defines = context;
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2006-05-24 22:46:17 -07:00
|
|
|
// If we're using fancy water, make sure its shader is loaded
|
2022-01-03 02:49:12 -08:00
|
|
|
if (!m->fancyWaterTech || waterManager.m_NeedsReloading)
|
2006-05-24 22:46:17 -07:00
|
|
|
{
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterRealDepth)
|
2013-09-29 06:19:52 -07:00
|
|
|
defines.Add(str_USE_REAL_DEPTH, str_1);
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterFancyEffects)
|
2014-07-01 09:05:05 -07:00
|
|
|
defines.Add(str_USE_FANCY_EFFECTS, str_1);
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterRefraction)
|
2013-09-29 06:19:52 -07:00
|
|
|
defines.Add(str_USE_REFRACTION, str_1);
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterReflection)
|
2013-09-29 06:19:52 -07:00
|
|
|
defines.Add(str_USE_REFLECTION, str_1);
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2021-12-13 22:34:02 -08:00
|
|
|
m->fancyWaterTech = g_Renderer.GetShaderManager().LoadEffect(str_water_high, defines);
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2021-11-27 07:01:14 -08:00
|
|
|
if (!m->fancyWaterTech)
|
2009-03-24 14:00:41 -07:00
|
|
|
{
|
2021-11-27 07:01:14 -08:00
|
|
|
LOGERROR("Failed to load water shader. Falling back to a simple water.\n");
|
2022-01-03 02:49:12 -08:00
|
|
|
waterManager.m_RenderWater = false;
|
2011-07-12 16:48:05 -07:00
|
|
|
return false;
|
2009-03-24 14:00:41 -07:00
|
|
|
}
|
2022-01-03 02:49:12 -08:00
|
|
|
waterManager.m_NeedsReloading = false;
|
2006-05-24 22:46:17 -07:00
|
|
|
}
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2022-01-04 05:29:01 -08:00
|
|
|
CLOSTexture& losTexture = sceneRenderer.GetScene().GetLOSTexture();
|
2012-10-31 11:42:17 -07:00
|
|
|
|
2012-11-04 07:54:36 -08:00
|
|
|
// Calculating the advanced informations about Foam and all if the quality calls for it.
|
2013-08-18 02:27:11 -07:00
|
|
|
/*if (WaterMgr->m_NeedInfoUpdate && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves))
|
2013-04-27 05:20:42 -07:00
|
|
|
{
|
2013-08-18 02:27:11 -07:00
|
|
|
WaterMgr->m_NeedInfoUpdate = false;
|
2012-11-04 07:54:36 -08:00
|
|
|
WaterMgr->CreateSuperfancyInfo();
|
2013-04-27 05:20:42 -07:00
|
|
|
}*/
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2022-01-03 02:49:12 -08:00
|
|
|
const double time = waterManager.m_WaterTexTimer;
|
|
|
|
|
const float repeatPeriod = waterManager.m_RepeatPeriod;
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2022-01-19 09:28:47 -08:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(
|
2022-12-31 10:29:44 -08:00
|
|
|
m->fancyWaterTech->GetGraphicsPipelineState());
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->BeginPass();
|
2022-05-02 13:57:22 -07:00
|
|
|
Renderer::Backend::IShaderProgram* fancyWaterShader = m->fancyWaterTech->GetShader();
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2022-01-04 05:29:01 -08:00
|
|
|
const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera();
|
2006-05-24 22:46:17 -07:00
|
|
|
|
2021-12-09 10:01:28 -08:00
|
|
|
const double period = 8.0;
|
2022-02-13 11:30:28 -08:00
|
|
|
// TODO: move uploading to a prepare function during loading.
|
|
|
|
|
const CTexturePtr& currentNormalTexture = waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)];
|
|
|
|
|
const CTexturePtr& nextNormalTexture = waterManager.m_NormalMap[waterManager.GetNextTextureIndex(period)];
|
2022-05-02 13:57:22 -07:00
|
|
|
|
2022-02-13 11:30:28 -08:00
|
|
|
currentNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
|
|
|
|
nextNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
2022-05-02 13:57:22 -07:00
|
|
|
|
|
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_normalMap),
|
|
|
|
|
currentNormalTexture->GetBackendTexture());
|
|
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_normalMap2),
|
|
|
|
|
nextNormalTexture->GetBackendTexture());
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterFancyEffects)
|
2014-07-28 03:14:00 -07:00
|
|
|
{
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_waterEffectsTex),
|
|
|
|
|
waterManager.m_FancyTexture.get());
|
2014-07-28 03:14:00 -07:00
|
|
|
}
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterRefraction && waterManager.m_WaterRealDepth)
|
2020-11-11 10:46:52 -08:00
|
|
|
{
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_depthTex),
|
|
|
|
|
waterManager.m_RefrFboDepthTexture.get());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_projInvTransform),
|
|
|
|
|
waterManager.m_RefractionProjInvMatrix.AsFloatArray());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_viewInvTransform),
|
|
|
|
|
waterManager.m_RefractionViewInvMatrix.AsFloatArray());
|
2020-11-11 10:46:52 -08:00
|
|
|
}
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterRefraction)
|
2022-05-02 13:57:22 -07:00
|
|
|
{
|
|
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_refractionMap),
|
|
|
|
|
waterManager.m_RefractionTexture.get());
|
|
|
|
|
}
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterReflection)
|
2022-05-02 13:57:22 -07:00
|
|
|
{
|
|
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_reflectionMap),
|
|
|
|
|
waterManager.m_ReflectionTexture.get());
|
|
|
|
|
}
|
|
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_losTex), losTexture.GetTextureSmooth());
|
2011-07-12 16:48:05 -07:00
|
|
|
|
2022-01-04 05:29:01 -08:00
|
|
|
const CLightEnv& lightEnv = sceneRenderer.GetLightEnv();
|
2012-10-31 11:42:17 -07:00
|
|
|
|
2022-05-02 13:57:22 -07:00
|
|
|
const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection();
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_transform), transform.AsFloatArray());
|
2014-07-28 03:14:00 -07:00
|
|
|
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_skyCube),
|
|
|
|
|
sceneRenderer.GetSkyManager().GetSkyCube());
|
2021-03-24 09:40:03 -07:00
|
|
|
// TODO: check that this rotates in the right direction.
|
|
|
|
|
CMatrix3D skyBoxRotation;
|
|
|
|
|
skyBoxRotation.SetIdentity();
|
|
|
|
|
skyBoxRotation.RotateY(M_PI + lightEnv.GetRotation());
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_skyBoxRot),
|
|
|
|
|
skyBoxRotation.AsFloatArray());
|
2021-03-24 09:40:03 -07:00
|
|
|
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterRefraction)
|
2022-05-02 13:57:22 -07:00
|
|
|
{
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_refractionMatrix),
|
|
|
|
|
waterManager.m_RefractionMatrix.AsFloatArray());
|
|
|
|
|
}
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterReflection)
|
2022-05-02 13:57:22 -07:00
|
|
|
{
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_reflectionMatrix),
|
|
|
|
|
waterManager.m_ReflectionMatrix.AsFloatArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_color), waterManager.m_WaterColor.AsFloatArray());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_tint), waterManager.m_WaterTint.AsFloatArray());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_waviness), waterManager.m_Waviness);
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_murkiness), waterManager.m_Murkiness);
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_windAngle), waterManager.m_WindAngle);
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_repeatScale), 1.0f / repeatPeriod);
|
|
|
|
|
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_losTransform),
|
|
|
|
|
losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12]);
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_cameraPos),
|
|
|
|
|
camera.GetOrientation().GetTranslation().AsFloatArray());
|
|
|
|
|
|
2025-10-10 23:11:35 -07:00
|
|
|
lightEnv.Bind(deviceCommandContext, fancyWaterShader);
|
|
|
|
|
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_time), static_cast<float>(time));
|
2024-10-07 10:26:48 -07:00
|
|
|
const float scale{g_Renderer.GetPostprocManager().IsEnabled()
|
|
|
|
|
? g_Renderer.GetPostprocManager().GetScale() : 1.0f};
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_screenSize),
|
2024-10-07 10:26:48 -07:00
|
|
|
g_Renderer.GetWidth() * scale, g_Renderer.GetHeight() * scale);
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2022-01-03 02:49:12 -08:00
|
|
|
if (waterManager.m_WaterType == L"clap")
|
2014-07-03 13:07:15 -07:00
|
|
|
{
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_waveParams1),
|
|
|
|
|
30.0f, 1.5f, 20.0f, 0.03f);
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_waveParams2),
|
|
|
|
|
0.5f, 0.0f, 0.0f, 0.0f);
|
2014-07-28 03:14:00 -07:00
|
|
|
}
|
2022-01-03 02:49:12 -08:00
|
|
|
else if (waterManager.m_WaterType == L"lake")
|
2014-07-28 03:14:00 -07:00
|
|
|
{
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_waveParams1),
|
|
|
|
|
8.5f, 1.5f, 15.0f, 0.03f);
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_waveParams2),
|
|
|
|
|
0.2f, 0.0f, 0.0f, 0.07f);
|
2014-07-28 03:14:00 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-05-02 13:57:22 -07:00
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_waveParams1),
|
|
|
|
|
15.0f, 0.8f, 10.0f, 0.1f);
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
fancyWaterShader->GetBindingSlot(str_waveParams2),
|
|
|
|
|
0.3f, 0.0f, 0.1f, 0.3f);
|
2014-07-03 13:07:15 -07:00
|
|
|
}
|
2016-11-23 06:09:58 -08:00
|
|
|
|
2021-01-15 07:45:39 -08:00
|
|
|
if (shadow)
|
2022-05-02 13:57:22 -07:00
|
|
|
shadow->BindTo(deviceCommandContext, fancyWaterShader);
|
2006-05-24 22:46:17 -07:00
|
|
|
|
2022-01-20 09:31:21 -08:00
|
|
|
for (CPatchRData* data : m->visiblePatches[cullGroup])
|
2006-05-24 22:46:17 -07:00
|
|
|
{
|
2023-01-05 16:39:25 -08:00
|
|
|
data->RenderWaterSurface(
|
|
|
|
|
deviceCommandContext, m->waterSurfaceWithDataVertexInputLayout);
|
2022-01-20 09:31:21 -08:00
|
|
|
if (waterManager.m_WaterFancyEffects)
|
2023-01-05 16:39:25 -08:00
|
|
|
data->RenderWaterShore(deviceCommandContext, m->waterShoreVertexInputLayout);
|
2006-05-24 22:46:17 -07:00
|
|
|
}
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->EndPass();
|
2006-01-06 17:04:26 -08:00
|
|
|
|
2011-07-12 16:48:05 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2006-05-27 19:13:32 -07:00
|
|
|
|
2022-01-19 09:28:47 -08:00
|
|
|
void TerrainRenderer::RenderSimpleWater(
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
2022-01-19 09:28:47 -08:00
|
|
|
int cullGroup)
|
2011-07-12 16:48:05 -07:00
|
|
|
{
|
2025-04-16 13:38:34 -07:00
|
|
|
PROFILE3("simple water");
|
2022-02-18 14:38:45 -08:00
|
|
|
GPU_SCOPED_LABEL(deviceCommandContext, "Render Simple Water");
|
2006-05-24 22:46:17 -07:00
|
|
|
|
2026-05-10 14:57:12 -07:00
|
|
|
CSceneRenderer& sceneRenderer{g_Renderer.GetSceneRenderer()};
|
|
|
|
|
const WaterManager& waterManager{sceneRenderer.GetWaterManager()};
|
|
|
|
|
CLOSTexture& losTexture{sceneRenderer.GetScene().GetLOSTexture()};
|
2011-07-12 16:48:05 -07:00
|
|
|
|
2022-01-03 02:49:12 -08:00
|
|
|
const double time = waterManager.m_WaterTexTimer;
|
2011-07-12 16:48:05 -07:00
|
|
|
|
2026-05-10 14:57:12 -07:00
|
|
|
CShaderTechniquePtr waterSimpleTech{
|
|
|
|
|
g_Renderer.GetShaderManager().LoadEffect(
|
|
|
|
|
sceneRenderer.GetWaterRenderMode() == WIREFRAME
|
|
|
|
|
? str_water_simple_wireframe
|
|
|
|
|
: str_water_simple, {})};
|
2022-01-19 09:28:47 -08:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(
|
2022-12-31 10:29:44 -08:00
|
|
|
waterSimpleTech->GetGraphicsPipelineState());
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->BeginPass();
|
2022-05-02 13:57:22 -07:00
|
|
|
Renderer::Backend::IShaderProgram* waterSimpleShader = waterSimpleTech->GetShader();
|
2020-11-04 14:25:08 -08:00
|
|
|
|
2022-02-13 11:30:28 -08:00
|
|
|
const CTexturePtr& waterTexture = waterManager.m_WaterTexture[waterManager.GetCurrentTextureIndex(1.6)];
|
|
|
|
|
waterTexture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
2022-05-02 13:57:22 -07:00
|
|
|
|
|
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
waterSimpleShader->GetBindingSlot(str_baseTex), waterTexture->GetBackendTexture());
|
|
|
|
|
deviceCommandContext->SetTexture(
|
|
|
|
|
waterSimpleShader->GetBindingSlot(str_losTex), losTexture.GetTextureSmooth());
|
|
|
|
|
|
|
|
|
|
const CMatrix3D transform =
|
|
|
|
|
g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection();
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
waterSimpleShader->GetBindingSlot(str_transform), transform.AsFloatArray());
|
|
|
|
|
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
waterSimpleShader->GetBindingSlot(str_losTransform),
|
|
|
|
|
losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12]);
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
waterSimpleShader->GetBindingSlot(str_time), static_cast<float>(time));
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
waterSimpleShader->GetBindingSlot(str_color), waterManager.m_WaterColor.AsFloatArray());
|
2012-02-13 06:02:14 -08:00
|
|
|
|
2023-01-05 16:39:25 -08:00
|
|
|
for (CPatchRData* data : m->visiblePatches[cullGroup])
|
2011-07-12 16:48:05 -07:00
|
|
|
{
|
2023-01-05 16:39:25 -08:00
|
|
|
data->RenderWaterSurface(
|
|
|
|
|
deviceCommandContext, m->waterSurfaceVertexInputLayout);
|
2006-05-28 14:58:56 -07:00
|
|
|
}
|
|
|
|
|
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->EndPass();
|
2006-01-06 17:04:26 -08:00
|
|
|
}
|
2011-01-29 08:31:48 -08:00
|
|
|
|
2011-07-12 16:48:05 -07:00
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
|
// Render water that is part of the terrain
|
2022-01-19 09:28:47 -08:00
|
|
|
void TerrainRenderer::RenderWater(
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
2022-01-19 09:28:47 -08:00
|
|
|
const CShaderDefines& context, int cullGroup, ShadowMap* shadow)
|
2011-07-12 16:48:05 -07:00
|
|
|
{
|
2022-01-06 14:44:54 -08:00
|
|
|
const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager();
|
2014-07-01 09:05:05 -07:00
|
|
|
|
2022-01-03 02:49:12 -08:00
|
|
|
if (!waterManager.WillRenderFancyWater())
|
2022-01-19 09:28:47 -08:00
|
|
|
RenderSimpleWater(deviceCommandContext, cullGroup);
|
2012-11-04 07:54:36 -08:00
|
|
|
else
|
2022-01-19 09:28:47 -08:00
|
|
|
RenderFancyWater(deviceCommandContext, context, cullGroup, shadow);
|
2011-07-12 16:48:05 -07:00
|
|
|
}
|
|
|
|
|
|
2022-01-19 09:28:47 -08:00
|
|
|
void TerrainRenderer::RenderWaterFoamOccluders(
|
2022-05-08 15:02:46 -07:00
|
|
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
2022-01-19 09:28:47 -08:00
|
|
|
int cullGroup)
|
2022-01-06 14:44:54 -08:00
|
|
|
{
|
|
|
|
|
CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer();
|
|
|
|
|
const WaterManager& waterManager = sceneRenderer.GetWaterManager();
|
|
|
|
|
if (!waterManager.WillRenderFancyWater())
|
|
|
|
|
return;
|
|
|
|
|
|
2022-12-31 10:29:44 -08:00
|
|
|
if (!m->shaderTechniqueSolidDepthTest)
|
|
|
|
|
{
|
|
|
|
|
m->shaderTechniqueSolidDepthTest = g_Renderer.GetShaderManager().LoadEffect(
|
2023-01-06 11:11:47 -08:00
|
|
|
str_solid, {},
|
|
|
|
|
[](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc)
|
|
|
|
|
{
|
|
|
|
|
pipelineStateDesc.depthStencilState.depthTestEnabled = true;
|
|
|
|
|
pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE;
|
|
|
|
|
});
|
2022-12-31 10:29:44 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-18 14:38:45 -08:00
|
|
|
GPU_SCOPED_LABEL(deviceCommandContext, "Render water foam occluders");
|
|
|
|
|
|
2023-01-06 11:11:47 -08:00
|
|
|
Renderer::Backend::IFramebuffer* framebuffer =
|
|
|
|
|
waterManager.m_FancyEffectsOccludersFramebuffer.get();
|
|
|
|
|
deviceCommandContext->BeginFramebufferPass(framebuffer);
|
|
|
|
|
Renderer::Backend::IDeviceCommandContext::Rect viewportRect{};
|
|
|
|
|
viewportRect.width = framebuffer->GetWidth();
|
|
|
|
|
viewportRect.height = framebuffer->GetHeight();
|
|
|
|
|
deviceCommandContext->SetViewports(1, &viewportRect);
|
2022-01-06 14:44:54 -08:00
|
|
|
|
|
|
|
|
// Overwrite waves that would be behind the ground.
|
2022-12-31 10:29:44 -08:00
|
|
|
deviceCommandContext->SetGraphicsPipelineState(
|
|
|
|
|
m->shaderTechniqueSolidDepthTest->GetGraphicsPipelineState());
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->BeginPass();
|
2022-01-06 14:44:54 -08:00
|
|
|
|
2022-12-31 10:29:44 -08:00
|
|
|
Renderer::Backend::IShaderProgram* dummyShader = m->shaderTechniqueSolidDepthTest->GetShader();
|
2022-05-02 13:57:22 -07:00
|
|
|
|
|
|
|
|
const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection();
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
dummyShader->GetBindingSlot(str_transform), transform.AsFloatArray());
|
|
|
|
|
deviceCommandContext->SetUniform(
|
|
|
|
|
dummyShader->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
|
|
2022-01-06 14:44:54 -08:00
|
|
|
for (CPatchRData* data : m->visiblePatches[cullGroup])
|
2023-01-05 16:39:25 -08:00
|
|
|
data->RenderWaterShore(deviceCommandContext, m->waterShoreVertexInputLayout);
|
2022-05-02 13:57:22 -07:00
|
|
|
|
2022-03-14 15:16:14 -07:00
|
|
|
deviceCommandContext->EndPass();
|
2022-01-06 14:44:54 -08:00
|
|
|
|
2022-10-12 14:51:27 -07:00
|
|
|
deviceCommandContext->EndFramebufferPass();
|
2022-01-06 14:44:54 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-25 00:14:11 -08:00
|
|
|
void TerrainRenderer::RenderPriorities(CCanvas2D& canvas, int cullGroup)
|
2011-01-29 08:31:48 -08:00
|
|
|
{
|
2011-11-09 05:09:01 -08:00
|
|
|
PROFILE("priorities");
|
2011-01-29 08:31:48 -08:00
|
|
|
|
2011-04-30 06:01:45 -07:00
|
|
|
ENSURE(m->phase == Phase_Render);
|
2011-01-29 18:14:44 -08:00
|
|
|
|
2021-05-30 11:28:06 -07:00
|
|
|
CTextRenderer textRenderer;
|
2025-07-02 06:43:04 -07:00
|
|
|
textRenderer.SetCurrentFont(CStrIntern{"mono-stroke-10"}, CStrIntern{});
|
2021-06-02 14:21:28 -07:00
|
|
|
textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 0.0f, 1.0f));
|
2011-01-29 08:31:48 -08:00
|
|
|
|
2014-06-24 18:11:10 -07:00
|
|
|
std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
|
|
|
|
|
for (size_t i = 0; i < visiblePatches.size(); ++i)
|
|
|
|
|
visiblePatches[i]->RenderPriorities(textRenderer);
|
2012-02-12 12:45:31 -08:00
|
|
|
|
2021-05-30 12:10:10 -07:00
|
|
|
canvas.DrawText(textRenderer);
|
2011-01-29 08:31:48 -08:00
|
|
|
}
|