#ifndef PostHDR_h__ #define PostHDR_h__ #include "render/PostEffect.h" #include "Globals.h" #include "render/ITextureSampler.h" #include "math/LifeMath.h" #define _CRTDBG_MAP_ALLOC #include "LifeDebug.h" #include #include namespace LifeGraphics { class PostHDR : public PostEffect { public: ITexture2D* g_brightPassTexture; ITexture2D* g_downSampleTexture; ITexture2D* g_horizontalBlur; ITexture2D* g_verticalBlur; ITexture2D* g_finalImage; ITexture2D* g_lumLast; ITexture2D* g_lumCur; static const int NumLuminanceTextures = 4; ITexture2D* luminanceTextures[NumLuminanceTextures]; ITexture2D* luminanceTexturesZ[NumLuminanceTextures]; ITexture2D* src; ITexture2D* srcZ; ITexture2D* downSampleZ; ITexture2D* brightPassZ; ITextureSampler* samplerPointClamp; float exposure; float brightTheresold; PostHDR() { } ~PostHDR() { SAFE_DELETE(g_brightPassTexture); SAFE_DELETE(g_downSampleTexture); SAFE_DELETE(g_horizontalBlur); SAFE_DELETE(g_verticalBlur); SAFE_DELETE(g_finalImage); SAFE_DELETE(g_lumLast); SAFE_DELETE(g_lumCur); SAFE_DELETE(downSampleZ); SAFE_DELETE(brightPassZ); SAFE_DELETE(g_downSamplePS); SAFE_DELETE(g_brightPassPS); SAFE_DELETE(g_horizontalBlurPS); SAFE_DELETE(g_verticalBlurPS); SAFE_DELETE(g_downSample2x2PS); SAFE_DELETE(g_downSample3x3PS); SAFE_DELETE(g_resampleAvgLumExp); SAFE_DELETE(g_lumAdaptation); SAFE_DELETE(g_composePS); SAFE_DELETE(g_constBuffer); SAFE_DELETE(g_pointSampler); SAFE_DELETE(g_linearSampler); SAFE_DELETE(g_cbLumAdaptation); for(int i = 0; iSetPSTextureSampler(g_pointSampler, 0); g_renderer->SetPSTextureSampler(g_linearSampler, 1); g_renderer->SetTargets(g_downSampleTexture, downSampleZ); g_renderer->SetViewport(LifeMath::Rect2i(0, 0, g_downSampleTexture->Width(), g_downSampleTexture->Height())); //1'st pass - do down sampling g_renderer->SetPixelShader(g_downSamplePS); g_renderer->SetPSTexture(params.renderTarget, 0); src = params.renderTarget; srcZ = params.depthTarget; Get4x4Offsets(params.renderTarget->Width(), params.renderTarget->Height(), offsets2); g_constBuffer->Update(offsets2, sizeof(LifeMath::float4)*16); g_renderer->SetPSConstantBuffer(g_constBuffer, 0); // g_downSamplePS.SetFloat4A("downSampleOffsets", offsets2); g_renderer->RenderToTextureNoPs(); // g_downSampleTexture.ToFile("C:\\rt_1_downSample.jpg"); //2'nd measure scene luminance MeasureLuminance(g_downSampleTexture, params.depthTex); //3'rd calculate scene luminance adaptation // CalculateLuminanceAdaptation(params.timeElapsed); //4'th step - bright pass g_renderer->UnbindResourcesPS(); g_renderer->SetTargets(g_brightPassTexture, brightPassZ); g_renderer->SetPixelShader(g_brightPassPS); g_renderer->SetPSTexture(g_downSampleTexture, 0); g_renderer->SetPSTexture(g_lumCur, 1); g_renderer->SetPSTexture(params.depthTex, 2); //g_renderer.SetTextureSampler(g_pointSampler, 0); /// g_renderer.SetTextureSampler(g_pointSampler, 1); g_renderer->SetViewport(LifeMath::Rect2i(0, 0, g_brightPassTexture->Width(), g_brightPassTexture->Height())); g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, g_brightPassTexture->Width(), g_brightPassTexture->Height())); g_renderer->RenderToTextureNoPs(); // g_brightPassTexture.ToFile("C:\\rt_2_brightPass.jpg"); // g_renderer.SetTextureSampler(g_linearSampler, 0); g_renderer->UnbindResourcesPS(); g_renderer->SetPSTextureSampler(samplerPointClamp, 0); g_renderer->SetPSTextureSampler(samplerPointClamp, 1); //5'th pass - do horizontal blur g_renderer->SetTargets(g_horizontalBlur, downSampleZ); g_renderer->SetPixelShader(g_horizontalBlurPS); g_renderer->SetPSTexture(g_brightPassTexture, 0); GetBlurWeightedOffsets((float)NumBlurSamples, g_brightPassTexture->Width(), offsets3); g_constBuffer->Update(offsets3, sizeof(LifeMath::float4)*NumBlurSamples); g_renderer->SetPSConstantBuffer(g_constBuffer, 0); // g_horizontalBlurPS.SetFloat4A("hBlurOffsets", offsets3); g_renderer->SetViewport(LifeMath::Rect2i(0, 0, g_horizontalBlur->Width(), g_horizontalBlur->Height())); g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, g_horizontalBlur->Width(), g_horizontalBlur->Height())); g_renderer->RenderToTextureNoPs(); // g_horizontalBlur.ToFile("C:\\rt_3_horBlur.jpg"); //6'th pass - do vertical blur g_renderer->UnbindResourcesPS(); g_renderer->SetTargets(g_verticalBlur, downSampleZ); g_renderer->SetPixelShader(g_verticalBlurPS); g_renderer->SetPSTexture(g_horizontalBlur, 0); GetBlurWeightedOffsets((float)NumBlurSamples, g_brightPassTexture->Height(), offsets3); //g_verticalBlurPS.SetFloat4A("vBlurOffsets", offsets4); g_constBuffer->Update(offsets3, sizeof(LifeMath::float4)*NumBlurSamples); g_renderer->SetPSConstantBuffer(g_constBuffer, 0); g_renderer->RenderToTextureNoPs(); //7'th compose final image ComposeFinalImage(params.renderTarget, g_lumCur, g_verticalBlur); // g_finalImage.ToFile("C:\\rt_5_final.jpg"); return g_finalImage; } void Init(SceneDescriptor& desc) { g_renderer = CG::me()->GetRenderer(); g_lumAdaptation = ResourceManager::me()->CompileUserShaderPS(String(_text("HDRLumAdaptation.psh"))); /* char laPs[] = "Texture2D tex0 : register(t7);"\ "Texture2D tex1 : register(t8);"\ "SamplerState linearSampler : register(s0);"\ "cbuffer timeData : register(b11){float4 g_fElapsedTime : packoffset(c0);};"\ "float4 main_PS(in float4 Position : SV_Position, in float2 texcoord : TEXCOORD0) : SV_Target{"\ "float4 fAdaptedLum =tex0.Sample(linearSampler, float2(0.25f, 0.25f));"\ "float4 fCurrentLum = tex1.Sample(linearSampler, float2(0.5f, 0.5f));"\ "float fNewAdaptation = fAdaptedLum + (fCurrentLum - fAdaptedLum) * g_fElapsedTime.x;"\ "return fAdaptedLum;}"; g_lumAdaptation = g_renderer->CompileUserShaderPS(laPs);*/ ISamplerDescription pscDesc(Clamp, Clamp, Clamp, MinMagMipPoint); samplerPointClamp = g_renderer->CreateTextureSampler(&pscDesc); exposure = 0.72f; brightTheresold = 0.7f; g_finalImage = g_renderer->CreateRenderTarget(desc.width, desc.height, FORMAT_R16G16B16A16_FLOAT); //Bright pass texture int brightPassTextureWidth = desc.width / 4; int brightPassTextureHeight = desc.height / 4; g_brightPassTexture = g_renderer->CreateRenderTarget(brightPassTextureWidth, brightPassTextureHeight, FORMAT_R16G16B16A16_FLOAT); brightPassZ = g_renderer->CreateDepthTarget(brightPassTextureWidth, brightPassTextureHeight, FORMAT_D16_UNORM); //Down sample texture int downSampledTextureWidth = brightPassTextureWidth / 1; int downSampledTextureHeight = brightPassTextureHeight / 1; g_downSampleTexture = g_renderer->CreateRenderTarget(downSampledTextureWidth, downSampledTextureHeight, FORMAT_R16G16B16A16_FLOAT); downSampleZ = g_renderer->CreateDepthTarget(downSampledTextureWidth, downSampledTextureHeight, FORMAT_D16_UNORM); //Horizontal blur texture int horizontalBlurTextureWidth = downSampledTextureWidth; int horizontalBlurTextureHeight = downSampledTextureHeight; g_horizontalBlur = g_renderer->CreateRenderTarget(horizontalBlurTextureWidth, horizontalBlurTextureHeight, FORMAT_R16G16B16A16_FLOAT); //Vertical blur texture int verticalBlurTextureWidth = horizontalBlurTextureWidth; int verticalBlurTextureHeight = horizontalBlurTextureHeight; g_verticalBlur = g_renderer->CreateRenderTarget(verticalBlurTextureWidth, verticalBlurTextureHeight, FORMAT_R16G16B16A16_FLOAT); g_downSamplePS = ResourceManager::me()->CompileUserShaderPS(String(_text("DownSample.psh"))); g_brightPassPS = ResourceManager::me()->CompileUserShaderPS(String(_text("BrightPass.psh"))); g_horizontalBlurPS = ResourceManager::me()->CompileUserShaderPS(String(_text("HorizontalBlur.psh"))); g_verticalBlurPS = ResourceManager::me()->CompileUserShaderPS(String(_text("VerticalBlur.psh"))); g_resampleAvgLumExp = ResourceManager::me()->CompileUserShaderPS(String(_text("ResampleAvgLumExp.psh"))); //LC g_downSample2x2PS = ResourceManager::me()->CompileUserShaderPS(String(_text("SampleLumInitial.psh"))); g_downSample3x3PS = ResourceManager::me()->CompileUserShaderPS(String(_text("DownSampleLum3.psh"))); g_composePS = ResourceManager::me()->CompileUserShaderPS(String(_text("ComposeHDR.psh"))); g_constBuffer = g_renderer->CreateConstantBuffer(16 * 16*256); g_cbLumAdaptation = g_renderer->CreateConstantBuffer(sizeof(LifeMath::float4)); CreateLuminanceTextures(); ISamplerDescription psDesc(Wrap, Wrap, Wrap, MinMagMipPoint); ISamplerDescription lsDesc(Wrap, Wrap, Wrap, Anisotropic); g_pointSampler = g_renderer->CreateTextureSampler(&psDesc); g_linearSampler = g_renderer->CreateTextureSampler(&lsDesc); } private: static const int MAX_SAMPLES = 6; //post effects IShader* g_downSamplePS; IShader* g_brightPassPS; IShader* g_horizontalBlurPS; IShader* g_verticalBlurPS; //luminance calculation IShader* g_downSample2x2PS; IShader* g_downSample3x3PS; IShader* g_resampleAvgLumExp; IShader* g_lumAdaptation; //final composing shader IShader* g_composePS; static const int NumBlurSamples = 9; //luminance calculator IRenderer* g_renderer; IConstantBuffer* g_constBuffer; ITextureSampler* g_pointSampler; ITextureSampler* g_linearSampler; IConstantBuffer* g_cbLumAdaptation; LifeMath::float4 offsets2[16]; LifeMath::float4 offsets3[NumBlurSamples]; LifeMath::float4 offsets[9]; void CreateLuminanceTextures() { for (int i = 0; i < NumLuminanceTextures; i++) { int iSampleLen = 1 << (2 * i); luminanceTextures[i] = g_renderer->CreateRenderTarget(iSampleLen, iSampleLen, FORMAT_R16G16B16A16_FLOAT); luminanceTexturesZ[i] = g_renderer->CreateDepthTarget(iSampleLen, iSampleLen, FORMAT_D16_UNORM); } g_lumCur = g_renderer->CreateRenderTarget(1, 1, FORMAT_R16G16B16A16_FLOAT); g_lumLast = g_renderer->CreateRenderTarget(1, 1, FORMAT_R16G16B16A16_FLOAT); LifeMath::float4 clear_color(1,1,1,1); g_renderer->ClearRenderTarget(g_lumCur, &clear_color); g_renderer->ClearRenderTarget(g_lumLast, &clear_color); } void Render2x2Pass(ITexture2D* srcTexture, ITexture2D* destTexture, ITexture2D* sceneDepth) { float tU, tV; tU = 1.0f / (3.0f * destTexture->Width()); tV = 1.0f / (3.0f * destTexture->Height()); int index = 0; for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { offsets[index].X = (float)x * tU; offsets[index].Y = (float)y * tV; index++; } } g_renderer->SetTargets(destTexture,luminanceTexturesZ[NumLuminanceTextures - 1]); g_renderer->SetPSTexture(srcTexture, 0); g_renderer->SetPSTexture(sceneDepth, 1); g_renderer->SetPixelShader(g_downSample2x2PS); g_constBuffer->Update(&offsets, sizeof(LifeMath::float4)* 9); g_renderer->SetPSConstantBuffer(g_constBuffer, 0); // With everything configured we can now render the first pass to the luminance textures. g_renderer->SetViewport(LifeMath::Rect2i(0, 0, destTexture->Width(), destTexture->Height())); g_renderer->RenderToTextureNoPs(); } void MeasureLuminance(ITexture2D* hdrTexture, ITexture2D* depth) { int curTex = NumLuminanceTextures - 1; Render2x2Pass(hdrTexture, luminanceTextures[curTex],depth); curTex--; while (curTex > 0) { g_renderer->SetTargets(luminanceTextures[curTex], luminanceTexturesZ[curTex]); Get4x4Offsets(luminanceTextures[curTex + 1]->Width(), luminanceTextures[curTex + 1]->Height(), offsets2); g_renderer->SetPixelShader(g_downSample3x3PS); g_renderer->SetPSTexture(luminanceTextures[curTex + 1], 0); g_constBuffer->Update(offsets2, sizeof(LifeMath::float4)*16); g_renderer->SetPSConstantBuffer(g_constBuffer, 0); g_renderer->SetViewport(LifeMath::Rect2i(0, 0, luminanceTextures[curTex]->Width(), luminanceTextures[curTex]->Height())); g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, luminanceTextures[curTex]->Width(), luminanceTextures[curTex]->Height())); g_renderer->RenderToTextureNoPs(); curTex--; } g_renderer->SetTargets(luminanceTextures[0],luminanceTexturesZ[0]); g_renderer->SetPixelShader(g_resampleAvgLumExp); Get4x4Offsets(luminanceTextures[1]->Width(), luminanceTextures[1]->Height(), offsets2); g_constBuffer->Update(offsets2, sizeof(LifeMath::float4)*16); g_renderer->SetPSConstantBuffer(g_constBuffer, 0); g_renderer->SetPSTexture(luminanceTextures[1], 0); g_renderer->SetViewport(LifeMath::Rect2i(0, 0, luminanceTextures[0]->Width(), luminanceTextures[0]->Height())); g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, luminanceTextures[0]->Width(), luminanceTextures[0]->Height())); g_renderer->RenderToTextureNoPs(); } void CalculateLuminanceAdaptation(float timeElapsed) { g_renderer->SetViewport(LifeMath::Rect2i(0, 0, 1, 1)); g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, 1, 1)); g_renderer->UnbindResourcesPS(); ITexture2D* texSwap = g_lumLast; g_lumLast = g_lumCur; g_lumCur = texSwap; g_renderer->SetTargets(g_lumCur, luminanceTexturesZ[0]); LifeMath::float4 clear_color(0,0,0,0); g_renderer->ClearRenderTarget(g_lumCur, &clear_color); g_renderer->SetPixelShader(g_lumAdaptation); g_renderer->SetPSTexture(g_lumLast, luminanceTextures[0], 7,2); // g_renderer->SetPSTexture(rgba.ptr(), luminanceTextures[0], 7,2); if(timeElapsed <0.0000001f) timeElapsed = 0.0000001f; if(timeElapsed > 1.0f) timeElapsed = 1.0f; float val = (1.0f - (pow(0.98f, 30.0f * timeElapsed))); LifeMath::float4 time(val, 1.0f, 1.0f, 1.0f); g_cbLumAdaptation->Update(&time, sizeof(LifeMath::float4)); g_renderer->SetPSConstantBuffer(g_cbLumAdaptation, 11); g_renderer->RenderToTextureNoPs(); } void ComposeFinalImage(ITexture2D* hdrTexture, ITexture2D* luminanceTexture, ITexture2D* bloomTexture) { g_renderer->SetPSTextureSampler(g_linearSampler, 1); g_renderer->SetTargets(g_finalImage, srcZ); g_renderer->SetPixelShader(g_composePS); g_renderer->SetPSTexture(hdrTexture, 0); g_renderer->SetPSTexture(bloomTexture, 1); g_renderer->SetPSTextureNULL(2); g_renderer->SetPSTexture(luminanceTexture, 3); float g_fKeyValue = 0.05f; LifeMath::float4 key(g_fKeyValue, 0, 0, 0); g_constBuffer->Update(key, sizeof(LifeMath::float4)); g_renderer->SetPSConstantBuffer(g_constBuffer, 0); // g_composePS.SetFloat("g_fMiddleGray", g_fKeyValue); g_renderer->SetViewport(LifeMath::Rect2i(0, 0, g_finalImage->Width(), g_finalImage->Height())); g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, g_finalImage->Width(), g_finalImage->Height())); g_renderer->RenderToTextureNoPs(); g_renderer->UnbindResourcesPS(); } }; } #endif // PostHDR_h__