Isohypsen-Shader
Isohypsen-Shader
Hallo zusammen,
ich versuche derzeit, per Shader Höhenlinien in Terrains zu realisieren bzw. Bereiche oberhalb einer bestimmten Höhe farblich hervorzuheben.
Mein erster Ansatz war es, in einem VertexShader die Farbwerte ab einer bestimmten Position zu manipulieren:
Dies führt nur zu dem abgebildeten "Sägezahn" Effekt - wie kann man nun die Höheninformation auf Pixelbasis bestimmen und somit eine schärfere Kontur zeichnen bzw. gar Linien darauf realisieren?
Cheers!
ich versuche derzeit, per Shader Höhenlinien in Terrains zu realisieren bzw. Bereiche oberhalb einer bestimmten Höhe farblich hervorzuheben.
Mein erster Ansatz war es, in einem VertexShader die Farbwerte ab einer bestimmten Position zu manipulieren:
Dies führt nur zu dem abgebildeten "Sägezahn" Effekt - wie kann man nun die Höheninformation auf Pixelbasis bestimmen und somit eine schärfere Kontur zeichnen bzw. gar Linien darauf realisieren?
Cheers!
Re: Isohypsen-Shader
Wie du an die Weltkoordinate eines Pixels kommst:
Wenn du nicht schon Deferred Shading benutzt, die z-Werte erstmal in einem Pass in eine Textur schreiben. Dann ein Fullscreen-Quad mit Texturkoordinaten von 0 bis 1 über den Bildschrim legen, und beim VS fürs Rendern dann mit diesen Texturkoordinaten die z-Textur samplen (=z), und x- und y-Koordinaten (=x,y) aus den Texturkoordinaten berechnen. Diesen Vektor (x,y,z,1) dann mit der inversen Projektionsmatrix multiplizieren, und noch durch die w-Koordinate teilen.
Ich glaube zwar, es gibt schnellere Ansätze, das müsste aber so funktionieren :oops:
Wenn du dann die Weltkoordinaten erst einmal hast, kannst du damit auch die Höhe bestimmen und deine schönen Höhenlinien zeichnen ;)
Wenn du nicht schon Deferred Shading benutzt, die z-Werte erstmal in einem Pass in eine Textur schreiben. Dann ein Fullscreen-Quad mit Texturkoordinaten von 0 bis 1 über den Bildschrim legen, und beim VS fürs Rendern dann mit diesen Texturkoordinaten die z-Textur samplen (=z), und x- und y-Koordinaten (=x,y) aus den Texturkoordinaten berechnen. Diesen Vektor (x,y,z,1) dann mit der inversen Projektionsmatrix multiplizieren, und noch durch die w-Koordinate teilen.
Ich glaube zwar, es gibt schnellere Ansätze, das müsste aber so funktionieren :oops:
Wenn du dann die Weltkoordinaten erst einmal hast, kannst du damit auch die Höhe bestimmen und deine schönen Höhenlinien zeichnen ;)
- Schrompf
- Moderator
- Beiträge: 5045
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Isohypsen-Shader
Nimm doch einfach die Höhe in Weltkoordinaten und reiche die in den PixelShader rein. Dort nimmst Du die dann, um aus einer 1D-Textur zu samplen. Fertig.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Re: Isohypsen-Shader
-.- ... mir fallen anscheinend immer die umständlichsten Lösungen ein :oops: ;)Schrompf hat geschrieben:Nimm doch einfach die Höhe in Weltkoordinaten und reiche die in den PixelShader rein. Dort nimmst Du die dann, um aus einer 1D-Textur zu samplen. Fertig.
Re: Isohypsen-Shader
Hallo eXile, hallo Schrompf,
vielen Dank für die Antworten, wobei mir noch nicht ganz klar ist, wie ich aus der Höheninformation eines Vertex im PixelShader 1D-Texturen samplen kann? Wie würde denn eine solche 1D-Textur aussehen?
Viele Grüße,
IH82W8
vielen Dank für die Antworten, wobei mir noch nicht ganz klar ist, wie ich aus der Höheninformation eines Vertex im PixelShader 1D-Texturen samplen kann? Wie würde denn eine solche 1D-Textur aussehen?
Viele Grüße,
IH82W8
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Isohypsen-Shader
Hi,
n Pixel in der Breite und nur ein Pixel in der Höhe. Möchtest du in der Mitte deines Terrains eine Höhenlinie, setzt du einen Punkt in die Mitte der Textur. Im Vertex-Shader nimmst du dann die Höhe des Terrains, bringst sie durch Division durch die Maximalhöhe, die in der Textur verzeichnet ist, in den Bereich [0, 1] und benutzt das als X-Texturkoordinate.
Gruß, Ky
n Pixel in der Breite und nur ein Pixel in der Höhe. Möchtest du in der Mitte deines Terrains eine Höhenlinie, setzt du einen Punkt in die Mitte der Textur. Im Vertex-Shader nimmst du dann die Höhe des Terrains, bringst sie durch Division durch die Maximalhöhe, die in der Textur verzeichnet ist, in den Bereich [0, 1] und benutzt das als X-Texturkoordinate.
Gruß, Ky
- Aramis
- Moderator
- Beiträge: 1458
- Registriert: 25.02.2009, 19:50
- Echter Name: Alexander Gessler
- Wohnort: 2016
- Kontaktdaten:
Re: Isohypsen-Shader
Die Textur dient nur zur Beschleunigung des Ganzen, im Prinzip kannst du auch einfach mit if()'s arbeiten.
Solche if's sind aber ziemlich lahm. Ein Lookup in einer ungefilterten 1D-Textur beschleunigt das ganze - du verwendest einfach die Höhe als Texturkoordinate.
Damit du die Textur nicht zu groß machen musst, einfach den Höhenwert noch skalieren - beträgt die Maximalhöhe 100, und hast du alle 10 Höheneinheiten eine andere Farbe, so bräuchtest du eine 1x10-Textur, Lookup mit floor((in.height/100)/10).
Und da war schon wieder jemand schneller als ich.
Code: Alles auswählen
struct vout {
// [...]
float height : TEXCOORD0;
};
[...]
vout vshader (vin in) {
vout out =0;
[....]
out.height = mul(in.position,world).z;
}
float4 pshader (pin in) : COLOR {
if (in.height >= quak) {
... Farbe 1
}
else if ( ... )
.. weitere Farben
}
Code: Alles auswählen
float4 pshader (pin in) : COLOR {
...
float4 col = tex1D(mytex,in.height)
}
Damit du die Textur nicht zu groß machen musst, einfach den Höhenwert noch skalieren - beträgt die Maximalhöhe 100, und hast du alle 10 Höheneinheiten eine andere Farbe, so bräuchtest du eine 1x10-Textur, Lookup mit floor((in.height/100)/10).
Und da war schon wieder jemand schneller als ich.
Re: Isohypsen-Shader
Clever, vielen Dank zusammen!
Re: Isohypsen-Shader
Hallo nochmal,
Euer Konzept der Färbung nach Höhenstufe im PS per 1D Textur funktioniert (nicht dass ich daran gezweifelt hätte ;)).
Nun möchte ich noch eine weitere Restriktion in das Färben mit einbeziehen, sprich: Es sollen nur jene Pixel eingefärbt werden, deren Weltposition sich in einem gewissen Höhenbereich befinden und einen variablen Radius um die Kameraposition unterschreiten.
Vllt. verdeutlicht diese Grafik die Idee:
Bisher ermittle ich (wieder im eingänglicheren Vertex Shader) die Entfernung Kamera - Vertex und liefere dann wie empfohlen entsprechende Höheneinstellungen an den PS.
Da diese Abgrenzung wieder auf Basis von Vertices erfolgt, ähnelt die Region eher einem Zahnrad denn einem hübschen Kreis um die Kameraposition. Habt ihr eine Idee, wie man dies schöner lösen kann?
Danke & Grüße,
IH82W8
Euer Konzept der Färbung nach Höhenstufe im PS per 1D Textur funktioniert (nicht dass ich daran gezweifelt hätte ;)).
Nun möchte ich noch eine weitere Restriktion in das Färben mit einbeziehen, sprich: Es sollen nur jene Pixel eingefärbt werden, deren Weltposition sich in einem gewissen Höhenbereich befinden und einen variablen Radius um die Kameraposition unterschreiten.
Vllt. verdeutlicht diese Grafik die Idee:
Bisher ermittle ich (wieder im eingänglicheren Vertex Shader) die Entfernung Kamera - Vertex und liefere dann wie empfohlen entsprechende Höheneinstellungen an den PS.
Da diese Abgrenzung wieder auf Basis von Vertices erfolgt, ähnelt die Region eher einem Zahnrad denn einem hübschen Kreis um die Kameraposition. Habt ihr eine Idee, wie man dies schöner lösen kann?
Danke & Grüße,
IH82W8
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Isohypsen-Shader
Verschieb die Berechnung in den Pixel-Shader – z.B., indem du die relative Position (Weltposition - Betrachterposition) in einem Texturregister übergibst.
Wenn der Wert auf per-Pixel-Basis berechnet wird, wird der Kreis (und damit auch das Geländefolgeradar) schön sauber.
Wenn der Wert auf per-Pixel-Basis berechnet wird, wird der Kreis (und damit auch das Geländefolgeradar) schön sauber.
Re: Isohypsen-Shader
Wird diese relative Position (Vertex - Kamera) dann auf die Pixelposition (in Richtung des folgenden Vertex) transformiert, wenn ich diese einfach in ein Texturregister stecke?
- Schrompf
- Moderator
- Beiträge: 5045
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Isohypsen-Shader
Ja. Du berechnest ja im Vertex die Relativposition (VPos - KameraPos). Wenn die Grafikkarte dann Deinen PixelShader laufen lässt, interpoliert sie vorher zwischen den ProVertex-Datensätzen den für den Pixel passenden ProPixel-Datensatz. Den bekommt dann Dein PixelShader als Eingabewerte. Eine Relativposition ist problemlos linear interpolierbar. Problematischer wird es erst, wenn Du die Entfernung im VertexShader ausrechnen und in den PixelShader reinreichen willst - die Entfernungsberechnung ist ja nichtlinear (weil quadratisch und wurzelisch), daher wird die nicht sauber interpoliert. Daher auch die Empfehlung, die Positionsdifferenz in den PixelShader runterzureichen und erst im PixelShader die Entfernung auszurechnen.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Re: Isohypsen-Shader
Danke, so langsam bekomme ich eine vage Vorstellung von der fundamentalen Funktionsweise der PS.
P.S.: Hat genauso funktioniert, wie gewünscht, endlich "hübsche" Übergänge...
P.S.: Hat genauso funktioniert, wie gewünscht, endlich "hübsche" Übergänge...
Re: Isohypsen-Shader
Hallo,
eine (vorerst) letzte Frage zu dem Shader Thema bleibt... Wie auf obigen Screens zu sehen sind die Trennlinien auf obigen Screens noch sehr scharf - um diese aufzuweichen wurde ein distanzbasierter "Färbungsfaktor" eingeführt:
Kann es bei anderen Grafikkarten zu Problemen kommen, wenn die gesetzten Farbwerte (hier bspw. der Rotanteil) auf einen Wert > 1.0 gesetzt wird? Ich würde gerne die Normalisierung des Wertes einsparen, möchte aber sicher gehen, dass dies nicht zu Komplikationen führt.
Danke & Gruß!
eine (vorerst) letzte Frage zu dem Shader Thema bleibt... Wie auf obigen Screens zu sehen sind die Trennlinien auf obigen Screens noch sehr scharf - um diese aufzuweichen wurde ein distanzbasierter "Färbungsfaktor" eingeführt:
Kann es bei anderen Grafikkarten zu Problemen kommen, wenn die gesetzten Farbwerte (hier bspw. der Rotanteil) auf einen Wert > 1.0 gesetzt wird? Ich würde gerne die Normalisierung des Wertes einsparen, möchte aber sicher gehen, dass dies nicht zu Komplikationen führt.
Danke & Gruß!
- Schrompf
- Moderator
- Beiträge: 5045
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Isohypsen-Shader
Nö, kein Problem. Wenn die Grafikkarte oder das Ziel-Rendertarget das nicht kann, wird die Grafikkarte automatisch clamp()en.IH82W8 hat geschrieben: Kann es bei anderen Grafikkarten zu Problemen kommen, wenn die gesetzten Farbwerte (hier bspw. der Rotanteil) auf einen Wert > 1.0 gesetzt wird? Ich würde gerne die Normalisierung des Wertes einsparen, möchte aber sicher gehen, dass dies nicht zu Komplikationen führt.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Isohypsen-Shader
Ist Clamping (oder präziser, Saturating) nicht sowieso kostenlos?
- Richard Schubert
- Moderator
- Beiträge: 106
- Registriert: 27.02.2009, 08:44
- Wohnort: Hohen Neuendorf (b. Berlin)
- Kontaktdaten:
Re: Isohypsen-Shader
Ab Shader Model 2.0 oder 3.0 leider nicht mehr (weiß es nicht mehr genau). Das _sat Suffix für die ASM codierung wurde zu der Zeit abgeschaft.
Produktivität über Performance - XNA Creators Club
- Schrompf
- Moderator
- Beiträge: 5045
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Isohypsen-Shader
Ich *glaube*, saturate ist immernoch kostenlos. Ich habe jetzt gerade nichts da, um das nachzuprüfen, aber wenn ich mich recht erinnere, hatte fxc selbst bei Target PS3_0 noch ASM-Anweisungen mit dem _sat -Postfix produziert. Du kannst ja mal fxc auf einen Deiner Shader loslassen, wenn Du magst. Kann aber auch sein, dass die Grakas intern noch den Saturate-Modifikator unterstützen und daher der Treiber die entsprechenden Codes im Shader findet und ersetzt. Ganz am Ende würde es wahrscheinlich nur was bringen, wenn man einen PixelShader mal mit einem Rudel saturates und mal ohne bildschirmfüllend anwendet und die Framerate misst.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Isohypsen-Shader
AMD GPU Shader Analyzer zeigt an, dass der interne Assembler-Code auf einer HD 4850 mit allen Shader-Models auf gleich viele Anweisungen hinausläuft – egal ob mit Saturation oder ohne.
Ich wollte noch andere (PS-3.0-)GPUs testen, da kam dann aber ein Absturz dazwischen :/
Edit: Also, die D3D-Assembly generiert auch bei PS 3.0, 4.0 und 4.1 noch mov_sat und mul_sat. Auf allen AMD-Karten von X800 über X1900 bis HD 4870 sind die Befehlszahlen mit und ohne Saturation gleich. Wäre schön, wenn das auch jemand für Nvidia-Karten prüfen könnte.
Ich wollte noch andere (PS-3.0-)GPUs testen, da kam dann aber ein Absturz dazwischen :/
Edit: Also, die D3D-Assembly generiert auch bei PS 3.0, 4.0 und 4.1 noch mov_sat und mul_sat. Auf allen AMD-Karten von X800 über X1900 bis HD 4870 sind die Befehlszahlen mit und ohne Saturation gleich. Wäre schön, wenn das auch jemand für Nvidia-Karten prüfen könnte.