[DX10] HDR Rendering - Tonemapping
Verfasst: 04.06.2010, 22:06
Hi
Hab mich mal mit HDR versucht, allerdings scheint es noch nicht richtig zu klappen (z.B. wird der Bildschirm oft schwarz, wenn ich die Kamera schwenke und bleibt auch danach schwarz). Ich habe mir verschiedene Beispiele angesehen, bei denen jeweils ein etwas anderer "Ansatz" gewählt wurde. Nun bin ich mir nicht mehr so sicher, ob ich das richtig implementiert und verstanden habe. Ich wäre da für ein paar Tipps dankbar.
Vorgehen:
- Szene in 128-Bit RT rendern
- downscale: den log-Wert in ein 256x256er RT mit zwei 16-Bit Kanälen (r für den durchschnittlichen Luminanzwert, g für den maximalen Luminanzwert) schreiben
- downsamplen bis 1x1 Pixel, jeweils den durchschnittlichen und maximalen Wert speichern
- exp() auf das Ergebnis anwenden und Lichtadaption durchführen
- Tonemapping
Ach ja, macht ein 16-bit-Format überhaupt Sinn wenn ich 32-bit für das Haupt-RT verwende?
Hier mal etwas Code:
Hab mich mal mit HDR versucht, allerdings scheint es noch nicht richtig zu klappen (z.B. wird der Bildschirm oft schwarz, wenn ich die Kamera schwenke und bleibt auch danach schwarz). Ich habe mir verschiedene Beispiele angesehen, bei denen jeweils ein etwas anderer "Ansatz" gewählt wurde. Nun bin ich mir nicht mehr so sicher, ob ich das richtig implementiert und verstanden habe. Ich wäre da für ein paar Tipps dankbar.
Vorgehen:
- Szene in 128-Bit RT rendern
- downscale: den log-Wert in ein 256x256er RT mit zwei 16-Bit Kanälen (r für den durchschnittlichen Luminanzwert, g für den maximalen Luminanzwert) schreiben
- downsamplen bis 1x1 Pixel, jeweils den durchschnittlichen und maximalen Wert speichern
- exp() auf das Ergebnis anwenden und Lichtadaption durchführen
- Tonemapping
Ach ja, macht ein 16-bit-Format überhaupt Sinn wenn ich 32-bit für das Haupt-RT verwende?
Hier mal etwas Code:
Code: Alles auswählen
float g_fGaussianScalar = 0.6;
float4 PSDownScaleLum(PS_INPUT input) : SV_Target
{
float fAverageLog = 0.0f;
float fMaxLog = -1e20;
float4 Color = 0.0f;
float2 Offsets[4] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 };
float fAtt = getVignetting(input.Tex, 1.6);
for (int i = 0; i < 4; i++)
{
Color = g_TexScene.SampleLevel(LinSamplerClamp, input.Tex + g_TexelSize * 2.0 * Offsets[i], 0);
float fGreyVal = log(1e-5 + dot(Color.rgb, g_LumConv) * fAtt);
fMaxLog = max(fMaxLog, fGreyVal);
fAverageLog += fGreyVal;
}
return float4(fAverageLog * 0.25f, fMaxLog, 0.0f, 0.0f);
}
float4 PSDownSampleLum(PS_INPUT input) : SV_Target
{
float fAverage = 0.0f;
float fMax = -1e20;
for (int v = 0; v < 4; v++)
{
for (int u = 0; u < 4; u++)
{
float2 Color = g_TexScene.SampleLevel(LinSamplerClamp, input.Tex + g_TexelSize * float2(u, v), 0).rg;
fAverage += Color.r;
fMax = max(fMax, Color.g);
}
}
fAverage /= 16.0f;
return float4(fAverage, fMax, 0.0f, 0.0f);
}
float4 PSToneMappingAdapted(PS_INPUT input) : SV_Target
{
// Read the HDR value that was computed as part of the original scene
float4 HDRColor = g_TexScene2.SampleLevel(LinSamplerClamp, input.Tex, 0);
float4 Bloom = g_TexScene.SampleLevel(LinSamplerClamp, input.Tex, 0);
// durchschnittliche und maximale Luminanz aus der 1x1-Pixel-Textur lesen
float2 Lum = g_TexLum.SampleLevel(LinSamplerClamp, float2(0.5f, 0.5f), 0).rg;
float fHDRLum = dot(HDRColor.rgb, g_LumConv);
// -- folgender Code nach Reinhard's tone mapping equation --
float fExposure = 0.18;
float fLumRel = (fExposure / (1e-5 + Lum.r)) * fHDRLum; // Luminance scaled
float fLumWSqr = (Lum.g + g_fGaussianScalar * Lum.g);
fLumWSqr = fLumWSqr * fLumWSqr;
float fToneScalar = (fLumRel * (1.0f + (fLumRel / fLumWSqr))) / (1.0f + fLumRel);
float4 LDRColor = HDRColor * fToneScalar;
return float4(LDRColor.rgb, 1.0);
}
float4 PSLuminanceAdaptation(PS_INPUT input) : SV_Target
{
float2 AdaptedLum = g_TexLum.Sample(LinSamplerClamp, float2(0.5f, 0.5f)).rg;
float2 CurrentLum = g_TexLum2.SampleLevel(LinSamplerClamp, float2(0.5f, 0.5f), 20).rg;
CurrentLum = float2(exp(CurrentLum.r), exp(CurrentLum.g));
float p = 1.0f;
return float4(AdaptedLum + (CurrentLum - AdaptedLum) * (1 - exp(-g_fElapsedTime * (p * .2 + (1 - p) * .4))), 0.0, 0.0);
}