[ERLEDIGT] [DX9] Deferred Shading und Shadowmaps

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
DomiOh
Establishment
Beiträge: 132
Registriert: 08.10.2002, 14:44

[ERLEDIGT] [DX9] Deferred Shading und Shadowmaps

Beitrag von DomiOh »

Hallo,

ich habe jetzt bei meinem Projekt Deferred Shading implementiert. Die Beleuchtung klappt hervorragend, jedoch habe ich ein kleineres (oder vielleicht großes Problem).

Ich benutze für den G-Buffer das Format A16B16G16R16F (das Problem besteht aber auch bei A32B32G32R32F).
Ich speichere in den G-Buffer die absolute Position des gerenderten Objects, also Vertex XYZ-Koordinaten.

Die Shadowmap rendere ich in ein R32F-Target und speichere auch dort die Z-Koordinate relativ zur Lichtposition (heisst View-Matrix ohne Projektion).
So sollte ich eigentlich erreichen eine lineare Depth-Map zu erhalten.

Dann berechne ich aus meinem Lichtkegel die Projected TexCoords um auf meiner Position-Map die Position zu ermitteln.
Danach habe ich die absolute Position, die ich mit der World-Matrix des Lichts multipliziere um so die Z-Koordinate relativ zur Position des Lichts zu erhalten.
Danach multipliziere ich die so erhaltende Position noch mit der Projektionsmatrix des Lichts, damit ich die Shadow-Map via Projected Texture auslesen kann, um die Z-Werte zu vergleichen.
Trotzdem ich einen Linearen Depth-Buffer habe, bekomme ich (trotz Bias) beim Schattenwurf Artefakte, die interessanterweise nicht abhängig von der Entfernung sind (oder auch doch, wer weiß).

Dazu hier mal Bilder:
Bild
Fehler relativ nah an der Lichtquelle und nur auf dem Boden.
Bild
Auch relativ nah an der Lichtquelle und nur auf dem Boden.
Bild
Hier keine Fehler obwohl das Licht auf der Wand ziemlich weit von der Lichtquelle entfernt ist.

Hier der Shader-Code für das Rendern der Depth-Map:

Code: Alles auswählen

float4x4		wvp;			// Light World-View-Projection Matrix
float4x4		worldview;		// Light World-View-Matrix

struct vs_out
{
	float4			Pos : POSITION;
	float			TC  : TEXCOORD0;
};

struct vs_in
{
	float4			Pos : POSITION;
};

///

vs_out VS(vs_in ix)
{
	vs_out ox;
	
	ox.Pos = mul(ix.Pos, wvp);
	ox.TC  = mul(ix.Pos, worldview).z;	
	return ox;
}

float4 PS(float TC : TEXCOORD0) : COLOR
{

	return float4(TC + 0.1f,0,0,0); // + 0.1f als Bias für die Shadowmap
}
Hier mein Shader-Code für das Rendern des Lichts: (Entwicklungs-Version)

Code: Alles auswählen

float4x4		wvp;			// Camera WorldViewProjection
float4x4		shadowSpace;		// Light World
float4x4		shadowProj;		// Light Projection
float3			lPos;			// Light Position

float4x4		projectiveMatrix = 
{
	0.5f, 0.0f, 0.0f, 0.0f,
	0.0f,-0.5f, 0.0f, 0.0f,
	0.0f, 0.0f, 0.0f, 0.0f,
	0.500625f, 0.500833f, 0.0f, 1.0f
}; // Werte für Texture 800 x 600

sampler2D		tex0 : register(s0);			// Albedo.RGB
sampler2D		tex1 : register(s1);			// Normals.XYZ
sampler2D		tex2 : register(s2);			// Relative Position.XYZ
sampler2D		shadowSamp : register(s4);		// Shadowmap.R



struct vs_out
{
	float4			Pos : POSITION;
	float4			TC0 : TEXCOORD0;
};

struct vs_in
{
	float4			Pos : POSITION;
	float2			TC0 : TEXCOORD0;
};

struct ps_in
{
	float4			TC0 : TEXCOORD0;
	float4			Col : COLOR0;
};

struct ps_out
{
	float4			c0 : COLOR0;
};

///

float 	shadow2Dproj(sampler2D sTex, float4 texCoord, float objectZ, float bias)
{
	float4x4 shadowProj2 =
	{
		0.5f, 0.0f, 0.0f, 0.0f,
		0.0f, -0.5f, 0.0f, 0.0f,
		0.0f, 0.0f, 0.0f, 0.0f,
		projectiveMatrix[3][0], projectiveMatrix[3][1], 0, 1.0f
	}; // Shadowmap derzeit auch 800 x 600
	
	float objectDepth = objectZ - bias;
	texCoord = mul(texCoord, shadowProj2);
	float mapDepth    = tex2Dproj(sTex, texCoord);
	
	return mapDepth < objectDepth ? 0.0f : 1.0f;
	

}

///

vs_out VS(vs_in ix)
{
	vs_out ox;
	
	ox.Pos = mul(ix.Pos, wvp);
	ox.TC0 = ox.Pos;
	
	return ox;
}

ps_out PS(ps_in ix)
{
	ps_out ox;

	ix.TC0 = mul(ix.TC0, projectiveMatrix);
	
	float3 nrm = tex2Dproj(tex1, ix.TC0);
	float3 pos = tex2Dproj(tex2, ix.TC0);
	
	float4 shadowSpacePos = mul(float4(pos,1), shadowSpace);
	float4 shadowUV = mul(shadowSpacePos, shadowProj);
	float noShadow = shadow2Dproj(shadowSamp, shadowUV, shadowSpacePos.z, 0);
	
	if (noShadow == 0) discard;
		
	float3 nrmDir = (lPos-pos);
	float lgt = length(nrmDir);
	float att = 1.f / (0 + 0.25f*lgt + 0*lgt*lgt);
	
	if (att == 0) discard;

	
	float litx = dot(nrm, normalize(nrmDir));
	
	ox.c0 = saturate(float4(1,1,1,1) * litx * att);
	
	return ox;
}

///

Wo liegt da das Problem?? Ich sehe es einfach nicht.
Zuletzt geändert von DomiOh am 07.10.2009, 23:05, insgesamt 1-mal geändert.
DomiOh
Establishment
Beiträge: 132
Registriert: 08.10.2002, 14:44

Re: [DX9] Deferred Shading und Shadowmaps

Beitrag von DomiOh »

Hat sich erledigt. Ich habe das Problem lösen können. Ich habe vegessen, bei der ShadowMap lineares Filtering einzuschalten.
Kaum eingeschaltet reicht ein BIAS von 0.05
Benutzeravatar
Zudomon
Establishment
Beiträge: 2273
Registriert: 25.03.2009, 07:20
Kontaktdaten:

Re: [ERLEDIGT] [DX9] Deferred Shading und Shadowmaps

Beitrag von Zudomon »

Das Problem, welches du ansprichst liegt in der Natur einer Shadowmap. Wie sich das Ergebnis durch das lineare Filtern verhält kann ich nicht einschätzen.
Die Streifen haben damit zu tun, das die Fläche, auf die der Schatten fällt einen geringen Einfallswinkel im Bezug zur Lichtquelle hat. Die Shadowmap repräsentiert ja die Geometrie. Allerdings wegen der begrenzten Auflösung nur quantisiert. Wenn du nun eine Wand hast, die fast Senkrecht zur Lichtquelle steht, dann wird die ganze Wand durch sehr wenig Pixel in der Shadowmap repräsentiert. D.h. ein Pixel in der Shadowmap repräsentiert nun z.B. mehrere Meter der Wand... allerdings nur mit einem einzigen Tiefenwert.

Das Problem lässt sich einigermaßen lösen, wenn man den Bias auch vom Einfallswinkel abhängig macht.
DomiOh
Establishment
Beiträge: 132
Registriert: 08.10.2002, 14:44

Re: [ERLEDIGT] [DX9] Deferred Shading und Shadowmaps

Beitrag von DomiOh »

Ja schon klar. Danke für die Antwort. Allerdings habe ich das Problem tatsächlich durch das lineare Filtern in den Griff bekommen.
Ich hatte vorher über vorberechnete Shadow-Volumes nachgedacht, das ganze aber verworfen, da es da echt Probleme mit Transparenz und Objekten gibt, die z.b. Löcher haben, wo der Schatten dann durchscheinen müsste.

Das ganze ist für meine Szene nicht sehr praktikabel, also habe ich mich für eine Shadowmap-Lösung entschieden.
Antworten