Files
FlaxEngine/Source/Engine/Renderer/AtmospherePreCompute.cpp
2022-01-14 13:31:12 +01:00

696 lines
25 KiB
C++

// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "AtmospherePreCompute.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Engine/Time.h"
#include "Engine/Content/Content.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/GPUPipelineState.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Platform/Window.h"
#include "RendererPass.h"
#include "Engine/Threading/ThreadPoolTask.h"
#include "Engine/Content/Assets/Shader.h"
#include "Engine/Content/AssetReference.h"
// Amount of frames to wait for data from atmosphere precompute job
#define ATMOSPHERE_PRECOMPUTE_LATENCY_FRAMES 1
const float DensityHeight = 0.5f;
const int32 MaxScatteringOrder = 4;
const int32 TransmittanceTexWidth = 256;
const int32 TransmittanceTexHeight = 64;
const int32 IrradianceTexWidth = 64;
const int32 IrradianceTexHeight = 16;
const int32 InscatterMuNum = 128;
const int32 InscatterMuSNum = 32;
const int32 InscatterNuNum = 8;
const int32 InscatterAltitudeSampleNum = 4;
const int32 InscatterWidth = InscatterMuSNum * InscatterNuNum;
const int32 InscatterHeight = InscatterMuNum;
const int32 InscatterDepth = InscatterAltitudeSampleNum;
const static float RadiusScale = 1;
const static float RadiusGround = 6360 * RadiusScale;
const static float RadiusAtmosphere = 6420 * RadiusScale;
class DownloadJob : public ThreadPoolTask
{
private:
GPUTexture* _transmittance;
GPUTexture* _irradiance;
GPUTexture* _inscatter;
public:
DownloadJob(GPUTexture* transmittance, GPUTexture* irradiance, GPUTexture* inscatter);
protected:
// [ThreadPoolTask]
bool Run() override;
};
PACK_STRUCT(struct Data
{
float First;
float AtmosphereR;
int AtmosphereLayer;
float Dummy0;
Vector4 dhdh;
});
namespace AtmospherePreComputeImpl
{
bool _isUpdatePending = false;
bool _isReadyForCompute = false;
bool _hasDataCached = false;
AssetReference<Shader> _shader;
GPUPipelineState* _psTransmittance = nullptr;
GPUPipelineState* _psIrradiance1 = nullptr;
GPUPipelineState* _psIrradianceN = nullptr;
GPUPipelineState* _psCopyIrradiance = nullptr;
GPUPipelineState* _psCopyIrradianceAdd = nullptr;
GPUPipelineState* _psInscatter1_A = nullptr;
GPUPipelineState* _psInscatter1_B = nullptr;
GPUPipelineState* _psCopyInscatter1 = nullptr;
GPUPipelineState* _psCopyInscatterNAdd = nullptr;
GPUPipelineState* _psInscatterS = nullptr;
GPUPipelineState* _psInscatterN = nullptr;
RenderTask* _task = nullptr;
//
GPUTexture* AtmosphereTransmittance = nullptr;
GPUTexture* AtmosphereIrradiance = nullptr;
GPUTexture* AtmosphereInscatter = nullptr;
//
GPUTexture* AtmosphereDeltaE = nullptr;
GPUTexture* AtmosphereDeltaSR = nullptr;
GPUTexture* AtmosphereDeltaSM = nullptr;
GPUTexture* AtmosphereDeltaJ = nullptr;
uint64 _updateFrameNumber;
bool _wasCancelled;
FORCE_INLINE bool isUpdateSynced()
{
return _updateFrameNumber > 0 && _updateFrameNumber + ATMOSPHERE_PRECOMPUTE_LATENCY_FRAMES <= Engine::FrameCount;
}
void onRender(RenderTask* task, GPUContext* context);
}
using namespace AtmospherePreComputeImpl;
class AtmospherePreComputeService : public EngineService
{
public:
AtmospherePreComputeService()
: EngineService(TEXT("Atmosphere Pre Compute"), 50)
{
}
void Update() override;
void Dispose() override;
};
AtmospherePreComputeService AtmospherePreComputeServiceInstance;
bool AtmospherePreCompute::GetCache(AtmosphereCache* cache)
{
if (_hasDataCached)
{
if (cache)
{
cache->Transmittance = AtmosphereTransmittance;
cache->Irradiance = AtmosphereIrradiance;
cache->Inscatter = AtmosphereInscatter;
}
}
else if (_task == nullptr || !_task->Enabled)
{
_isUpdatePending = true;
}
return _hasDataCached;
}
bool init()
{
if (_isReadyForCompute)
return false;
LOG(Info, "Starting Atmosphere Pre Compute service");
// Load shader
if (_shader == nullptr)
{
LOG(Warning, "Failed to load AtmospherePreCompute shader!");
return true;
}
if (_shader->WaitForLoaded())
{
LOG(Warning, "Loading AtmospherePreCompute shader timeout!");
return true;
}
auto shader = _shader->GetShader();
// Validate shader constant buffers sizes
ASSERT(shader->GetCB(0) != nullptr);
if (shader->GetCB(0)->GetSize() != sizeof(Data))
{
LOG(Fatal, "Shader {0} has incorrect constant buffer {1} size: {2} bytes. Expected: {3} bytes", _shader->ToString(), 0, shader->GetCB(0)->GetSize(), sizeof(Data));
return true;
}
// Create pipeline stages
_psTransmittance = GPUDevice::Instance->CreatePipelineState();
_psIrradiance1 = GPUDevice::Instance->CreatePipelineState();
_psIrradianceN = GPUDevice::Instance->CreatePipelineState();
_psCopyIrradiance = GPUDevice::Instance->CreatePipelineState();
_psCopyIrradianceAdd = GPUDevice::Instance->CreatePipelineState();
_psInscatter1_A = GPUDevice::Instance->CreatePipelineState();
_psInscatter1_B = GPUDevice::Instance->CreatePipelineState();
_psCopyInscatter1 = GPUDevice::Instance->CreatePipelineState();
_psInscatterS = GPUDevice::Instance->CreatePipelineState();
_psInscatterN = GPUDevice::Instance->CreatePipelineState();
_psCopyInscatterNAdd = GPUDevice::Instance->CreatePipelineState();
GPUPipelineState::Description psDesc, psDescLayers;
psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle;
psDescLayers = psDesc;
//psDescLayers.GS = shader->GetGS(0);
{
psDesc.PS = shader->GetPS("PS_Transmittance");
if (_psTransmittance->Init(psDesc))
return true;
}
{
psDesc.PS = shader->GetPS("PS_Irradiance1");
if (_psIrradiance1->Init(psDesc))
return true;
}
{
psDesc.PS = shader->GetPS("PS_IrradianceN");
if (_psIrradianceN->Init(psDesc))
return true;
}
{
psDesc.PS = shader->GetPS("PS_CopyIrradiance1");
if (_psCopyIrradiance->Init(psDesc))
return true;
}
{
psDescLayers.PS = shader->GetPS("PS_Inscatter1_A");
if (_psInscatter1_A->Init(psDescLayers))
return true;
}
{
psDescLayers.PS = shader->GetPS("PS_Inscatter1_B");
if (_psInscatter1_B->Init(psDescLayers))
return true;
}
{
psDescLayers.PS = shader->GetPS("PS_CopyInscatter1");
if (_psCopyInscatter1->Init(psDescLayers))
return true;
}
{
psDescLayers.PS = shader->GetPS("PS_InscatterS");
if (_psInscatterS->Init(psDescLayers))
return true;
}
{
psDescLayers.PS = shader->GetPS("PS_InscatterN");
if (_psInscatterN->Init(psDescLayers))
return true;
}
psDescLayers.BlendMode = BlendingMode::Add;
psDesc.BlendMode = BlendingMode::Add;
{
psDescLayers.PS = shader->GetPS("PS_CopyInscatterN");
if (_psCopyInscatterNAdd->Init(psDescLayers))
return true;
}
{
psDesc.PS = shader->GetPS("PS_CopyIrradiance1");
if (_psCopyIrradianceAdd->Init(psDesc))
return true;
}
// Init rendering pipeline
_task = New<SceneRenderTask>();
_task->Enabled = false;
_task->Render.Bind(onRender);
// Init render targets
AtmosphereTransmittance = GPUDevice::Instance->CreateTexture(TEXT("AtmospherePreCompute.Transmittance"));
if (AtmosphereTransmittance->Init(GPUTextureDescription::New2D(TransmittanceTexWidth, TransmittanceTexHeight, PixelFormat::R16G16B16A16_Float, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget)))
return true;
AtmosphereIrradiance = GPUDevice::Instance->CreateTexture(TEXT("AtmospherePreCompute.Irradiance"));
if (AtmosphereIrradiance->Init(GPUTextureDescription::New2D(IrradianceTexWidth, IrradianceTexHeight, PixelFormat::R16G16B16A16_Float, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget)))
return true;
AtmosphereDeltaE = GPUDevice::Instance->CreateTexture(TEXT("AtmospherePreCompute.DeltaE"));
if (AtmosphereDeltaE->Init(GPUTextureDescription::New2D(IrradianceTexWidth, IrradianceTexHeight, PixelFormat::R16G16B16A16_Float, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget)))
return true;
AtmosphereInscatter = GPUDevice::Instance->CreateTexture(TEXT("AtmospherePreCompute.Inscatter"));
if (AtmosphereInscatter->Init(GPUTextureDescription::New3D(InscatterWidth, InscatterHeight, InscatterDepth, PixelFormat::R16G16B16A16_Float, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerSliceViews)))
return true;
AtmosphereDeltaSR = GPUDevice::Instance->CreateTexture(TEXT("AtmospherePreCompute.DeltaSR"));
if (AtmosphereDeltaSR->Init(GPUTextureDescription::New3D(InscatterWidth, InscatterHeight, InscatterDepth, PixelFormat::R16G16B16A16_Float, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerSliceViews)))
return true;
AtmosphereDeltaSM = GPUDevice::Instance->CreateTexture(TEXT("AtmospherePreCompute.DeltaSM"));
if (AtmosphereDeltaSM->Init(GPUTextureDescription::New3D(InscatterWidth, InscatterHeight, InscatterDepth, PixelFormat::R16G16B16A16_Float, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerSliceViews)))
return true;
AtmosphereDeltaJ = GPUDevice::Instance->CreateTexture(TEXT("AtmospherePreCompute.DeltaJ"));
if (AtmosphereDeltaJ->Init(GPUTextureDescription::New3D(InscatterWidth, InscatterHeight, InscatterDepth, PixelFormat::R16G16B16A16_Float, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerSliceViews)))
return true;
// Mark as ready
_isReadyForCompute = true;
_wasCancelled = false;
return false;
}
void release()
{
if (!_isReadyForCompute)
return;
if (_updateFrameNumber != 0)
{
_wasCancelled = true;
}
_updateFrameNumber = 0;
LOG(Info, "Disposing Atmosphere Pre Compute service");
// Release data
SAFE_DELETE_GPU_RESOURCE(_psTransmittance);
SAFE_DELETE_GPU_RESOURCE(_psIrradiance1);
SAFE_DELETE_GPU_RESOURCE(_psIrradianceN);
SAFE_DELETE_GPU_RESOURCE(_psCopyIrradiance);
SAFE_DELETE_GPU_RESOURCE(_psCopyIrradianceAdd);
SAFE_DELETE_GPU_RESOURCE(_psInscatter1_A);
SAFE_DELETE_GPU_RESOURCE(_psInscatter1_B);
SAFE_DELETE_GPU_RESOURCE(_psCopyInscatter1);
SAFE_DELETE_GPU_RESOURCE(_psInscatterS);
SAFE_DELETE_GPU_RESOURCE(_psInscatterN);
SAFE_DELETE_GPU_RESOURCE(_psCopyInscatterNAdd);
_shader = nullptr;
SAFE_DELETE(_task);
SAFE_DELETE_GPU_RESOURCE(AtmosphereTransmittance);
SAFE_DELETE_GPU_RESOURCE(AtmosphereIrradiance);
SAFE_DELETE_GPU_RESOURCE(AtmosphereInscatter);
SAFE_DELETE_GPU_RESOURCE(AtmosphereDeltaE);
SAFE_DELETE_GPU_RESOURCE(AtmosphereDeltaSR);
SAFE_DELETE_GPU_RESOURCE(AtmosphereDeltaSM);
SAFE_DELETE_GPU_RESOURCE(AtmosphereDeltaJ);
_isReadyForCompute = false;
}
void AtmospherePreComputeService::Update()
{
// Calculate time delta since last update
auto currentTime = Time::Update.UnscaledTime;
// Check if render job is done
if (isUpdateSynced())
{
// Create async job to gather data from the GPU
//ThreadPool::AddJob(New<DownloadJob>(AtmosphereTransmittance, AtmosphereIrradiance, AtmosphereInscatter));
// TODO: download data from generated cache textures
// TODO: serialize cached textures
// Clear flags
_updateFrameNumber = 0;
_isUpdatePending = false;
// Release service
//release();
// TODO: release service data
}
else if (_isUpdatePending && (_task == nullptr || !_task->Enabled))
{
// TODO: init but without a stalls, just wait for resources loaded and then start rendering
// Init service
if (!_shader)
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/AtmospherePreCompute"));
if (_shader && !_shader->IsLoaded())
return;
if (init())
{
LOG(Fatal, "Cannot setup Atmosphere Pre Compute!");
}
// Mark task to update
_task->Enabled = true;
_updateFrameNumber = 0;
}
}
void AtmospherePreComputeService::Dispose()
{
release();
}
void GetLayerValue(int32 layer, float& atmosphereR, Vector4& dhdh)
{
float r = layer / Math::Max<float>(InscatterAltitudeSampleNum - 1.0f, 1.0f);
r = r * r;
r = Math::Sqrt(RadiusGround * RadiusGround + r * (RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround)) + (layer == 0 ? 0.01f : (layer == InscatterAltitudeSampleNum - 1 ? -0.001f : 0.0f));
const float dMin = RadiusAtmosphere - r;
const float dMax = Math::Sqrt(r * r - RadiusGround * RadiusGround) + Math::Sqrt(RadiusAtmosphere * RadiusAtmosphere - RadiusGround * RadiusGround);
const float dMinP = r - RadiusGround;
const float dMaxP = Math::Sqrt(r * r - RadiusGround * RadiusGround);
atmosphereR = r;
dhdh = Vector4(dMin, dMax, dMinP, dMaxP);
}
void AtmospherePreComputeImpl::onRender(RenderTask* task, GPUContext* context)
{
// If job has been cancelled (eg. on window close)
if (_wasCancelled)
{
LOG(Warning, "AtmospherePreCompute job cancelled");
return;
}
ASSERT(_isUpdatePending && _updateFrameNumber == 0);
const auto shader = _shader->GetShader();
const auto cb = shader->GetCB(0);
Data data;
// Compute transmittance texture T (line 1 in algorithm 4.1)
context->SetRenderTarget(*AtmosphereTransmittance);
context->SetViewportAndScissors((float)TransmittanceTexWidth, (float)TransmittanceTexHeight);
context->SetState(_psTransmittance);
context->DrawFullscreenTriangle();
context->ResetRenderTarget();
// Compute irradiance texture deltaE (line 2 in algorithm 4.1)
context->SetRenderTarget(*AtmosphereDeltaE);
context->SetViewportAndScissors((float)IrradianceTexWidth, (float)IrradianceTexHeight);
context->BindSR(0, AtmosphereTransmittance);
context->SetState(_psIrradiance1);
context->DrawFullscreenTriangle();
context->ResetRenderTarget();
// Compute single scattering texture deltaS (line 3 in algorithm 4.1)
// Rayleigh and Mie separated in deltaSR + deltaSM
context->SetViewportAndScissors((float)InscatterWidth, (float)InscatterHeight);
context->SetState(_psInscatter1_A);
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
{
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
data.AtmosphereLayer = layer;
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->SetRenderTarget(AtmosphereDeltaSR->View(layer));
context->DrawFullscreenTriangle();
}
context->SetState(_psInscatter1_B);
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
{
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
data.AtmosphereLayer = layer;
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->SetRenderTarget(AtmosphereDeltaSM->View(layer));
context->DrawFullscreenTriangle();
}
context->ResetRenderTarget();
//// old way to render Inscatter1 to DeltaSR and DeltaSM at once but didn't work well :/ (no time to find out why)
//for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
//{
// GetLayerValue(layer, data.AtmosphereR, data.dhdh);
// data.AtmosphereLayer = layer;
// cb->SetData(&data);
// context->Bind(0, cb);
// GPUTextureView* deltaRTs[2] = { AtmosphereDeltaSR->HandleSlice(layer), AtmosphereDeltaSM->HandleSlice(layer) };
// //GPUTextureView* deltaRTs[2] = { AtmosphereIrradiance->Handle(), AtmosphereDeltaE->Handle() };
// context->SetRenderTarget(nullptr, 2, deltaRTs);
// //context->SetRenderTarget(AtmosphereIrradiance->View());
// //context->SetRenderTarget(AtmosphereDeltaSR->HandleSlice(layer));
// //context->SetRenderTarget(AtmosphereDeltaSR->View());
// context->DrawFullscreenTriangle();
//}
//context->SetRenderTarget();
// Copy deltaE into irradiance texture E (line 4 in algorithm 4.1)
/*context->SetRenderTarget(*AtmosphereIrradiance);
context->SetViewport(IrradianceTexWidth, IrradianceTexHeight);
context->Bind(3, AtmosphereDeltaE);
context->SetState(_psCopyIrradiance);
context->DrawFullscreenTriangle();*/
// TODO: remove useless CopyIrradiance shader program?
context->SetViewportAndScissors((float)IrradianceTexWidth, (float)IrradianceTexHeight);
context->Clear(*AtmosphereIrradiance, Color::Transparent);
// Copy deltaS into inscatter texture S (line 5 in algorithm 4.1)
context->SetViewportAndScissors((float)InscatterWidth, (float)InscatterHeight);
context->SetState(_psCopyInscatter1);
context->BindSR(4, AtmosphereDeltaSR->ViewVolume());
context->BindSR(5, AtmosphereDeltaSM->ViewVolume());
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
{
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
data.AtmosphereLayer = layer;
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->SetRenderTarget(AtmosphereInscatter->View(layer));
context->DrawFullscreenTriangle();
}
context->ResetRenderTarget();
// Loop for each scattering order (line 6 in algorithm 4.1)
for (int32 order = 2; order <= MaxScatteringOrder; order++)
{
// Compute deltaJ (line 7 in algorithm 4.1)
context->UnBindSR(6);
context->SetViewportAndScissors((float)InscatterWidth, (float)InscatterHeight);
context->SetState(_psInscatterS);
data.First = order == 2 ? 1.0f : 0.0f;
context->BindSR(0, AtmosphereTransmittance);
context->BindSR(3, AtmosphereDeltaE);
context->BindSR(4, AtmosphereDeltaSR->ViewVolume());
context->BindSR(5, AtmosphereDeltaSM->ViewVolume());
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
{
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
data.AtmosphereLayer = layer;
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->SetRenderTarget(AtmosphereDeltaJ->View(layer));
context->DrawFullscreenTriangle();
}
// Compute deltaE (line 8 in algorithm 4.1)
context->UnBindSR(3);
context->SetRenderTarget(AtmosphereDeltaE->View());
context->SetViewportAndScissors((float)IrradianceTexWidth, (float)IrradianceTexHeight);
context->BindSR(0, AtmosphereTransmittance);
context->BindSR(4, AtmosphereDeltaSR->ViewVolume());
context->BindSR(5, AtmosphereDeltaSM->ViewVolume());
context->SetState(_psIrradianceN);
context->DrawFullscreenTriangle();
// Compute deltaS (line 9 in algorithm 4.1)
context->UnBindSR(4);
context->SetViewportAndScissors((float)InscatterWidth, (float)InscatterHeight);
context->SetState(_psInscatterN);
context->BindSR(0, AtmosphereTransmittance);
context->BindSR(6, AtmosphereDeltaJ->ViewVolume());
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
{
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
data.AtmosphereLayer = layer;
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->SetRenderTarget(AtmosphereDeltaSR->View(layer));
context->DrawFullscreenTriangle();
}
// Add deltaE into irradiance texture E (line 10 in algorithm 4.1)
context->SetRenderTarget(*AtmosphereIrradiance);
context->SetViewportAndScissors((float)IrradianceTexWidth, (float)IrradianceTexHeight);
context->BindSR(3, AtmosphereDeltaE);
context->SetState(_psCopyIrradianceAdd);
context->DrawFullscreenTriangle();
// Add deltaS into inscatter texture S (line 11 in algorithm 4.1)
context->SetViewportAndScissors((float)InscatterWidth, (float)InscatterHeight);
context->SetState(_psCopyInscatterNAdd);
context->BindSR(4, AtmosphereDeltaSR->ViewVolume());
for (int32 layer = 0; layer < InscatterAltitudeSampleNum; layer++)
{
GetLayerValue(layer, data.AtmosphereR, data.dhdh);
data.AtmosphereLayer = layer;
context->UpdateCB(cb, &data);
context->BindCB(0, cb);
context->SetRenderTarget(AtmosphereInscatter->View(layer));
context->DrawFullscreenTriangle();
}
}
// Cleanup
context->ResetRenderTarget();
context->ResetSR();
// Mark as rendered
_hasDataCached = true;
_isUpdatePending = false;
_updateFrameNumber = Engine::FrameCount;
_task->Enabled = false;
}
DownloadJob::DownloadJob(GPUTexture* transmittance, GPUTexture* irradiance, GPUTexture* inscatter)
: _transmittance(transmittance)
, _irradiance(irradiance)
, _inscatter(inscatter)
{
}
bool DownloadJob::Run()
{
TextureData textureData;
Array<byte> data;
#if BUILD_DEBUG
// Transmittance
/*{
if (_transmittance->DownloadData(textureData))
{
LOG(Fatal, 193, "AtmospherePreCompute::DownloadJob::Transmittance");
return;
}
auto in = textureData.Get(0, 0);
int rowPich = 3 * TransmittanceTexWidth * sizeof(BYTE);
int size = rowPich * TransmittanceTexHeight;
data.EnsureCapacity(size, false);
byte* p = data.Get();
for (int y = 0; y < TransmittanceTexHeight; y++)
{
for (int x = 0; x < TransmittanceTexWidth; x++)
{
Vector4 t = ((Half4*)&in->Data[y * in->RowPitch + x * sizeof(Half4)])->ToVector4();
*p++ = Math::Saturate(t.Z) * 255;
*p++ = Math::Saturate(t.Y) * 255;
*p++ = Math::Saturate(t.X) * 255;
}
}
FileSystem::SaveBitmapToFile(data.Get(),
TransmittanceTexWidth,
TransmittanceTexHeight,
24,
0,
L"C:\\Users\\Wojtek\\Downloads\\transmittance_Flax.bmp");
}*/
// Irradiance
/*{
textureData.Clear();
if (_irradiance->DownloadData(textureData))
{
LOG(Fatal, 193, "AtmospherePreCompute::DownloadJob::Irradiance");
return;
}
auto in = textureData.Get(0, 0);
int rowPich = 3 * IrradianceTexWidth * sizeof(BYTE);
int size = rowPich * IrradianceTexHeight;
data.EnsureCapacity(size, false);
byte* p = data.Get();
for (int y = 0; y < IrradianceTexHeight; y++)
{
for (int x = 0; x < IrradianceTexWidth; x++)
{
Vector4 t = ((Half4*)&in->Data[y * in->RowPitch + x * sizeof(Half4)])->ToVector4();
*p++ = Math::Saturate(t.Z) * 255;
*p++ = Math::Saturate(t.Y) * 255;
*p++ = Math::Saturate(t.X) * 255;
}
}
FileSystem::SaveBitmapToFile(data.Get(),
IrradianceTexWidth,
IrradianceTexHeight,
24,
0,
L"C:\\Users\\Wojtek\\Downloads\\irradiance_Flax.bmp");
}*/
/*// Inscatter
{
textureData.Clear();
if (_inscatter->DownloadData(textureData))
{
LOG(Fatal, 193, "AtmospherePreCompute::DownloadJob::Inscatter");
return;
}
auto in = textureData.Get(0, 0);
int rowPich = 3 * InscatterWidth * sizeof(BYTE);
int size = rowPich * InscatterHeight;
data.EnsureCapacity(size, false);
for (int32 depthSlice = 0; depthSlice < InscatterDepth; depthSlice++)
{
byte* p = data.Get();
byte* s = in->Data.Get() + depthSlice * in->DepthPitch;
for (int y = 0; y < InscatterHeight; y++)
{
for (int x = 0; x < InscatterWidth; x++)
{
Vector4 t = ((Half4*)&s[y * in->RowPitch + x * sizeof(Half4)])->ToVector4();
*p++ = Math::Saturate(t.Z) * 255;
*p++ = Math::Saturate(t.Y) * 255;
*p++ = Math::Saturate(t.X) * 255;
}
}
FileSystem::SaveBitmapToFile(data.Get(),
InscatterWidth,
InscatterHeight,
24,
0,
*String::Format(TEXT("C:\\Users\\Wojtek\\Downloads\\inscatter_{0}_Flax.bmp"), depthSlice));
break;
}
}*/
#else
MISSING_CODE("download precomputed atmosphere data from the GPU!");
#endif
return false;
}