WIP multiple probes support

This commit is contained in:
RaveYard 2025-02-20 20:10:39 +01:00 committed by Magnus Norddahl
commit 2dd7ad8eb2
11 changed files with 153 additions and 11 deletions

View file

@ -12,3 +12,20 @@ struct LightProbeTarget
{
int index = 0; // parameter for renderstate.SetLightProbe
};
class LightProbeIncrementalBuilder
{
int lastIndex = 0;
int collected;
TArray<uint16_t> irradianceMaps;
TArray<uint16_t> prefilterMaps;
public:
void Step(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArray<uint16_t>&, TArray<uint16_t>&)> renderScene, std::function<void(TArray<uint16_t>&&, TArray<uint16_t>&&)> uploadEnv);
void Full(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArray<uint16_t>&, TArray<uint16_t>&)> renderScene, std::function<void(TArray<uint16_t>&&, TArray<uint16_t>&&)> uploadEnv);
auto GetStep() const { return lastIndex; }
};

View file

@ -221,7 +221,8 @@ public:
// Get the array index for the material in the textures array accessible from shaders
virtual int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) { return -1; }
virtual void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc) {}
virtual void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc, TArray<uint16_t>& irradianceMap, TArray<uint16_t>& prefilterMap) {}
virtual void UploadEnvironmentMaps(int cubemapCount, TArray<uint16_t>&& irradianceMaps, TArray<uint16_t>&& prefilterMaps) {}
// Screen wiping
virtual FTexture *WipeStartScreen();

View file

@ -420,7 +420,7 @@ void VkTextureManager::CreatePrefiltermap(int size, int count, TArray<uint16_t>&
.Execute(cmdbuffer);
int offset = 0;
for (int i = 0; i < 6; ++i)
for (int i = 0; i < count; ++i)
{
for (int level = 0; level < miplevels; level++)
{

View file

@ -321,13 +321,18 @@ void VulkanRenderDevice::RenderTextureView(FCanvasTexture* tex, std::function<vo
tex->SetUpdated(true);
}
void VulkanRenderDevice::RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc)
void VulkanRenderDevice::RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc, TArray<uint16_t>& irradianceMap, TArray<uint16_t>& prefilterMap)
{
mLightprober->RenderEnvironmentMap(std::move(renderFunc));
TArray<uint16_t> irradianceMap = mLightprober->GenerateIrradianceMap();
TArray<uint16_t> prefilterMap = mLightprober->GeneratePrefilterMap();
mTextureManager->CreateIrradiancemap(32, 6, std::move(irradianceMap));
mTextureManager->CreatePrefiltermap(128, 6, std::move(prefilterMap));
irradianceMap = mLightprober->GenerateIrradianceMap();
prefilterMap = mLightprober->GeneratePrefilterMap();
}
void VulkanRenderDevice::UploadEnvironmentMaps(int cubemapCount, TArray<uint16_t>&& irradianceMaps, TArray<uint16_t>&& prefilterMaps)
{
mTextureManager->CreateIrradiancemap(32, 6 * cubemapCount, std::move(irradianceMaps));
mTextureManager->CreatePrefiltermap(128, 6 * cubemapCount, std::move(prefilterMaps));
}
void VulkanRenderDevice::PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D)

View file

@ -104,7 +104,8 @@ public:
private:
void RenderTextureView(FCanvasTexture* tex, std::function<void(IntRect &)> renderFunc) override;
void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc) override;
void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc, TArray<uint16_t>& irradianceMap, TArray<uint16_t>& prefilterMap) override;
void UploadEnvironmentMaps(int cubemapCount, TArray<uint16_t>&& irradianceMaps, TArray<uint16_t>&& prefilterMaps) override;
void PrintStartupLog();
void CopyScreenToBuffer(int w, int h, uint8_t *data) override;

View file

@ -881,6 +881,9 @@ xx(light_dontlightactors)
xx(light_dontlightmap)
xx(light_shadowminquality)
// Light probe
xx(LightProbe)
xx(skew_bottom_type)
xx(skew_middle_type)
xx(skew_top_type)

View file

@ -379,6 +379,7 @@ void FLevelLocals::ClearLevelData(bool fullgc)
if (levelMesh) delete levelMesh;
aabbTree = nullptr;
levelMesh = nullptr;
lightProbes.Clear();
if (screen)
screen->SetLevelMesh(nullptr);
if (screen && screen->mShadowMap)

View file

@ -333,6 +333,7 @@ static void CheckTimer(FRenderState &state, uint64_t ShaderStartTime)
state.firstFrame = screen->FrameTime - 1;
}
LightProbeIncrementalBuilder lightProbeBuilder;
sector_t* RenderView(player_t* player)
{
@ -403,16 +404,56 @@ sector_t* RenderView(player_t* player)
if (gl_lightprobe)
{
// Render the light probes if not found in a lump
// To do: we need light probe actors
AActor* lightprobe = player->camera;
AActor* lightprobe = level.GetThinkerIterator<AActor>(NAME_LightProbe, STAT_DEFAULT).Next();
if (lightprobe)
{
/*TArray<uint16_t> irradianceMap;
TArray<uint16_t> prefilteredMap;
screen->RenderEnvironmentMap([=](IntRect& bounds, int side)
{
FRenderViewpoint probevp;
RenderViewpoint(probevp, lightprobe, &bounds, 90.0, 1.0f, 1.0f, false, false, side);
});
}, irradianceMap, prefilteredMap);
screen->UploadEnvironmentMaps(1, std::move(irradianceMap), std::move(prefilteredMap));*/
auto renderEnvMap = [&](const LightProbe& probe, TArray<uint16_t>& irradianceMap, TArray<uint16_t>& prefilteredMap)
{
auto oldPos = lightprobe->Pos();
lightprobe->SetOrigin(DVector3(probe.position), false); // crime against nature
lightprobe->ClearInterpolation();
r_NoInterpolate = true;
// Printf("%p | %f %f %f\n", &probe, probe.position.X, probe.position.Y, probe.position.Z);
screen->RenderEnvironmentMap([&](IntRect& bounds, int side)
{
FRenderViewpoint probevp;
RenderViewpoint(probevp, lightprobe, &bounds, 90.0, 1.0f, 1.0f, false, false, side);
}, irradianceMap, prefilteredMap);
r_NoInterpolate = false;
};
lightProbeBuilder.Step(
level.lightProbes,
renderEnvMap,
[&](TArray<uint16_t>&& irradianceMaps, TArray<uint16_t>&& prefilteredMaps) {
screen->UploadEnvironmentMaps(level.lightProbes.size(), std::move(irradianceMaps), std::move(prefilteredMaps));
}
);
}
else
{
Printf("Warning: spawning LightProbe\n");
Spawn(&level, NAME_LightProbe);
}
}
@ -438,3 +479,60 @@ sector_t* RenderView(player_t* player)
return retsec;
}
void LightProbeIncrementalBuilder::Step(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArray<uint16_t>&, TArray<uint16_t>&)> renderScene, std::function<void(TArray<uint16_t>&&, TArray<uint16_t>&&)> uploadEnv)
{
if (lastIndex >= probes.size())
{
lastIndex = 0;
collected = 0;
if (!probes.size())
{
return;
}
}
TArray<uint16_t> irradianceMap;
TArray<uint16_t> prefilterMap;
renderScene(probes[lastIndex++], irradianceMap, prefilterMap);
++collected;
this->irradianceMaps.Append(irradianceMap);
this->prefilterMaps.Append(prefilterMap);
if (lastIndex >= probes.size())
{
if (collected == probes.size())
{
uploadEnv(std::move(this->irradianceMaps), std::move(this->prefilterMaps));
}
this->irradianceMaps.Clear();
this->prefilterMaps.Clear();
}
}
void LightProbeIncrementalBuilder::Full(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArray<uint16_t>&, TArray<uint16_t>&)> renderScene, std::function<void(TArray<uint16_t>&&, TArray<uint16_t>&&)> uploadEnv)
{
if (lastIndex >= probes.size())
{
lastIndex = 0;
if (!probes.size())
{
return;
}
}
while (lastIndex < probes.size())
{
Step(probes, renderScene, uploadEnv);
}
}
ADD_STAT(lightprobes)
{
FString out;
out.Format("Rendering probe: %d / %d", lightProbeBuilder.GetStep(), level.lightProbes.Size());
return out;
}

View file

@ -147,7 +147,7 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight)
vec3 kS = F;
vec3 kD = 1.0 - kS;
const float environmentScaleFactor = 0.1;
const float environmentScaleFactor = 1.0;
vec3 irradiance = texture(IrradianceMap, vec4(N, uLightProbeIndex)).rgb * environmentScaleFactor;
vec3 diffuse = irradiance * albedo;

View file

@ -97,6 +97,7 @@ version "4.12"
#include "zscript/actors/shared/dynlights.zs"
#include "zscript/actors/shared/corona.zs"
#include "zscript/actors/shared/fogball.zs"
#include "zscript/actors/shared/lightprobe.zs"
#include "zscript/actors/doom/doomplayer.zs"
#include "zscript/actors/doom/possessed.zs"

View file

@ -0,0 +1,15 @@
/*
Light probe actor.
*/
class LightProbe : Actor
{
Default
{
+NOINTERACTION
+NOBLOCKMAP
+NOGRAVITY
Height 2;
Radius 1;
}
}