Render environment probe at player position
This commit is contained in:
parent
c4c249cd7c
commit
3f01630b8a
10 changed files with 131 additions and 44 deletions
|
|
@ -221,6 +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) {}
|
||||
|
||||
// Screen wiping
|
||||
virtual FTexture *WipeStartScreen();
|
||||
virtual FTexture *WipeEndScreen();
|
||||
|
|
|
|||
|
|
@ -212,10 +212,10 @@ void VkTextureManager::CreatePrefiltermap()
|
|||
int size = 1 << MAX_REFLECTION_LOD;
|
||||
for (int arrayIndex = 0; arrayIndex < 6; arrayIndex++)
|
||||
{
|
||||
for (int level = 0; level < MAX_REFLECTION_LOD; level++)
|
||||
for (int level = 0; level <= MAX_REFLECTION_LOD; level++)
|
||||
{
|
||||
int mipsize = size >> level;
|
||||
for (int i = 0; i < mipsize; i++)
|
||||
for (int i = 0; i < mipsize * mipsize; i++)
|
||||
{
|
||||
data.Push(0);
|
||||
data.Push(0);
|
||||
|
|
@ -256,10 +256,10 @@ void VkTextureManager::CreateIrradiancemap(int size, int count, TArray<uint16_t>
|
|||
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
if (count > 0 && newPixelData.Size() >= (size_t)w * h * count * 3)
|
||||
{
|
||||
assert(newPixelData.Size() == (size_t)w * h * count * 3);
|
||||
assert(newPixelData.Size() == (size_t)w * h * count * 3);
|
||||
|
||||
if (count > 0 && newPixelData.Size() == (size_t)w * h * count * 3)
|
||||
{
|
||||
int totalSize = w * h * count * pixelsize;
|
||||
|
||||
auto stagingBuffer = BufferBuilder()
|
||||
|
|
@ -333,28 +333,27 @@ void VkTextureManager::CreatePrefiltermap(int size, int count, TArray<uint16_t>&
|
|||
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
if (count > 0 && newPixelData.Size() >= (size_t)w * h * count * 3)
|
||||
int totalSize = 0;
|
||||
for (int level = 0; level < miplevels; level++)
|
||||
{
|
||||
assert(newPixelData.Size() == (size_t)w * h * count * 3);
|
||||
|
||||
int totalSize = 0;
|
||||
for (int level = 0; level < miplevels; level++)
|
||||
{
|
||||
int mipwidth = std::max(w >> level, 1);
|
||||
int mipheight = std::max(h >> level, 1);
|
||||
totalSize += mipwidth * mipheight * count * pixelsize;
|
||||
}
|
||||
int mipwidth = std::max(w >> level, 1);
|
||||
int mipheight = std::max(h >> level, 1);
|
||||
totalSize += mipwidth * mipheight * count;
|
||||
}
|
||||
assert(newPixelData.Size() == (size_t)totalSize * 3);
|
||||
|
||||
if (count > 0 && newPixelData.Size() == (size_t)totalSize * 3)
|
||||
{
|
||||
auto stagingBuffer = BufferBuilder()
|
||||
.Size(totalSize)
|
||||
.Size(totalSize * pixelsize)
|
||||
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
|
||||
.DebugName("VkTextureManager.PrefiltermapStagingBuffer")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
uint16_t one = 0x3c00; // half-float 1.0
|
||||
const uint16_t* src = newPixelData.Data();
|
||||
uint16_t* data = (uint16_t*)stagingBuffer->Map(0, totalSize);
|
||||
for (int i = w * h * count; i > 0; i--)
|
||||
uint16_t* data = (uint16_t*)stagingBuffer->Map(0, totalSize * pixelsize);
|
||||
for (int i = 0; i < totalSize; i++)
|
||||
{
|
||||
*(data++) = *(src++);
|
||||
*(data++) = *(src++);
|
||||
|
|
@ -370,18 +369,19 @@ void VkTextureManager::CreatePrefiltermap(int size, int count, TArray<uint16_t>&
|
|||
int offset = 0;
|
||||
for (int level = 0; level < miplevels; level++)
|
||||
{
|
||||
int mipwidth = std::max(w >> level, 1);
|
||||
int mipheight = std::max(h >> level, 1);
|
||||
|
||||
VkBufferImageCopy region = {};
|
||||
region.bufferOffset = offset;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.layerCount = count;
|
||||
region.imageSubresource.mipLevel = level;
|
||||
region.imageExtent.depth = 1;
|
||||
region.imageExtent.width = w;
|
||||
region.imageExtent.height = h;
|
||||
region.imageExtent.width = mipwidth;
|
||||
region.imageExtent.height = mipheight;
|
||||
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, Prefiltermap.Image.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
int mipwidth = std::max(w >> level, 1);
|
||||
int mipheight = std::max(h >> level, 1);
|
||||
offset += mipwidth * mipheight * count * pixelsize;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ VkLightprober::VkLightprober(VulkanRenderDevice* fb) : fb(fb)
|
|||
{
|
||||
CreateIrradianceMap();
|
||||
CreatePrefilterMap();
|
||||
CreateEnvironmentMap();
|
||||
}
|
||||
|
||||
VkLightprober::~VkLightprober()
|
||||
|
|
@ -134,6 +135,7 @@ void VkLightprober::CreateEnvironmentMap()
|
|||
{
|
||||
environmentMap.renderTargets[i].View = ImageViewBuilder()
|
||||
.Image(environmentMap.cubeimage.get(), VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_ASPECT_COLOR_BIT, 0, i, 1, 1)
|
||||
.DebugName("VkLightprober.environmentMap.renderTargets[].View")
|
||||
.Create(fb->GetDevice());
|
||||
}
|
||||
}
|
||||
|
|
@ -149,7 +151,9 @@ void VkLightprober::RenderEnvironmentMap(std::function<void(IntRect&, int)> rend
|
|||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
0, 1, 0, 6)
|
||||
.Execute(
|
||||
fb->GetCommands()->GetDrawCommands(),
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
|
|
@ -192,7 +196,9 @@ void VkLightprober::RenderEnvironmentMap(std::function<void(IntRect&, int)> rend
|
|||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT)
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
0, 1, 0, 6)
|
||||
.Execute(
|
||||
fb->GetCommands()->GetDrawCommands(),
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
|
|
@ -250,7 +256,7 @@ void VkLightprober::CreateIrradianceMap()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> VkLightprober::GenerateIrradianceMap()
|
||||
TArray<uint16_t> VkLightprober::GenerateIrradianceMap()
|
||||
{
|
||||
auto staging = BufferBuilder()
|
||||
.Size(32 * 32 * 8 * 6)
|
||||
|
|
@ -304,7 +310,7 @@ std::vector<uint8_t> VkLightprober::GenerateIrradianceMap()
|
|||
push.up = up[i];
|
||||
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_COMPUTE, irradianceMap.pipelineLayout.get(), 0, irradianceMap.descriptorSets[i].get());
|
||||
cmdbuffer->pushConstants(irradianceMap.pipelineLayout.get(), VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, sizeof(PushConstants), &push);
|
||||
cmdbuffer->pushConstants(irradianceMap.pipelineLayout.get(), VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(IrradianceMapPushConstants), &push);
|
||||
cmdbuffer->dispatch(32, 32, 1);
|
||||
}
|
||||
|
||||
|
|
@ -327,9 +333,18 @@ std::vector<uint8_t> VkLightprober::GenerateIrradianceMap()
|
|||
|
||||
fb->GetCommands()->WaitForCommands(false);
|
||||
|
||||
std::vector<uint8_t> databuffer(32 * 32 * 8 * 6);
|
||||
auto src = staging->Map(0, databuffer.size());
|
||||
memcpy(databuffer.data(), src, databuffer.size());
|
||||
// Copy while dropping the alpha channel
|
||||
int texelCount = 32 * 32 * 6;
|
||||
TArray<uint16_t> databuffer(texelCount * 3, true);
|
||||
auto dst = databuffer.data();
|
||||
auto src = (uint16_t*)staging->Map(0, texelCount * 8);
|
||||
for (int i = 0; i < texelCount; i++)
|
||||
{
|
||||
*(dst++) = *(src++);
|
||||
*(dst++) = *(src++);
|
||||
*(dst++) = *(src++);
|
||||
src++;
|
||||
}
|
||||
staging->Unmap();
|
||||
return databuffer;
|
||||
}
|
||||
|
|
@ -383,10 +398,10 @@ void VkLightprober::CreatePrefilterMap()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> VkLightprober::GeneratePrefilterMap()
|
||||
TArray<uint16_t> VkLightprober::GeneratePrefilterMap()
|
||||
{
|
||||
auto staging = BufferBuilder()
|
||||
.Size(prefilterMap.levelsSize * 6)
|
||||
.Size(prefilterMap.levelsSize * 6 * 8)
|
||||
.Usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU)
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
|
|
@ -441,7 +456,7 @@ std::vector<uint8_t> VkLightprober::GeneratePrefilterMap()
|
|||
push.roughness = (float)level / (float)(prefilterMap.maxlevels - 1);
|
||||
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_COMPUTE, prefilterMap.pipelineLayout.get(), 0, prefilterMap.descriptorSets[i * prefilterMap.maxlevels + level].get());
|
||||
cmdbuffer->pushConstants(prefilterMap.pipelineLayout.get(), VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, sizeof(PrefilterMapPushConstants), &push);
|
||||
cmdbuffer->pushConstants(prefilterMap.pipelineLayout.get(), VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(PrefilterMapPushConstants), &push);
|
||||
cmdbuffer->dispatch(128 >> level, 128 >> level, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -468,9 +483,18 @@ std::vector<uint8_t> VkLightprober::GeneratePrefilterMap()
|
|||
|
||||
fb->GetCommands()->WaitForCommands(false);
|
||||
|
||||
std::vector<uint8_t> databuffer(prefilterMap.levelsSize * 6);
|
||||
auto src = staging->Map(0, databuffer.size());
|
||||
memcpy(databuffer.data(), src, databuffer.size());
|
||||
// Copy while dropping the alpha channel
|
||||
int texelCount = prefilterMap.levelsSize * 6;
|
||||
TArray<uint16_t> databuffer(texelCount * 3, true);
|
||||
auto dst = databuffer.data();
|
||||
auto src = (uint16_t*)staging->Map(0, texelCount * 8);
|
||||
for (int i = 0; i < texelCount; i++)
|
||||
{
|
||||
*(dst++) = *(src++);
|
||||
*(dst++) = *(src++);
|
||||
*(dst++) = *(src++);
|
||||
src++;
|
||||
}
|
||||
staging->Unmap();
|
||||
return databuffer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ public:
|
|||
~VkLightprober();
|
||||
|
||||
void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc);
|
||||
std::vector<uint8_t> GenerateIrradianceMap();
|
||||
std::vector<uint8_t> GeneratePrefilterMap();
|
||||
TArray<uint16_t> GenerateIrradianceMap();
|
||||
TArray<uint16_t> GeneratePrefilterMap();
|
||||
|
||||
private:
|
||||
void CreateBrdfLutResources();
|
||||
|
|
@ -94,7 +94,7 @@ private:
|
|||
enum
|
||||
{
|
||||
maxlevels = 5,
|
||||
levelsSize = (128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8) * 8
|
||||
levelsSize = 128 * 128 + 64 * 64 + 32 * 32 + 16 * 16 + 8 * 8
|
||||
};
|
||||
std::unique_ptr<VulkanShader> shader;
|
||||
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
|
||||
|
|
|
|||
|
|
@ -321,6 +321,15 @@ void VulkanRenderDevice::RenderTextureView(FCanvasTexture* tex, std::function<vo
|
|||
tex->SetUpdated(true);
|
||||
}
|
||||
|
||||
void VulkanRenderDevice::RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
void VulkanRenderDevice::PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D)
|
||||
{
|
||||
if (!swscene) mPostprocess->BlitSceneToPostprocess(); // Copy the resulting scene to the current post process texture
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ public:
|
|||
|
||||
private:
|
||||
void RenderTextureView(FCanvasTexture* tex, std::function<void(IntRect &)> renderFunc) override;
|
||||
void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc) override;
|
||||
void PrintStartupLog();
|
||||
void CopyScreenToBuffer(int w, int h, uint8_t *data) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ EXTERN_CVAR(Bool, gl_bandedswlight)
|
|||
EXTERN_CVAR(Bool, lm_dynlights);
|
||||
|
||||
CVAR(Bool, gl_raytrace, false, 0/*CVAR_ARCHIVE | CVAR_GLOBALCONFIG*/)
|
||||
CVAR(Bool, gl_lightprobe, false, 0/*CVAR_ARCHIVE | CVAR_GLOBALCONFIG*/)
|
||||
|
||||
extern bool NoInterpolateView;
|
||||
|
||||
|
|
@ -108,11 +109,11 @@ void CollectLights(FLevelLocals* Level)
|
|||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen)
|
||||
sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen, int side)
|
||||
{
|
||||
auto& RenderState = *screen->RenderState();
|
||||
|
||||
R_SetupFrame(mainvp, r_viewwindow, camera);
|
||||
R_SetupFrame(mainvp, r_viewwindow, camera, side);
|
||||
|
||||
if (mainview && toscreen && !(camera->Level->flags3 & LEVEL3_NOSHADOWMAP) && camera->Level->HasDynamicLights && gl_light_shadows > 0 && !lm_dynlights)
|
||||
{
|
||||
|
|
@ -399,6 +400,22 @@ 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;
|
||||
if (lightprobe)
|
||||
{
|
||||
screen->RenderEnvironmentMap([=](IntRect& bounds, int side)
|
||||
{
|
||||
FRenderViewpoint probevp;
|
||||
RenderViewpoint(probevp, lightprobe, &bounds, 90.0, 1.0f, 1.0f, false, false, side);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
NoInterpolateView = saved_niv;
|
||||
|
||||
// now render the main view
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ private:
|
|||
};
|
||||
|
||||
void CleanSWDrawer();
|
||||
sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen);
|
||||
sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen, int side = -1);
|
||||
void WriteSavePic(player_t* player, FileWriter* file, int width, int height);
|
||||
sector_t* RenderView(player_t* player);
|
||||
|
||||
|
|
|
|||
|
|
@ -903,7 +903,7 @@ static void R_DoActorTickerAngleChanges(player_t* const player, DRotator& angles
|
|||
EXTERN_CVAR(Float, chase_dist)
|
||||
EXTERN_CVAR(Float, chase_height)
|
||||
|
||||
void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AActor* const actor)
|
||||
void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AActor* const actor, int side)
|
||||
{
|
||||
viewPoint.TicFrac = I_GetTimeFrac();
|
||||
if (cl_capfps || r_NoInterpolate)
|
||||
|
|
@ -1067,6 +1067,41 @@ void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AA
|
|||
|
||||
R_InterpolateView(viewPoint, player, viewPoint.TicFrac, iView);
|
||||
|
||||
if (side != -1) // Cubemap rendering
|
||||
{
|
||||
DRotator cubeside;
|
||||
cubeside.Roll = DAngle::fromDeg(0);
|
||||
switch (side)
|
||||
{
|
||||
default:
|
||||
case 0: // +X
|
||||
cubeside.Yaw = DAngle::fromDeg(0);
|
||||
cubeside.Pitch = DAngle::fromDeg(0);
|
||||
break;
|
||||
case 1: // +Y
|
||||
cubeside.Yaw = DAngle::fromDeg(90);
|
||||
cubeside.Pitch = DAngle::fromDeg(0);
|
||||
break;
|
||||
case 2: // +Z
|
||||
cubeside.Yaw = DAngle::fromDeg(0);
|
||||
cubeside.Pitch = DAngle::fromDeg(90);
|
||||
break;
|
||||
case 3: // -X
|
||||
cubeside.Yaw = DAngle::fromDeg(180);
|
||||
cubeside.Pitch = DAngle::fromDeg(0);
|
||||
break;
|
||||
case 4: // -Y
|
||||
cubeside.Yaw = DAngle::fromDeg(-90);
|
||||
cubeside.Pitch = DAngle::fromDeg(0);
|
||||
break;
|
||||
case 5: // -Z
|
||||
cubeside.Yaw = DAngle::fromDeg(0);
|
||||
cubeside.Pitch = DAngle::fromDeg(-90);
|
||||
break;
|
||||
}
|
||||
viewPoint.Angles = cubeside;
|
||||
}
|
||||
|
||||
viewPoint.SetViewAngle(viewWindow);
|
||||
|
||||
// Keep the view within the sector's floor and ceiling
|
||||
|
|
|
|||
|
|
@ -126,8 +126,7 @@ void R_ClearInterpolationPath();
|
|||
void R_AddInterpolationPoint(const DVector3a &vec);
|
||||
void R_SetViewSize (int blocks);
|
||||
void R_SetFOV (FRenderViewpoint &viewpoint, DAngle fov);
|
||||
void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AActor* const camera);
|
||||
void R_SetViewAngle (FRenderViewpoint &viewpoint, const FViewWindow &viewwindow);
|
||||
void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AActor* const camera, int side = -1);
|
||||
|
||||
// Called by startup code.
|
||||
void R_Init (void);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue