[DX10] HDR Rendering - Tonemapping

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
keepcoding
Beiträge: 30
Registriert: 28.11.2003, 17:19
Kontaktdaten:

[DX10] HDR Rendering - Tonemapping

Beitrag von keepcoding »

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:

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);
}
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [DX10] HDR Rendering - Tonemapping

Beitrag von Jörg »

Ich habe jetzt deinen Code nicht angeschaut, aber hast Du denn schon einmal versucht, mit PIX dem Problem näher zu kommen? Macht sich i.A. ganz gut ...
Benutzeravatar
Schrompf
Moderator
Beiträge: 5045
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [DX10] HDR Rendering - Tonemapping

Beitrag von Schrompf »

Sorry für die späte Antwort, aber falls das Problem noch besteht: beschränke die vom PixelShader ausgegebenen Werte immer auf einen gewissen Bereich, z.B. auf 1e-5 bis 1e+5. Wenn Du z.B. irgendwo in Deinem Mesh gequetschte Texturkoordinaten hast (was bei Modellen aus dem Netz oder von unerfahrenen Grafikern sehr oft vorkommt), sind die Tangenten und Bitangenten für diese Flächen INF oder NAN. Und diese Werte propagieren dann durch die PixelShader durch, landen im Float-Rendertarget, und ziehen sich durch alle PostFX-Stufen durch. Auf dem Bildschirm siehst Du am Ende nur schwarz. Und da Du ja für HDR am Ende immer mit AlphaBlending in ein 1x1-Rendertarget schreibst, breitet sich dieses NAN auch auf die folgenden Frames aus.

[edit] Ein 16Bit-Target für die Luminanz ist natürlich albern, wenn Du vorher alles mit 32Bit-Floats renderst. Und da Du ja vorher schon unglaublich Speicherbandbreite verbrennst, kannst Du die kleinen Targets nachher problemlos auch mit 32Bit-Floats betreiben.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
keepcoding
Beiträge: 30
Registriert: 28.11.2003, 17:19
Kontaktdaten:

Re: [DX10] HDR Rendering - Tonemapping

Beitrag von keepcoding »

Danke für eure Antworten!

@Schrompf: Wow, auf so eine Idee wär ich nie gekommen! (das mit den Tangenten) Habs grad mal ausprobiert und bis jetzt hatte ich keinen schwarzen Bildschirm mehr. Werde dann nochmals berichten obs jetzt wirklich weg ist. Da ich die Werte wie du vorgeschlagen hast auf einen relativ kleinen Bereich einschränke, habe ich auf 16-Bit umgestellt (sollte völlig ausreichen, wenn ich mir die specs von 16-bit-float ansehe).

@Jörg: PIX kenn ich nicht, werd ich mir mal ansehen!
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [DX10] HDR Rendering - Tonemapping

Beitrag von Jörg »

PIX: Da du damit durch alle Direct3D-Calls vorwaerts und rueckwaerts laufen kannst und jeder Pixel einzlen debug-bar ist, findet man die problematischen Stellen i.A. sehr schnell.
keepcoding
Beiträge: 30
Registriert: 28.11.2003, 17:19
Kontaktdaten:

Re: [DX10] HDR Rendering - Tonemapping

Beitrag von keepcoding »

Auf den ersten Blick sieht das Tool ganz harmlos aus, aber das Ding ist ja ziemlich heftig :) Hab mal ein bisschen rumprobiert, wahnsinn der Debug Output! Mit ein bisschen Übung kann man den Output bestimmt relativ schnell analysieren.

Also das Problem ist wirklich verschwunden. Allerdings hab ich gemerkt, dass das Tonemapping für den Bloom-Filter noch sehr sensitiv ist, also der Himmel schnell ins Weisse überstrahlt. Auch scheint HDR einige Anpassungen an der Engine zu erfordern, damit das einigermassen ok aussieht (mit den Helligkeitswerten muss man wohl etwas vorsichtiger sein da nicht mehr schön alles abgeschnitten wird bei 1.0)...
Antworten