Water rendering

Einstiegsfragen, Mathematik, Physik, künstliche Intelligenz, Engine Design
Antworten
stalker
Beiträge: 9
Registriert: 28.10.2009, 11:04

Water rendering

Beitrag von stalker »

Hallo,

Bei einem Projekt, das unter DirectX 10 entwickelt wird, möchte ich gern water rendering realisieren.
Dazu hab ich folgende Fragen und hoffe jemand kann mir da weiterhelfen.

1) Wie kann ich eine Wasseroberfläche am besten realisieren, damit ich Wellenanimationen einbauen kann und damit es auch bei großen Terrain noch performant ist?
ZB: Wenn ich jetzt ein Terrain (1024x1024, Zellenweite 2) und ein Wasser(512x512, Zellenweite sag ma mal 8) erstelle. Somit befindet sich um das ganze Terrain, Wasser. Das Problem ist aber, dass es nicht wirklich Performant ist, da es aus vielen Vertizen besteht und ich jedes Frame die Normalen und Positionsdaten in Y neu berechnen muss. Gibt es hier Techniken, die zu bevorzugen wären?
Beim FarCry Editor ist mit aufgefallen, dass das Wasser aus einem runden Grid besteht und dass das Grid immer mit der Kamera mitwandert. Desweiteren befindet sich meiner Meinung nach noch ein weiteres Grid unterhalb des wandernden, das aber nicht mitwandert(bin mir aber nicht sicher). Ist das korrekt so bzw kann mir das wer etwas genauer erklären?

2) Die größeren Wellen möchte ich gern per Vertexmanipulation(wie oben beschrieben) realisieren. Die klieneren Wellen mittels normal mapping. Wie kann ich jetzt mittels normal mapping einen Wellengang simmulieren?

3) Sind diese Ansätze Grundsätzlich eine gute Wahl. Oder gibt es bessere?

Wichtig wäre mir, dass das Wasser im Endeffekt gut ausschaut und das ich es auch für Terrains in der Grössenordnung von ca 8000x8000 verwenden kann.
stalker
Beiträge: 9
Registriert: 28.10.2009, 11:04

Re: Water rendering

Beitrag von stalker »

/push

Hat keiner eine Idee?
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: Water rendering

Beitrag von Aramis »

Das Problem ist aber, dass es nicht wirklich Performant ist, da es aus vielen Vertizen besteht und ich jedes Frame die Normalen und Positionsdaten in Y neu berechnen muss. Gibt es hier Techniken, die zu bevorzugen wären?
Das jedes Frame auf's neue mit der CPU zu machen ist ein Performancekiller erster Güte .. Ich würde auf VTF (Vertex Texture Fetch) setzen und die Wellenbewegung im Vertex-Shader auf die Geometrie anwenden. Dann im Pixel-Shader 1-n, über mehrere Frames animierte, kleinere Normal-Maps interpolieren um die Feinstruktur rauszuholen. Wenn diese Normal-Maps jeweils Wellenstrukturen unterschiedlicher Frequenz abbilden, solltest du insgesamt eine ziemlich realistische Wellensimulation rauskriegen. Wie du die dann dazu kriegst, dass sie auf ihre Umgebung reagiert, sich z.B. Wellen zum Ufer hin brechen, ist eine andere Sache.
stalker
Beiträge: 9
Registriert: 28.10.2009, 11:04

Re: Water rendering

Beitrag von stalker »

Die Wellenberechnungen will ich eigentlich eh auf der GPU durchführen. Das Problem was ich so seh ist, dass ich bei einem 8192x8192(x2 Zellweite) Terrain eine Wasseroberfläche von ca 2024x2024x8 brauche. Das wären dann 4194304 Vertizen, die zu animieren sind.

NormalMaps:
Thx. Aber wie funktioniert das jetzt genau.
Soll ich die einzelnen Normalmaps auch Animieren? Sprich, Sie jetzt auf und ab schwingen lassen. Kann ich das einfach so machen, dass ich die Normalmap jedes Frame mit einem anderen Wert zwischen -1.0 und 1.0 multipliziere. Dann hab ich aber ein Problem, wenn ich in einem Frame das ganze mit 0 multipliziere. Dann werden alle Normalen ja 0.
Oder soll ich einfach mehrere Normalmaps mit unterschiedlichen Geschwindigkeiten übers Wasser laufen lassen, damit der Welleneffekt entsteht? Das Problem was ich hier seh ist, das es nicht nauürlich ausschaut, weil ich ja nichts animiere, sondern nur die Texturen mit unterschiedlichen Geschwindigkeiten laufen lasse.
Benutzeravatar
exploid
Establishment
Beiträge: 146
Registriert: 21.08.2005, 18:33

Re: Water rendering

Beitrag von exploid »

...
Zuletzt geändert von exploid am 04.11.2010, 14:04, insgesamt 1-mal geändert.
All your base are belong to us! Justice
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: Water rendering

Beitrag von Aramis »

Spontan wäre meine Idee, sowohl die Wellentextur doppelt zu animieren (z.B. durch Unterbringung von 16 Einzelframes in einer großen [Volumen]Textur), als auch die Textur über das Wasser gleiten zu lassen. Ob es gut bzw. realitätsnah aussehen würde, kann ich nicht sagen. Aber vermutlich ist es ein guter Startpunkt.
Das Problem was ich so seh ist, dass ich bei einem 8192x8192(x2 Zellweite) Terrain eine Wasseroberfläche von ca 2024x2024x8 brauche. Das wären dann 4194304 Vertizen, die zu animieren sind
Naja, du musst sie ja nicht alle rendern, sie sind ja sowieso nicht alle sichtbar, und die meisten Sichtbaren sind auch nicht so nah dass aufwändige Animationen nötig sind .. schlussendlich kommen die selben Datenstrukturen in Frage wie für Terrains ... LOD .. adaptiv in quadratische Patches unterteilen, Clipmaps. Letztere könnten sich vom Prinzip her mit deiner Beobachtung von FarCry decken.
stalker
Beiträge: 9
Registriert: 28.10.2009, 11:04

Re: Water rendering

Beitrag von stalker »

Das Ooze.rfx Beispiel ist wirklich gut. Genau sowas hab ich gesucht. Jetzt kann ich mir das auch gleich viel leichter vorstellen.
Nun kommt aber noch ne andere Frage auf. Kennt Ihr auch Programme, mit denen ich so eine volumetrische Textur selbst erstellen kann?
Da gehts mir primär um das, dass die Textur in jeder Ebene automatische manipuliert wird und sich so von Ebene zu Ebene leicht ändert. Ich mein, ich will jetzt zb keine 256 Texturen von Hand berabeiten. Das wär etwas stressig und zeitraubend :). Den Rest(zusammenfügen aller Ebenen zu einer volumetrischen Textur) mach ich dann mittels Photoshop oder DirectX Texture Tool.

Ich werd das mal so wie von euch beschrieben mittels mehrerer volumetrischer Texturen + langsame Bewegung der Texturen realisieren. Was ich bei diesem einem Beispiel so gesehen habe, dürfte das recht gut ausschauen. Und das Wasser unterteil ich in quadratische Patches und rendere sie aus einem Quadtree heraus. Clipmaps sind mir momentan noch etwas zu viel. Aber danke für den Tipp. Werd mir das mal später durch den Kopf gehen lassen.
stalker
Beiträge: 9
Registriert: 28.10.2009, 11:04

Re: Water rendering

Beitrag von stalker »

Hallo nochmal,

Hab mich mit den Volummaps etwas beschäftigt, da ich diese zum ersten mal verwende. Nun steh ich vor einem Problem, dass mir unlogisch erscheint und dass ich auch nicht Lösen konnte. Ich hoffe, irgendwer kann mir da weiterhelfen.

Wenn ich in meinem Shadercode auf die einzelen Schichten der Textur zugreifen will, bekomm ich folgenden Effekt:
http://s11b.directupload.net/images/091124/yhzpt9bg.jpg

Und hier nochmal, das Laden der Textur in DirectX 10:

Code: Alles auswählen

	ID3D10ShaderResourceView* pTextureRV = NULL;
	ID3D10Texture3D* pTexture = NULL;

	D3DX10CreateTextureFromFile(g_D3DDevice, L".\\Content\\Texture\\Water\\volTexture1.dds", NULL, NULL, (ID3D10Resource**)&pTexture, NULL);
	
	D3D10_TEXTURE3D_DESC TexDesc;
	pTexture->GetDesc(&TexDesc);

	D3D10_SHADER_RESOURCE_VIEW_DESC SRVDesc;
	ZeroMemory(&SRVDesc, sizeof(SRVDesc));
	SRVDesc.Format = TexDesc.Format;
	SRVDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE3D;
	SRVDesc.Texture3D.MipLevels = TexDesc.MipLevels;

	g_D3DDevice->CreateShaderResourceView(pTexture, &SRVDesc, &pTextureRV);

	pDDTextureVariable = pEffect->GetVariableByName("ddTexture")->AsShaderResource();
	pDDTextureVariable->SetResource(pTextureRV);
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Water rendering

Beitrag von Krishty »

Sollte die dritte Koordinate nicht relativ (im Bereich zwischen 0 und 1) sein, wie die beiden anderen auch?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
stalker
Beiträge: 9
Registriert: 28.10.2009, 11:04

Re: Water rendering

Beitrag von stalker »

Meinst du leicht.
Ebene 1: zwischen 0 und 0.25
Ebene 2: 0.25-0.5
usw.

?
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Water rendering

Beitrag von Krishty »

Warum zwischen zwei Ebenen gefiltert wird kann ich aber nicht sagen, denn normalerweise sollte 1.0 ausschließlich die vierte Ebene darstellen – seit D3D10 gibt es keine Texel-Offsets mehr, d.h. Ebene 0 geht von -0.125 bis +0.125, Ebene 1 von 0.125 bis 0.375 usw.

Die Adressierung der ersten Ebene durch 0, der zweiten Ebene mit 1 usw wird bei Arrays von 2D-Texturen benutzt, nicht bei 3D-Texturen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
stalker
Beiträge: 9
Registriert: 28.10.2009, 11:04

Re: Water rendering

Beitrag von stalker »

Habs jetzt verstanden wies funktioniert.
Für die erste Schicht nehm ich 0.125, zweite Schicht 0.375, usw.
Da wär ich von selbst wohl nie draufkommen. Thx.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Water rendering

Beitrag von Krishty »

Wirklich, funktioniert das? Da müssen echt 0.125 Offset drauf? Verrückte Welt.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
stalker
Beiträge: 9
Registriert: 28.10.2009, 11:04

Re: Water rendering

Beitrag von stalker »

Scheint zu funktionieren -> Habs jetzt mit allen vier Ebenen probiert und es funktioniert.
0.125
0.375
0.625
0.875

Hoff, das bleibt auch so wenn ich mehrere Ebenen benutze :) (mit anderen Werten halt).
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Water rendering

Beitrag von Schrompf »

Keine verrückte Welt, sondern endlich mal Klarheit. Stell Dir das wie folgt vor:

Code: Alles auswählen

 +-----+-----+-----+-----+
 |.....|.....|.....|.....|
 +-----+-----+-----+-----+
0,0..0,25..0,5..0,75..1,0
Der linke Texel erstreckt sich im Koordinatenbereich also von 0.0 bis 0.25. 0.0 ist die linke Kante des ersten Texels, 1.0 ist die rechte Kante des letzten Texels. Damit ist dann auch klar, wie diese Koordinatenbereiche zustandekommen, und es ist auch klar, warum 0.125 die Mitte des ersten Texels darstellt. Google mal nach "Directly mapping texels to pixels". Das ist ein Artikel aus dem DX-SDK, allerdings noch für DX9 geschrieben. Und da steht u.a. auch beschrieben, dass bis DX9 die Bildschirmkoordinaten-Rechnung so ein Offset hatte, man also tatsächlich einen halben Pixel abziehen musste, um die Mitte des linken oberen Bildschirmpixels zu treffen. Mit DX10 ist das zum Glück Geschichte.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Water rendering

Beitrag von Krishty »

Schrompf hat geschrieben:Mit DX10 ist das zum Glück Geschichte.
Eben! Er benutzt doch D3D10 – und dort sind die Texturkoordinaten doch so angeordnet:

Code: Alles auswählen

---+------+------+------+---
...|......|......|......|...
---+------+------+------+---
0,0..0,25....0,5...0,75...1,0
Bzw. sollten so angeordnet sein. Das Offset hatten bei D3D9 nicht die Bildschirm-, sondern die Texel-Koordinaten, und zwar immer genau einen halben Texel.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Water rendering

Beitrag von Schrompf »

Krishty hat geschrieben:
Schrompf hat geschrieben:Mit DX10 ist das zum Glück Geschichte.
Eben! Er benutzt doch D3D10 – und dort sind die Texturkoordinaten doch so angeordnet:

Code: Alles auswählen

---+------+------+------+---
...|......|......|......|...
---+------+------+------+---
0,0..0,25....0,5...0,75...1,0
Bzw. sollten so angeordnet sein. Das Offset hatten bei D3D9 nicht die Bildschirm-, sondern die Texel-Koordinaten, und zwar immer genau einen halben Texel.
Äh... nein! Die Texturkoordinaten sind weiterhin vernünftig ausgelegt, so wie ich das beschrieben habe. Die Bildschirmkoordinaten waren unter DX9 so wie in Deinem Beispiel, sind unter DX10 aber endlich auch wie die Texturkoordinaten ausgerichtet. Unter DX9 war beim Rendern auf den Bildschirm noch ein Offset von -0.5 Pixeln nötig, unter DX10 ist kein Offset mehr nötig.

[edit] Situation unter DX9 siehe hier: http://blogs.msdn.com/jsteed/articles/209220.aspx
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Water rendering

Beitrag von Krishty »

Stimmt: http://msdn.microsoft.com/en-us/library/ee415731.aspx
Da hatte ich wohl was fundamental missverstanden …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
stalker
Beiträge: 9
Registriert: 28.10.2009, 11:04

Re: Water rendering

Beitrag von stalker »

Hi,
hab wieder mal ein Problem mit dem Rendern des Wassers.

Und zwar simulier ich mittels einer sin/cos Berechnung, Wellen.
Wenn ich jedes Farme die Normalen und Tangenten auf der CPU berechne und diese dann zum Shader schicke, funktioniert alles bestens.

Will ich diese jetzt auf der GPU im GeometryShader berechnen lassen, funktioniert es nicht. Die ganze Szene schaut einfach schei.e aus. Ich verwende aber die selben Formeln, wie auch auf der CPU.

Hier mal der wichtigste Teil des Shader-Codes, bei Berechnung der Normalen und Tangenten auf der CPU (Hier schaut das Wasser nach dem Rendern richtig aus):

Code: Alles auswählen

PS_INPUT VS(float4 Pos : POSITION, float3 Norm : NORMAL, float3 Tangent : TANGENT, float3 TangentS : TANGENT, float4 Color : COLOR, float2 Tex1 :TEXCOORD0, float2 Tex2 :TEXCOORD1)
{
PS_INPUT psInput;

	.
	.

	psInput.Pos = mul( Pos, WVPMatrix);	//WVPMatrix ist eine WorldViewProjection Matrix
	psInput.Norm = normalize(mul(Norm, (float3x3)World));
	psInput.Tangent = mul(Tangent, (float3x3)World);
	psInput.WorldPos = mul(Pos, World);
	
	.
	.
	
	return psInput;
}

Und hier der Code, wenn ich das ganze jetzt auf der GPU berechnen will. Wie gesagt, im Geometry Shader verwend ich die selben Formeln, wie auch auf der CPU.
Ich bin mir nicht sicher ob ich richtig liege. Aber wenn [maxvertexcount(3)] bedeutet, dass der Geometryshader die drei zusammengesetzten Vertizen eines Dreieckes bekommt, sollte es doch funktionieren.

Code: Alles auswählen

PS_INPUT VS(float4 Pos : POSITION, float3 Norm : NORMAL, float3 Tangent : TANGENT, float3 TangentS : TANGENT, float4 Color : COLOR, float2 Tex1 :TEXCOORD0, float2 Tex2 :TEXCOORD1)
{
PS_INPUT psInput;

	.
	.

	psInput.Pos = Pos;	//WVPMatrix ist eine WorldViewProjection Matrix
	psInput.Norm = Norm;
	psInput.Tangent = Tangent;
	psInput.WorldPos = Pos;
	
	.
	.
	
	return psInput;
}

Code: Alles auswählen

[maxvertexcount(3)]
 void GS( triangle GS_INPUT input[3], inout TriangleStream<PS_INPUT> TriStream)
 {    
	 PS_INPUT output;
	
 	//calc normal
	float3 temp_v1 = input[1].Pos.xyz - input[0].Pos.xyz;
	float3 temp_v2 = input[2].Pos.xyz - input[0].Pos.xyz;
	float3 normal = cross(temp_v1, temp_v2);
	
	//calc tangent
	float3 tangent;
	float3 Edge1uv = float3(input[1].Tex.x, input[1].Tex.y, 0.0f) - float3(input[0].Tex.x, input[0].Tex.y, 0.0f);
	float3 Edge2uv = float3(input[2].Tex.x, input[2].Tex.y, 0.0f) - float3(input[0].Tex.x, input[0].Tex.y, 0.0f);

	float cp = Edge1uv.y * Edge2uv.x - Edge1uv.x * Edge2uv.y;

	if (cp != 0.0f) 
	{
		float mul = 1.0f / cp;

		tangent  = normalize( (temp_v1 * -Edge2uv.y + temp_v2 * Edge1uv.y) * mul );
	}
	 
 

	 for(int i=0; i<3; i++)
	 {
		 output.Pos = mul( input[i].Pos, WVPMatrix);
		 output.Norm = normalize(mul(normal, (float3x3)World));
		 output.Tangent = mul(tangent, (float3x3)World);
		 output.Tex = input[i].Tex;
		 output.TexS = input[i].TexS;
		 output.Tex2 = input[i].Tex2;
		 output.TexS2 = input[i].TexS2;
		 output.Color = input[i].Color;
		 output.Depth = input[i].Depth;
		 output.WorldPos = mul(input[i].Pos, World);
		 output.TangentS = input[i].TangentS;

		 TriStream.Append( output );	 
	 }
	 
	 TriStream.RestartStrip(); 
 }

Und hier noch mal ein Bild, wie es in beiden Fällen ausschaut. Die Wellen sind mit absicht so Übertrieben, damit das FAIL besser in geltung kommt.
Bild
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Water rendering

Beitrag von Jörg »

Schaut fuer mich danach aus, als ob du auf der CPU smooth-normals (also gemittelt ueber alle angrenzenden Dreiecke) verwendest. Das bekommst Du nach deinem aktuellen Code im GS natuerlich nicht hin , da du ja nur eine Normale pro Flaeche bestimmst...wie du auf der CPU die Normalen berechnest, hast Du ja nicht gezeigt...
Schau Dir mal Alternativen zur Normalenberechnung an...Stichwort Jacobi-Matrix.
Antworten