- removed the remaining dependencies of the shadowmap code on game data.

Everything is handled with callbacks now.
This commit is contained in:
Christoph Oelckers 2020-04-26 19:58:17 +02:00
parent ba0b42465d
commit c30165db0d
5 changed files with 71 additions and 76 deletions

View file

@ -20,8 +20,7 @@
//--------------------------------------------------------------------------
//
#include "r_state.h"
#include "g_levellocals.h"
#include <algorithm>
#include "hw_aabbtree.h"
namespace hwrenderer
@ -82,7 +81,7 @@ double LevelAABBTree::RayTest(const DVector3 &ray_start, const DVector3 &ray_end
else if (nodes[node_index].line_index != -1) // isLeaf(node_index)
{
// We reached a leaf node. Do a ray/line intersection test to see if we hit the line.
hit_fraction = MIN(IntersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), hit_fraction);
hit_fraction = std::min(IntersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), hit_fraction);
stack_pos--;
}
else if (stack_pos == 32)

View file

@ -28,6 +28,7 @@
#include "actorinlines.h"
#include "a_dynlight.h"
#include "hw_dynlightdata.h"
#include"hw_cvars.h"
#include "hwrenderer/scene/hw_drawstructs.h"
// If we want to share the array to avoid constant allocations it needs to be thread local unless it'd be littered with expensive synchronization.
@ -105,10 +106,15 @@ void AddLightToList(FDynLightData &dld, int group, FDynamicLight * light, bool f
i = 1;
}
float shadowIndex = light->mShadowmapIndex + 1.0f;
float shadowIndex;
if (gl_light_shadowmap)
{
shadowIndex = light->mShadowmapIndex + 1.0f;
// Store attenuate flag in the sign bit of the float.
if (light->IsAttenuated() || forceAttenuate) shadowIndex = -shadowIndex;
// Store attenuate flag in the sign bit of the float.
if (light->IsAttenuated() || forceAttenuate) shadowIndex = -shadowIndex;
}
else shadowIndex = 1025.f;
float lightType = 0.0f;
float spotInnerAngle = 0.0f;

View file

@ -25,10 +25,6 @@
#include "hw_dynlightdata.h"
#include "hwrenderer/data/buffers.h"
#include "hwrenderer/data/shaderuniforms.h"
#include "stats.h"
#include "g_levellocals.h"
#include "v_video.h"
#include "a_dynlight.h"
#include "hwrenderer/postprocessing/hw_postprocess.h"
/*
@ -63,6 +59,8 @@ cycle_t IShadowMap::UpdateCycles;
int IShadowMap::LightsProcessed;
int IShadowMap::LightsShadowmapped;
CVAR(Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
ADD_STAT(shadowmap)
{
FString out;
@ -85,68 +83,14 @@ CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
}
}
CUSTOM_CVAR (Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (!self) for (auto Level : AllLevels())
{
auto light = Level->lights;
while (light)
{
light->mShadowmapIndex = 1024;
light = light->next;
}
}
}
bool IShadowMap::ShadowTest(const DVector3 &lpos, const DVector3 &pos)
{
if (mAABBTree)
if (mAABBTree && gl_light_shadowmap)
return mAABBTree->RayTest(lpos, pos) >= 1.0f;
else
return true;
}
bool IShadowMap::IsEnabled() const
{
return gl_light_shadowmap && (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER);
}
void IShadowMap::CollectLights()
{
if (mLights.Size() != 1024 * 4) mLights.Resize(1024 * 4);
int lightindex = 0;
auto Level = &level;
// Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred.
for (auto light = Level->lights; light; light = light->next)
{
LightsProcessed++;
if (light->shadowmapped && light->IsActive() && lightindex < 1024 * 4)
{
LightsShadowmapped++;
light->mShadowmapIndex = lightindex >> 2;
mLights[lightindex] = (float)light->X();
mLights[lightindex+1] = (float)light->Y();
mLights[lightindex+2] = (float)light->Z();
mLights[lightindex+3] = light->GetRadius();
lightindex += 4;
}
else
{
light->mShadowmapIndex = 1024;
}
}
for (; lightindex < 1024 * 4; lightindex++)
{
mLights[lightindex] = 0;
}
}
bool IShadowMap::PerformUpdate()
{
UpdateCycles.Reset();
@ -154,7 +98,7 @@ bool IShadowMap::PerformUpdate()
LightsProcessed = 0;
LightsShadowmapped = 0;
if (IsEnabled())
if (gl_light_shadowmap && (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER) && CollectLights != nullptr)
{
UpdateCycles.Clock();
UploadAABBTree();
@ -166,6 +110,7 @@ bool IShadowMap::PerformUpdate()
void IShadowMap::UploadLights()
{
mLights.Resize(1024 * 4);
CollectLights();
if (mLightList == nullptr)
@ -207,3 +152,4 @@ IShadowMap::~IShadowMap()
{
Reset();
}

View file

@ -5,10 +5,7 @@
#include "stats.h"
#include <memory>
struct FDynamicLight;
struct level_info_t;
class IDataBuffer;
struct FLevelLocals;
class IShadowMap
{
@ -21,9 +18,6 @@ public:
// Test if a world position is in shadow relative to the specified light and returns false if it is
bool ShadowTest(const DVector3 &lpos, const DVector3 &pos);
// Returns true if gl_light_shadowmap is enabled and supported by the hardware
bool IsEnabled() const;
static cycle_t UpdateCycles;
static int LightsProcessed;
static int LightsShadowmapped;
@ -46,13 +40,23 @@ public:
mNewTree = true;
}
protected:
void CollectLights();
void SetCollectLights(std::function<void()> func)
{
CollectLights = std::move(func);
}
void SetLight(int index, float x, float y, float z, float r)
{
index *= 4;
mLights[index] = x;
mLights[index + 1] = y;
mLights[index + 2] = z;
mLights[index + 3] = r;
}
protected:
// Upload the AABB-tree to the GPU
void UploadAABBTree();
// Upload light list to the GPU
void UploadLights();
// Working buffer for creating the list of lights. Stored here to avoid allocating memory each frame
@ -74,4 +78,6 @@ public:
IDataBuffer *mNodesBuffer = nullptr;
IDataBuffer *mLinesBuffer = nullptr;
std::function<void()> CollectLights = nullptr;
};

View file

@ -59,6 +59,41 @@ void CleanSWDrawer()
swdrawer = nullptr;
}
#include "g_levellocals.h"
#include "a_dynlight.h"
void CollectLights(FLevelLocals* Level)
{
IShadowMap* sm = &screen->mShadowMap;
int lightindex = 0;
// Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred.
for (auto light = Level->lights; light; light = light->next)
{
IShadowMap::LightsProcessed++;
if (light->shadowmapped && light->IsActive() && lightindex < 1024 * 4)
{
IShadowMap::LightsShadowmapped++;
light->mShadowmapIndex = lightindex;
sm->SetLight(lightindex, (float)light->X(), (float)light->Y(), (float)light->Z(), light->GetRadius());
lightindex++;
}
else
{
light->mShadowmapIndex = 1024;
}
}
for (; lightindex < 1024; lightindex++)
{
sm->SetLight(lightindex, 0, 0, 0, 0);
}
}
//-----------------------------------------------------------------------------
//
// Renders one viewpoint in a scene
@ -75,6 +110,9 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou
{
screen->SetAABBTree(camera->Level->aabbTree);
screen->UpdateShadowMap();
screen->mShadowMap.SetCollectLights([=] {
CollectLights(camera->Level);
});
}
// Update the attenuation flag of all light defaults for each viewpoint.