mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Moves all rendering to material passes
Now we should use material passes instead of context and defines to select a needed shader. It allows us to reduce the number of shader combinations we use and reduce memory consumption.
This commit is contained in:
parent
aced56c336
commit
18a16aa135
11 changed files with 193 additions and 132 deletions
|
|
@ -49,14 +49,6 @@ X(DISABLE_RECEIVE_SHADOWS)
|
|||
X(IGNORE_LOS)
|
||||
X(MINIMAP_BASE)
|
||||
X(MINIMAP_POINT)
|
||||
X(MODE_SHADOWCAST)
|
||||
X(MODE_SILHOUETTEDISPLAY)
|
||||
X(MODE_SILHOUETTEOCCLUDER)
|
||||
X(MODE_WIREFRAME)
|
||||
X(MODE_WIREFRAME_SOLID)
|
||||
X(PASS_REFLECTIONS)
|
||||
X(PASS_REFRACTIONS)
|
||||
X(PASS_SHADOWS)
|
||||
X(RENDER_DEBUG_MODE)
|
||||
X(RENDER_DEBUG_MODE_AO)
|
||||
X(RENDER_DEBUG_MODE_ALPHA)
|
||||
|
|
@ -140,6 +132,7 @@ X(particle_multiply)
|
|||
X(particle_overlay)
|
||||
X(particle_solid)
|
||||
X(particle_subtract)
|
||||
X(particle_wireframe)
|
||||
X(playerColor)
|
||||
X(projInvTransform)
|
||||
X(qualityLevel)
|
||||
|
|
@ -169,11 +162,18 @@ X(spaceTransform)
|
|||
X(sunColor)
|
||||
X(sunDir)
|
||||
X(terrain_base)
|
||||
X(terrain_base_reflections)
|
||||
X(terrain_base_wireframe)
|
||||
X(terrain_blend)
|
||||
X(terrain_blend_reflections)
|
||||
X(terrain_blend_wireframe)
|
||||
X(terrain_decal)
|
||||
X(terrain_decal_reflections)
|
||||
X(terrain_decal_wireframe)
|
||||
X(terrain_shadow_caster)
|
||||
X(terrain_silhouette_occluder)
|
||||
X(terrain_solid)
|
||||
X(terrain_wireframe)
|
||||
X(tex)
|
||||
X(texSize)
|
||||
X(textureTransform)
|
||||
|
|
@ -187,6 +187,7 @@ X(vertexCount)
|
|||
X(viewInvTransform)
|
||||
X(water_high)
|
||||
X(water_simple)
|
||||
X(water_simple_wireframe)
|
||||
X(water_waves)
|
||||
X(waterEffectsTex)
|
||||
X(waterTex)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -138,7 +138,8 @@ void CDecalRData::Update(CSimulation2* simulation)
|
|||
void CDecalRData::RenderDecals(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
Renderer::Backend::IVertexInputLayout* vertexInputLayout,
|
||||
const std::vector<CDecalRData*>& decals, const CShaderDefines& context, ShadowMap* shadow)
|
||||
const std::vector<CDecalRData*>& decals, const CShaderDefines& context,
|
||||
ShadowMap* shadow, const CMaterial::Pass materialPass)
|
||||
{
|
||||
PROFILE3("render terrain decals");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain decals");
|
||||
|
|
@ -156,7 +157,7 @@ void CDecalRData::RenderDecals(
|
|||
{
|
||||
CMaterial& material = decal->m_Decal->m_Decal.m_Material;
|
||||
|
||||
if (material.GetShaderEffect().empty())
|
||||
if (material.GetShaderEffect(materialPass).empty())
|
||||
{
|
||||
LOGERROR("Terrain renderer failed to load shader effect.\n");
|
||||
continue;
|
||||
|
|
@ -167,7 +168,7 @@ void CDecalRData::RenderDecals(
|
|||
|
||||
SDecalBatch batch;
|
||||
batch.decal = decal;
|
||||
batch.shaderEffect = material.GetShaderEffect();
|
||||
batch.shaderEffect = material.GetShaderEffect(materialPass);
|
||||
batch.shaderDefines = material.GetShaderDefines();
|
||||
batch.vertices = decal->m_VBDecals.Get();
|
||||
batch.indices = decal->m_VBDecalsIndices.Get();
|
||||
|
|
@ -193,8 +194,16 @@ void CDecalRData::RenderDecals(
|
|||
CShaderDefines defines = contextDecal;
|
||||
defines.SetMany(itTechBegin->shaderDefines);
|
||||
// TODO: move enabling blend to XML.
|
||||
CShaderTechniquePtr techBase = g_Renderer.GetShaderManager().LoadEffect(
|
||||
itTechBegin->shaderEffect == str_terrain_base ? str_terrain_decal : itTechBegin->shaderEffect, defines);
|
||||
CShaderTechniquePtr techBase{g_Renderer.GetShaderManager().LoadEffect([](const CStrIntern shaderEffect)
|
||||
{
|
||||
if (shaderEffect == str_terrain_base)
|
||||
return str_terrain_decal;
|
||||
if (shaderEffect == str_terrain_base_reflections)
|
||||
return str_terrain_decal_reflections;
|
||||
if (shaderEffect == str_terrain_base_wireframe)
|
||||
return str_terrain_decal_wireframe;
|
||||
return shaderEffect;
|
||||
}(itTechBegin->shaderEffect), defines)};
|
||||
if (!techBase)
|
||||
{
|
||||
LOGERROR("Terrain renderer failed to load shader effect (%s)\n",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
#ifndef INCLUDED_DECALRDATA
|
||||
#define INCLUDED_DECALRDATA
|
||||
|
||||
#include "graphics/Material.h"
|
||||
#include "graphics/RenderableObject.h"
|
||||
#include "lib/code_annotation.h"
|
||||
#include "maths/Vector2D.h"
|
||||
|
|
@ -45,7 +46,8 @@ public:
|
|||
static void RenderDecals(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
Renderer::Backend::IVertexInputLayout* vertexInputLayout,
|
||||
const std::vector<CDecalRData*>& decals, const CShaderDefines& context, ShadowMap* shadow);
|
||||
const std::vector<CDecalRData*>& decals, const CShaderDefines& context,
|
||||
ShadowMap* shadow, const CMaterial::Pass materialPass);
|
||||
|
||||
CModelDecal* GetDecal() { return m_Decal; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -64,8 +64,43 @@
|
|||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ModelRenderer implementation
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
CMaterial::Pass GetMaterialPassFromCullGroup(const int cullGroup, const ERenderMode renderMode)
|
||||
{
|
||||
switch (renderMode)
|
||||
{
|
||||
case ERenderMode::WIREFRAME:
|
||||
return CMaterial::Pass::WIREFRAME;
|
||||
case ERenderMode::EDGED_FACES:
|
||||
return CMaterial::Pass::WIREFRAME_SOLID;
|
||||
case ERenderMode::SOLID:
|
||||
break;
|
||||
}
|
||||
|
||||
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:
|
||||
return CMaterial::Pass::SHADOW_CASTER;
|
||||
case CSceneRenderer::CULL_SILHOUETTE_OCCLUDER:
|
||||
return CMaterial::Pass::SILHOUETTE_OCCLUDER;
|
||||
case CSceneRenderer::CULL_SILHOUETTE_CASTER:
|
||||
return CMaterial::Pass::SILHOUETTE_CASTER;
|
||||
case CSceneRenderer::CULL_DEFAULT:
|
||||
return CMaterial::Pass::MAIN;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CMaterial::Pass::MAIN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ModelRenderer::Init()
|
||||
{
|
||||
|
|
@ -380,7 +415,8 @@ struct SMRCompareTechBucket
|
|||
|
||||
void ShaderModelRenderer::Render(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags)
|
||||
const RenderModifierPtr& modifier, const CShaderDefines& context,
|
||||
int cullGroup, int flags, const ERenderMode renderMode)
|
||||
{
|
||||
if (m->submissions[cullGroup].empty())
|
||||
return;
|
||||
|
|
@ -388,6 +424,8 @@ void ShaderModelRenderer::Render(
|
|||
CMatrix3D worldToCam;
|
||||
g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse(worldToCam);
|
||||
|
||||
const CMaterial::Pass materialPass{GetMaterialPassFromCullGroup(cullGroup, renderMode)};
|
||||
|
||||
/*
|
||||
* Rendering approach:
|
||||
*
|
||||
|
|
@ -462,8 +500,10 @@ void ShaderModelRenderer::Render(
|
|||
for (size_t i = 0; i < m->submissions[cullGroup].size(); ++i)
|
||||
{
|
||||
CModel* model = m->submissions[cullGroup][i];
|
||||
const CShaderDefines& defines = model->GetMaterial().GetShaderDefines();
|
||||
SMRMaterialBucketKey key(model->GetMaterial().GetShaderEffect(), defines);
|
||||
const CMaterial material{model->GetMaterial()};
|
||||
const CShaderDefines& defines{material.GetShaderDefines()};
|
||||
const CStrIntern shaderEffect{material.GetShaderEffect(materialPass)};
|
||||
SMRMaterialBucketKey key(shaderEffect, defines);
|
||||
|
||||
MaterialBuckets_t::iterator it = materialBuckets.find(key);
|
||||
if (it == materialBuckets.end())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "graphics/MeshManager.h"
|
||||
#include "graphics/RenderableObject.h"
|
||||
#include "renderer/SceneRenderer.h"
|
||||
#include "lib/types.h"
|
||||
|
||||
#include <memory>
|
||||
|
|
@ -173,7 +174,8 @@ public:
|
|||
*/
|
||||
virtual void Render(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags) = 0;
|
||||
const RenderModifierPtr& modifier, const CShaderDefines& context,
|
||||
int cullGroup, int flags, const ERenderMode renderMode) = 0;
|
||||
|
||||
/**
|
||||
* CopyPositionAndNormals: Copy unanimated object-space vertices and
|
||||
|
|
@ -282,7 +284,8 @@ public:
|
|||
void EndFrame() override;
|
||||
void Render(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const RenderModifierPtr& modifier, const CShaderDefines& context, int cullGroup, int flags) override;
|
||||
const RenderModifierPtr& modifier, const CShaderDefines& context,
|
||||
int cullGroup, int flags, const ERenderMode renderMode) override;
|
||||
|
||||
private:
|
||||
struct ShaderModelRendererInternals;
|
||||
|
|
|
|||
|
|
@ -883,7 +883,8 @@ using ShaderTechniqueBatches = PooledBatchMap<std::pair<CStrIntern, CShaderDefin
|
|||
void CPatchRData::RenderBases(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
Renderer::Backend::IVertexInputLayout* vertexInputLayout,
|
||||
const std::vector<CPatchRData*>& patches, const CShaderDefines& context, ShadowMap* shadow)
|
||||
const std::vector<CPatchRData*>& patches, const CShaderDefines& context,
|
||||
ShadowMap* shadow, const CMaterial::Pass materialPass)
|
||||
{
|
||||
PROFILE3("render terrain bases");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain bases");
|
||||
|
|
@ -902,7 +903,7 @@ void CPatchRData::RenderBases(
|
|||
{
|
||||
SSplat& splat = patch->m_Splats[j];
|
||||
const CMaterial& material = splat.m_Texture->GetMaterial();
|
||||
if (material.GetShaderEffect().empty())
|
||||
if (material.GetShaderEffect(materialPass).empty())
|
||||
{
|
||||
LOGERROR("Terrain renderer failed to load shader effect.\n");
|
||||
continue;
|
||||
|
|
@ -911,7 +912,9 @@ void CPatchRData::RenderBases(
|
|||
BatchElements& batch = PooledPairGet(
|
||||
PooledMapGet(
|
||||
PooledMapGet(
|
||||
PooledMapGet(batches, std::make_pair(material.GetShaderEffect(), material.GetShaderDefines()), scopedLinearAllocator),
|
||||
PooledMapGet(
|
||||
batches, std::make_pair(material.GetShaderEffect(materialPass), material.GetShaderDefines()),
|
||||
scopedLinearAllocator),
|
||||
splat.m_Texture, scopedLinearAllocator
|
||||
),
|
||||
patch->m_VBBase->m_Owner, scopedLinearAllocator
|
||||
|
|
@ -1043,7 +1046,8 @@ struct SBlendStackItem
|
|||
void CPatchRData::RenderBlends(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
Renderer::Backend::IVertexInputLayout* vertexInputLayout,
|
||||
const std::vector<CPatchRData*>& patches, const CShaderDefines& context, ShadowMap* shadow)
|
||||
const std::vector<CPatchRData*>& patches, const CShaderDefines& context,
|
||||
ShadowMap* shadow, const CMaterial::Pass materialPass)
|
||||
{
|
||||
PROFILE3("render terrain blends");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain blends");
|
||||
|
|
@ -1130,11 +1134,19 @@ void CPatchRData::RenderBlends(
|
|||
CShaderDefines defines = contextBlend;
|
||||
defines.SetMany(bestTex->GetMaterial().GetShaderDefines());
|
||||
// TODO: move enabling blend to XML.
|
||||
const CStrIntern shaderEffect = bestTex->GetMaterial().GetShaderEffect();
|
||||
if (shaderEffect != str_terrain_base)
|
||||
const CStrIntern shaderEffect = bestTex->GetMaterial().GetShaderEffect(materialPass);
|
||||
if (shaderEffect != str_terrain_base && shaderEffect != str_terrain_base_reflections && shaderEffect != str_terrain_base_wireframe)
|
||||
ONCE(LOGWARNING("Shader effect '%s' doesn't support semi-transparent terrain rendering.", shaderEffect.c_str()));
|
||||
layer.m_ShaderTech = g_Renderer.GetShaderManager().LoadEffect(
|
||||
shaderEffect == str_terrain_base ? str_terrain_blend : shaderEffect, defines);
|
||||
layer.m_ShaderTech = g_Renderer.GetShaderManager().LoadEffect([](const CStrIntern shaderEffect)
|
||||
{
|
||||
if (shaderEffect == str_terrain_base)
|
||||
return str_terrain_blend;
|
||||
if (shaderEffect == str_terrain_base_reflections)
|
||||
return str_terrain_blend_reflections;
|
||||
if (shaderEffect == str_terrain_base_wireframe)
|
||||
return str_terrain_blend_wireframe;
|
||||
return shaderEffect;
|
||||
}(shaderEffect), defines);
|
||||
}
|
||||
batches.push_back(layer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#ifndef INCLUDED_PATCHRDATA
|
||||
#define INCLUDED_PATCHRDATA
|
||||
|
||||
#include "graphics/Material.h"
|
||||
#include "graphics/Patch.h"
|
||||
#include "graphics/RenderableObject.h"
|
||||
#include "lib/code_annotation.h"
|
||||
|
|
@ -76,11 +77,13 @@ public:
|
|||
static void RenderBases(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
Renderer::Backend::IVertexInputLayout* vertexInputLayout,
|
||||
const std::vector<CPatchRData*>& patches, const CShaderDefines& context, ShadowMap* shadow);
|
||||
const std::vector<CPatchRData*>& patches, const CShaderDefines& context,
|
||||
ShadowMap* shadow, const CMaterial::Pass materialPass);
|
||||
static void RenderBlends(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
Renderer::Backend::IVertexInputLayout* vertexInputLayout,
|
||||
const std::vector<CPatchRData*>& patches, const CShaderDefines& context, ShadowMap* shadow);
|
||||
const std::vector<CPatchRData*>& patches, const CShaderDefines& context,
|
||||
ShadowMap* shadow, const CMaterial::Pass materialPass);
|
||||
static void RenderStreams(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
Renderer::Backend::IVertexInputLayout* vertexInputLayout,
|
||||
|
|
|
|||
|
|
@ -154,18 +154,18 @@ public:
|
|||
*/
|
||||
void CallModelRenderers(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, int cullGroup, int flags)
|
||||
const CShaderDefines& context, int cullGroup, int flags, const ERenderMode renderMode)
|
||||
{
|
||||
CShaderDefines contextSkinned = context;
|
||||
if (g_RenderingOptions.GetGPUSkinning())
|
||||
contextSkinned.Add(str_USE_INSTANCING, str_1);
|
||||
Model.NormalSkinned->Render(deviceCommandContext, Model.ModShader, contextSkinned, cullGroup, flags);
|
||||
Model.NormalSkinned->Render(deviceCommandContext, Model.ModShader, contextSkinned, cullGroup, flags, renderMode);
|
||||
|
||||
if (Model.NormalUnskinned != Model.NormalSkinned)
|
||||
{
|
||||
CShaderDefines contextUnskinned = context;
|
||||
contextUnskinned.Add(str_USE_INSTANCING, str_1);
|
||||
Model.NormalUnskinned->Render(deviceCommandContext, Model.ModShader, contextUnskinned, cullGroup, flags);
|
||||
Model.NormalUnskinned->Render(deviceCommandContext, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,18 +174,18 @@ public:
|
|||
*/
|
||||
void CallTranspModelRenderers(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, int cullGroup, int flags)
|
||||
const CShaderDefines& context, int cullGroup, int flags, const ERenderMode renderMode)
|
||||
{
|
||||
CShaderDefines contextSkinned = context;
|
||||
if (g_RenderingOptions.GetGPUSkinning())
|
||||
contextSkinned.Add(str_USE_INSTANCING, str_1);
|
||||
Model.TranspSkinned->Render(deviceCommandContext, Model.ModShader, contextSkinned, cullGroup, flags);
|
||||
Model.TranspSkinned->Render(deviceCommandContext, Model.ModShader, contextSkinned, cullGroup, flags, renderMode);
|
||||
|
||||
if (Model.TranspUnskinned != Model.TranspSkinned)
|
||||
{
|
||||
CShaderDefines contextUnskinned = context;
|
||||
contextUnskinned.Add(str_USE_INSTANCING, str_1);
|
||||
Model.TranspUnskinned->Render(deviceCommandContext, Model.ModShader, contextUnskinned, cullGroup, flags);
|
||||
Model.TranspUnskinned->Render(deviceCommandContext, Model.ModShader, contextUnskinned, cullGroup, flags, renderMode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -294,18 +294,11 @@ void CSceneRenderer::SetSimulation(CSimulation2* simulation)
|
|||
}
|
||||
|
||||
void CSceneRenderer::RenderShadowMap(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context)
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
PROFILE3_GPU(deviceCommandContext, "shadow map");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render shadow map");
|
||||
|
||||
CShaderDefines shadowsContext = context;
|
||||
shadowsContext.Add(str_PASS_SHADOWS, str_1);
|
||||
|
||||
CShaderDefines contextCast = shadowsContext;
|
||||
contextCast.Add(str_MODE_SHADOWCAST, str_1);
|
||||
|
||||
m->shadow.BeginRender(deviceCommandContext);
|
||||
|
||||
const int cascadeCount = m->shadow.GetCascadeCount();
|
||||
|
|
@ -317,17 +310,18 @@ void CSceneRenderer::RenderShadowMap(
|
|||
const int cullGroup = CULL_SHADOWS_CASCADE_0 + cascade;
|
||||
{
|
||||
PROFILE("render patches");
|
||||
m->terrainRenderer.RenderPatches(deviceCommandContext, cullGroup, {});
|
||||
m->terrainRenderer.RenderPatches(
|
||||
deviceCommandContext, cullGroup, {}, CColor(0.0f, 0.0f, 0.0f, 1.0f), false);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE("render models");
|
||||
m->CallModelRenderers(deviceCommandContext, contextCast, cullGroup, ModelFlag::CAST_SHADOWS);
|
||||
m->CallModelRenderers(deviceCommandContext, {}, cullGroup, ModelFlag::CAST_SHADOWS, ERenderMode::SOLID);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE("render transparent models");
|
||||
m->CallTranspModelRenderers(deviceCommandContext, contextCast, cullGroup, ModelFlag::CAST_SHADOWS);
|
||||
m->CallTranspModelRenderers(deviceCommandContext, {}, cullGroup, ModelFlag::CAST_SHADOWS, ERenderMode::SOLID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -341,23 +335,17 @@ void CSceneRenderer::RenderPatches(
|
|||
PROFILE3("patches");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render patches");
|
||||
|
||||
// Switch on wireframe if we need it.
|
||||
CShaderDefines localContext = context;
|
||||
if (m_TerrainRenderMode == WIREFRAME)
|
||||
localContext.Add(str_MODE_WIREFRAME, str_1);
|
||||
|
||||
// Render all the patches, including blend pass.
|
||||
m->terrainRenderer.RenderTerrainShader(deviceCommandContext, localContext, cullGroup,
|
||||
g_RenderingOptions.GetShadows() ? &m->shadow : nullptr);
|
||||
m->terrainRenderer.RenderTerrainShader(deviceCommandContext, context, cullGroup,
|
||||
g_RenderingOptions.GetShadows() ? &m->shadow : nullptr, m_TerrainRenderMode == WIREFRAME);
|
||||
|
||||
if (m_TerrainRenderMode == EDGED_FACES)
|
||||
{
|
||||
localContext.Add(str_MODE_WIREFRAME, str_1);
|
||||
// Edged faces: need to make a second pass over the data.
|
||||
|
||||
// Render tiles edges.
|
||||
m->terrainRenderer.RenderPatches(
|
||||
deviceCommandContext, cullGroup, localContext, CColor(0.5f, 0.5f, 1.0f, 1.0f));
|
||||
deviceCommandContext, cullGroup, context, CColor(0.5f, 0.5f, 1.0f, 1.0f), true);
|
||||
|
||||
// Render outline of each patch.
|
||||
m->terrainRenderer.RenderOutlines(deviceCommandContext, cullGroup);
|
||||
|
|
@ -373,18 +361,13 @@ void CSceneRenderer::RenderModels(
|
|||
|
||||
int flags = 0;
|
||||
|
||||
CShaderDefines localContext = context;
|
||||
const ERenderMode modelRenderMode{
|
||||
m_ModelRenderMode == WIREFRAME ? WIREFRAME : SOLID};
|
||||
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
localContext.Add(str_MODE_WIREFRAME, str_1);
|
||||
|
||||
m->CallModelRenderers(deviceCommandContext, localContext, cullGroup, flags);
|
||||
m->CallModelRenderers(deviceCommandContext, context, cullGroup, flags, modelRenderMode);
|
||||
|
||||
if (m_ModelRenderMode == EDGED_FACES)
|
||||
{
|
||||
localContext.Add(str_MODE_WIREFRAME_SOLID, str_1);
|
||||
m->CallModelRenderers(deviceCommandContext, localContext, cullGroup, flags);
|
||||
}
|
||||
m->CallModelRenderers(deviceCommandContext, {}, cullGroup, flags, EDGED_FACES);
|
||||
}
|
||||
|
||||
void CSceneRenderer::RenderTransparentModels(
|
||||
|
|
@ -402,25 +385,17 @@ void CSceneRenderer::RenderTransparentModels(
|
|||
CShaderDefines contextBlend = context;
|
||||
contextBlend.Add(str_ALPHABLEND_PASS_BLEND, str_1);
|
||||
|
||||
if (m_ModelRenderMode == WIREFRAME)
|
||||
{
|
||||
contextOpaque.Add(str_MODE_WIREFRAME, str_1);
|
||||
contextBlend.Add(str_MODE_WIREFRAME, str_1);
|
||||
}
|
||||
const ERenderMode modelRenderMode{
|
||||
m_ModelRenderMode == WIREFRAME ? WIREFRAME : SOLID};
|
||||
|
||||
if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_OPAQUE)
|
||||
m->CallTranspModelRenderers(deviceCommandContext, contextOpaque, cullGroup, flags);
|
||||
m->CallTranspModelRenderers(deviceCommandContext, contextOpaque, cullGroup, flags, modelRenderMode);
|
||||
|
||||
if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_BLEND)
|
||||
m->CallTranspModelRenderers(deviceCommandContext, contextBlend, cullGroup, flags);
|
||||
m->CallTranspModelRenderers(deviceCommandContext, contextBlend, cullGroup, flags, modelRenderMode);
|
||||
|
||||
if (m_ModelRenderMode == EDGED_FACES)
|
||||
{
|
||||
CShaderDefines contextWireframe = contextOpaque;
|
||||
contextWireframe.Add(str_MODE_WIREFRAME, str_1);
|
||||
|
||||
m->CallTranspModelRenderers(deviceCommandContext, contextWireframe, cullGroup, flags);
|
||||
}
|
||||
m->CallTranspModelRenderers(deviceCommandContext, {}, cullGroup, flags, EDGED_FACES);
|
||||
}
|
||||
|
||||
// SetObliqueFrustumClipping: change the near plane to the given clip plane (in world space)
|
||||
|
|
@ -602,13 +577,10 @@ void CSceneRenderer::RenderReflections(
|
|||
scissorRect.height = screenScissor.y2 - screenScissor.y1;
|
||||
deviceCommandContext->SetScissors(1, &scissorRect);
|
||||
|
||||
CShaderDefines reflectionsContext = context;
|
||||
reflectionsContext.Add(str_PASS_REFLECTIONS, str_1);
|
||||
|
||||
// Render terrain and models
|
||||
RenderPatches(deviceCommandContext, reflectionsContext, CULL_REFLECTIONS);
|
||||
RenderModels(deviceCommandContext, reflectionsContext, CULL_REFLECTIONS);
|
||||
RenderTransparentModels(deviceCommandContext, reflectionsContext, CULL_REFLECTIONS, TRANSPARENT);
|
||||
RenderPatches(deviceCommandContext, context, CULL_REFLECTIONS);
|
||||
RenderModels(deviceCommandContext, context, CULL_REFLECTIONS);
|
||||
RenderTransparentModels(deviceCommandContext, context, CULL_REFLECTIONS, TRANSPARENT);
|
||||
|
||||
// Particles are always oriented to face the camera in the vertex shader,
|
||||
// so they don't need the inverted cull face.
|
||||
|
|
@ -713,18 +685,11 @@ void CSceneRenderer::RenderRefractions(
|
|||
}
|
||||
|
||||
void CSceneRenderer::RenderSilhouettes(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context)
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
PROFILE3("silhouettes");
|
||||
GPU_SCOPED_LABEL(deviceCommandContext, "Render silhouettes");
|
||||
|
||||
CShaderDefines contextOccluder = context;
|
||||
contextOccluder.Add(str_MODE_SILHOUETTEOCCLUDER, str_1);
|
||||
|
||||
CShaderDefines contextDisplay = context;
|
||||
contextDisplay.Add(str_MODE_SILHOUETTEDISPLAY, str_1);
|
||||
|
||||
// Render silhouettes of units hidden behind terrain or occluders.
|
||||
// To avoid breaking the standard rendering of alpha-blended objects, this
|
||||
// has to be done in a separate pass.
|
||||
|
|
@ -739,29 +704,30 @@ void CSceneRenderer::RenderSilhouettes(
|
|||
|
||||
{
|
||||
PROFILE("render patches");
|
||||
m->terrainRenderer.RenderPatches(deviceCommandContext, CULL_SILHOUETTE_OCCLUDER, {});
|
||||
m->terrainRenderer.RenderPatches(
|
||||
deviceCommandContext, CULL_SILHOUETTE_OCCLUDER, {}, CColor(0.0f, 0.0f, 0.0f, 1.0f), false);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE("render model occluders");
|
||||
m->CallModelRenderers(deviceCommandContext, contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0);
|
||||
m->CallModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_OCCLUDER, 0, ERenderMode::SOLID);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE("render transparent occluders");
|
||||
m->CallTranspModelRenderers(deviceCommandContext, contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0);
|
||||
m->CallTranspModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_OCCLUDER, 0, ERenderMode::SOLID);
|
||||
}
|
||||
|
||||
// Since we can't sort, we'll use the stencil buffer to ensure we only draw
|
||||
// a pixel once (using the color of whatever model happens to be drawn first).
|
||||
{
|
||||
PROFILE("render model casters");
|
||||
m->CallModelRenderers(deviceCommandContext, contextDisplay, CULL_SILHOUETTE_CASTER, 0);
|
||||
m->CallModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_CASTER, 0, ERenderMode::SOLID);
|
||||
}
|
||||
|
||||
{
|
||||
PROFILE("render transparent casters");
|
||||
m->CallTranspModelRenderers(deviceCommandContext, contextDisplay, CULL_SILHOUETTE_CASTER, 0);
|
||||
m->CallTranspModelRenderers(deviceCommandContext, {}, CULL_SILHOUETTE_CASTER, 0, ERenderMode::SOLID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -832,7 +798,7 @@ void CSceneRenderer::PrepareSubmissions(
|
|||
|
||||
if (g_RenderingOptions.GetShadows())
|
||||
{
|
||||
RenderShadowMap(deviceCommandContext, context);
|
||||
RenderShadowMap(deviceCommandContext);
|
||||
}
|
||||
|
||||
if (m->waterManager.m_RenderWater)
|
||||
|
|
@ -1164,7 +1130,7 @@ void CSceneRenderer::RenderSceneOverlays(
|
|||
if (!g_RenderingOptions.GetCutsceneMode())
|
||||
{
|
||||
if (g_RenderingOptions.GetSilhouettes())
|
||||
RenderSilhouettes(deviceCommandContext, m->globalContext);
|
||||
RenderSilhouettes(deviceCommandContext);
|
||||
|
||||
m->silhouetteRenderer.RenderDebugOverlays(deviceCommandContext);
|
||||
|
||||
|
|
|
|||
|
|
@ -230,8 +230,7 @@ protected:
|
|||
const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode);
|
||||
|
||||
void RenderSilhouettes(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context);
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
|
||||
|
||||
void RenderParticles(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
|
|
@ -239,8 +238,7 @@ protected:
|
|||
|
||||
// shadow rendering stuff
|
||||
void RenderShadowMap(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context);
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
|
||||
|
||||
// render water reflection and refraction textures
|
||||
void RenderReflections(
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* TerrainRenderer keeps track of which phase it is in, to detect
|
||||
* when Submit, PrepareForRendering etc. are called in the wrong order.
|
||||
|
|
@ -75,6 +78,17 @@ enum Phase
|
|||
Phase_Render
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class.
|
||||
|
|
@ -93,7 +107,7 @@ struct TerrainRendererInternals
|
|||
/// Fancy water shader
|
||||
CShaderTechniquePtr fancyWaterTech;
|
||||
|
||||
CShaderTechniquePtr shadowCasterTech, silhouettteOccluderTech;
|
||||
CShaderTechniquePtr shadowCasterTech, silhouettteOccluderTech, wireframeTech;
|
||||
|
||||
CShaderTechniquePtr shaderTechniqueSolid, shaderTechniqueSolidDepthTest;
|
||||
|
||||
|
|
@ -156,6 +170,7 @@ void TerrainRenderer::Initialize()
|
|||
CShaderManager& shaderManager{g_Renderer.GetShaderManager()};
|
||||
m->shadowCasterTech = shaderManager.LoadEffect(str_terrain_shadow_caster);
|
||||
m->silhouettteOccluderTech = shaderManager.LoadEffect(str_terrain_silhouette_occluder);
|
||||
m->wireframeTech = shaderManager.LoadEffect(str_terrain_wireframe);
|
||||
}
|
||||
|
||||
void TerrainRenderer::SetSimulation(CSimulation2* simulation)
|
||||
|
|
@ -316,7 +331,8 @@ void TerrainRenderer::PrepareShader(
|
|||
|
||||
void TerrainRenderer::RenderTerrainShader(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, int cullGroup, ShadowMap* shadow)
|
||||
const CShaderDefines& context, int cullGroup, ShadowMap* shadow,
|
||||
const bool wireframe)
|
||||
{
|
||||
ENSURE(m->phase == Phase_Render);
|
||||
|
||||
|
|
@ -353,22 +369,25 @@ void TerrainRenderer::RenderTerrainShader(
|
|||
|
||||
deviceCommandContext->EndPass();
|
||||
|
||||
const CMaterial::Pass materialPass{GetMaterialPassFromCullGroup(cullGroup, wireframe)};
|
||||
|
||||
CPatchRData::RenderBases(
|
||||
deviceCommandContext, m->baseVertexInputLayout, visiblePatches, context, shadow);
|
||||
deviceCommandContext, m->baseVertexInputLayout, visiblePatches, context, shadow, materialPass);
|
||||
|
||||
// render blend passes for each patch
|
||||
CPatchRData::RenderBlends(
|
||||
deviceCommandContext, m->blendVertexInputLayout, visiblePatches, context, shadow);
|
||||
deviceCommandContext, m->blendVertexInputLayout, visiblePatches, context, shadow, materialPass);
|
||||
|
||||
CDecalRData::RenderDecals(
|
||||
deviceCommandContext, m->decalsVertexInputLayout, visibleDecals, context, shadow);
|
||||
deviceCommandContext, m->decalsVertexInputLayout, visibleDecals, context, shadow, materialPass);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Render un-textured patches as polygons
|
||||
void TerrainRenderer::RenderPatches(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
int cullGroup, const CShaderDefines& defines, const CColor& color)
|
||||
int cullGroup, const CShaderDefines& defines, const CColor& color,
|
||||
const bool wireframe)
|
||||
{
|
||||
ENSURE(m->phase == Phase_Render);
|
||||
|
||||
|
|
@ -379,22 +398,29 @@ void TerrainRenderer::RenderPatches(
|
|||
GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain patches");
|
||||
|
||||
CShaderTechniquePtr solidTech;
|
||||
switch (cullGroup)
|
||||
if (wireframe)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
deviceCommandContext->SetGraphicsPipelineState(
|
||||
solidTech->GetGraphicsPipelineState());
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -104,7 +104,8 @@ public:
|
|||
*/
|
||||
void RenderTerrainShader(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderDefines& context, int cullGroup, ShadowMap* shadow);
|
||||
const CShaderDefines& context, int cullGroup, ShadowMap* shadow,
|
||||
const bool wireframe);
|
||||
|
||||
/**
|
||||
* RenderPatches: Render all patches un-textured as polygons.
|
||||
|
|
@ -118,7 +119,7 @@ public:
|
|||
void RenderPatches(
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||
int cullGroup, const CShaderDefines& defines,
|
||||
const CColor& color = CColor(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
const CColor& color, const bool wireframe);
|
||||
|
||||
/**
|
||||
* RenderOutlines: Render the outline of patches as lines.
|
||||
|
|
|
|||
Loading…
Reference in a new issue