Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Dr. Best Senior JLI'ler

Alter: 35 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 09.06.2006, 20:07 Titel: Annäherung eines Kehrwerts im Pixelshader |
|
|
Tach,
ich habe im Moment ein ziemlich kniffliges Problem. Ich überarbeite meinen Parallaxmapping und Bumpmapping Shader. Ich will die Abschwächung der Lichthelligkeit über die Distanz bei Punktlichtern jetzt nicht mehr auf Vertex sondern auf Pixelbasis berechnen. Ich kann allerdings nur Pixelshader Version 1.4 und Vertexshader Version 1.1 verwenden. Und ich möchte meinen Pixel Shader drei Lichtquellen berechnen lassen. Das berechnen des Parallax Effekts kommt natürlich noch dazu.
Ich habe mir jetzt eine Methode überlegt dies zu realisieren. Das Problem ist, dass ich dazu mit sieben Arithmetischen Rechenoperationen im Pixelshader, drei Vektoren berechnen muss die die gleiche Richtung aber die invertierte Länge der drei gegebenen Vektoren haben. Es muss also folgendes Verhältnis gelten:
|x|=1/|v| und x.v=1 (der Punkt soll hier für Skalarprodukt stehen)
Wobei x der gesuchte Vektor und v der gegebene ist.
Der letzte Baustein der mir noch fehlt um dies zu erreichnen ist ein Annäherungsverfahren zur Berechnung eines Kehrwerts, das ich in einen Pixelshaderbefehl quetschen kann. Und da komm ich mit meinem erweiterten Zehntklässler Mathewissen an meine Grenzen. Ich habe bereits eine ganze Weile nach so etwas gegooglet aber bis jetzt ohne Erfolg. Etwas was so ungefähr in diese Richtung geht ist das Newton-Raphson-Verfahren. Das berechnet allerdings den Kehrwert der Wurzel und daher nützt es mir nichts, da ich nicht genug Rechenoperationen zur Verfügung habe um das Ergebnis nochmal zu quadrieren.
Also für jeden Tipp wie ich das machen könnte wäre ich sehr dankbar. Es braucht nich präzise zu sein. Ich will bloß irgendetwas was keinen erkennbaren Unterschied macht wenn man es neben Objekten sieht die kein Bumpmapping verwenden. Ich hoffe es gibt da irgendeine Methode die mir weiterhelfen kann.
Im vorraus schonmal Danke,
mit freundlichen Grüßen
Dr. Best |
|
Nach oben |
|
 |
Fallen JLI MVP


Alter: 41 Anmeldedatum: 08.03.2003 Beiträge: 2860 Wohnort: Münster Medaillen: 1 (mehr...)
|
Verfasst am: 09.06.2006, 20:40 Titel: |
|
|
Kannst du nicht die Abschwächung ausserhalb des Shaders berechnen und dem Shader die berechneten Werte als Konstanten übergeben?
Ansonsten habe ich dein Post nicht ganz verstanden beim flotten lesen. _________________ "I have a Core2Quad at 3.2GHz, 4GB of RAM at 1066 and an Nvidia 8800 GTS 512 on Vista64 and this game runs like ass whereas everything else I own runs like melted butter over a smokin' hot 18 year old catholic schoolgirl's arse." |
|
Nach oben |
|
 |
PeaceKiller JLI Master

Alter: 36 Anmeldedatum: 28.11.2002 Beiträge: 970
Medaillen: Keine
|
Verfasst am: 09.06.2006, 21:16 Titel: Re: Annäherung eines Kehrwerts im Pixelshader |
|
|
Dr. Best hat Folgendes geschrieben: | Annäherungsverfahren zur Berechnung eines Kehrwerts |
Was spricht gegen 1/x? _________________ »If the automobile had followed the same development cycle as the computer, a Rolls-Royce would today cost $100, get a million miles per gallon, and explode once a year, killing everyone inside.«
– Robert X. Cringely, InfoWorld magazine |
|
Nach oben |
|
 |
Jonathan_Klein Living Legend

Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
|
Nach oben |
|
 |
Dr. Best Senior JLI'ler

Alter: 35 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 09.06.2006, 21:38 Titel: |
|
|
@ Fallen
Nein, kann ich nicht. Die Stärke des Lichts nimmt ja über die Distanz ab. Das Licht hat einen Reichweitefaktor. Ich verwende zur Berechnung der Abnahme die Formel A=1/(r/9) wobei A der Abnahmefaktor und r die maximale Reichweite ist. So ist bei der maximalen Reichweite die Helligkeit nur noch ein neuntel so dass es nicht auffällt wenn der Kram dahinter nicht mehr belichtet wird. Aber das ist hier eigentlich ziemlich egal. Entscheidend ist, dass man die Abschwächung weder auf Meshbasis noch auf Vertexbasis berechnen kann. Die Abschwächung ist für jeden Pixel anders.
Ich verdeutliche das mal an einem Beispiel:
Man hat ein gleichseitiges Dreieck mit einer Seitenlänge von 15 und genau in der Mitte davon ist in einer Entfernung von 1 eine Lichtquelle mit einer Reichweite von 2. Berechnet man die Abschwächung auf Vertexbasis würde das Dreieck überhaupt nicht beleuchtet werden denn alle Drei Eckpunkte sind deutlich weiter als 2 von der Lichtquelle entfernt. Aber in der Mitte müsste eigentlich ein Heller Fleck sein. Deswegen muss man die Lichtabschwächung auf Pixelbasis berechnen.
@ Peacekiller
Dann sag mir mal wie ich in einem Pixelshader Version 1.4 1/x schreiben soll.
Mir stehen da nur einfache Rechenoperationen wie Addition, Multiplikation und entsprechend auch Subtraktion zur Verfügung. Ich brauche also irgendeine Formel zur Berechnung eines Kehrwerts in der keine Division auftaucht. Und sie darf nicht zu kompliziert sein denn sonst kann ich sie nicht in einen Shaderbefehl packen.
Ein gutes Beispiel für soetwas ist wie gesagt das Newton-Raphson-Verfahren. Das geht nämlich folgendermaßen (zumindest wenn ich mich jetzt nicht vertue):
1/(x)^0.5=(0.5*(1-X))+1
Man berechnet eine Wurzel und einen Kehrwert und trotzdem steht da weder ein Exponent noch ein Bruchstrich. So etwas suche ich für die Berechnung des Kehrwerts.
Edit:
@ Jona
Würde ich es verstehen würde es mir vielleicht weiterhelfen . Aber es scheint wirklich bereits ein bisschen zu kompliziert für einen Pixelshader zu sein. |
|
Nach oben |
|
 |
Jonathan_Klein Living Legend

Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 09.06.2006, 23:06 Titel: |
|
|
Tja, kannst ja mal bei Patrick im Forum fragne, ob der das hinkreigt das in nen Shader zu packen. _________________ https://jonathank.de/games/ |
|
Nach oben |
|
 |
Dr. Best Senior JLI'ler

Alter: 35 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 10.06.2006, 00:33 Titel: |
|
|
Ja, ich werde Patrick vielleicht mal fragen wenn ich's garnicht mehr hinkriege.
Aber vorher noch was für euch . Das hier verwirrt mich:
Das mit dem Newton-Raphson-Verfahren habe ich aus einem sehr lehrreichen Pixelhaderprogrammierungstutorial von Wolfgang Engel.
Da heißt es:
Code: | ; Assuming v0 contains the unnormalized biased & scaled vector ( just
; like a normal map), r0 will end up with a very close to normalized
; result.
; This trick is also useful to do 'detail normal maps' by adding
; a vector to a normal map, and then renormalizing it.
dp3 r0, v0_bx2, v0_bx2 ; r0 = N . N
mad r0, v0_bias, 1-r0, v0_bx2 ; (v0_bias * (1-r0)) + v0_bx2
; ((N - 0.5) * (1 - N.N)) + (N - 0.5) * 2 |
Wenn man v als (N-0.5)*2 (also v0_bx2) definiert dann ist die Formel die da steht folgende:
v*0.5*(1-|v|²)+v=n
Wobei n das normalisierte v ist.
Wenn ich das ganze ein bisschen umforme komme ich auf folgendes:
(-0.5*|v|²+1.5)*v=v/|v|
Und wenn ich dann noch v auf beiden Seiten wegdividiere und x als |v|² definiere bleibt das hier stehen:
-0.5*x+1.5=1/x^0.5
Aber das was da auf der linken Seite steht ist ja nichts weiter als eine lineare Funktion die den Graphen von 1/x^0.5 lediglich in einem Punkt tangiert. Sicherlich nichts was für eine ordentliche Approximation taugt (das wird ja sogar negativ). Habe ich beim umformen irgendetwas falsch gemacht oder stimmt in dieser Formel aus einem populären Tutorial tatsächlich etwas nicht ?
Ich hatte nämlich meine Hoffnung irgendeine Annäherung für den Kehrwert zu finden auf diese Formel gestützt . |
|
Nach oben |
|
 |
GreveN JLI Master

Alter: 38 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 10.06.2006, 13:55 Titel: |
|
|
Was Parick verwendet ist im Grunde dieses Snippet, welches im Internet umhergeistert:
CPP: | #define FP_ONE_BITS 0x3F800000
// r = 1/p
#define FP_INV(r,p) \
{ \
int _i = 2 * FP_ONE_BITS - *(int *)&(p); \
r = *(float *)&_i; \
r = r * (2.0f - (p) * r); \
} |
"2 * FP_ONE_BITS" lässt sich noch zusammenfassen und ist: 0x7F000000
Vielleicht etwas verständlicher für dich der Algo in dieser Form... ;)
Und das hier ist die gepimpte Version von Vincent Van Eeckhout (genau die, die Patrick auch verwendet, ist halt als Makro definiert nur Käse ;)):
CPP: | /////////////////////////////////////////////////
// The following comes from Vincent Van Eeckhout
// Thanks for sending us the code!
// It's the same thing in assembly but without this C-needed line:
// r = *(float *)&_i;
float __two = 2.0f;
#define FP_INV2(r,p) \
{ \
__asm { mov eax,0x7F000000 }; \
__asm { sub eax,dword ptr [p] }; \
__asm { mov dword ptr [r],eax }; \
__asm { fld dword ptr [p] }; \
__asm { fmul dword ptr [r] }; \
__asm { fsubr [__two] }; \
__asm { fmul dword ptr [r] }; \
__asm { fstp dword ptr [r] }; \
} |
p.s.: Wie wär's denn mit einem Mathe-Subforum für solche Fragen? |
|
Nach oben |
|
 |
Dr. Best Senior JLI'ler

Alter: 35 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 10.06.2006, 16:21 Titel: |
|
|
Ok, ich hab mich bei Wikipedia mal ein bisschen über den Aufbau von float-Variablen schlau gemacht und jetzt zumindest so ne ungefähre Ahnung davon wie dieser Algorithmus funktioniert. Leider muss ich aus diesen Erkenntnissen schließen, dass ich das in meinem Shader mit Sicherheit nicht verwenden kann . Dem GPU kann man nicht beibringen irgendetwas plötzlich nicht mehr als Fließkommazahl sondern als Integer zu interpretieren. Außerdem werden da ja komplett andere Datenformate verwendet.
Mir ist gerade noch eingefallen, dass die Möglichkeit besteht dafür zu sorgen, dass die gegebenen Vektoren, deren Länge ich umkehren will, immer eine Länge zwischen 0 und 1 haben. Das heißt die Annäherung müsste bloß in diesem Bereich ordentlich funktionieren. Ich werde mal ausprobieren wie gut folgende Annäherung funktioniert:
1/x ~= (x-1)²*4+1
Diese Formel müsste ich eigentlich im Shader umsetzen können. Vergleicht man die Graphen sieht es eigentlich auch so halbwegs ähnlich aus:
BILD
BTW, praktische Freeware.
Die Stellen die eigentlich extrem hell sein sollten werden bei dieser Annäherung dann halt nicht ganz so hell werden. Aber die Farbwerte werden hinterher ja sowieso wieder geclampt (also zwischen 0 und 1 gebracht) also fällt das mit etwas Glück nicht groß auf.
Ich lass euch dann wissen, ob und wenn ja wie gut das funktioniert.
Ein Mathe Subforum fände ich auch mal angebracht. Ist ja schließlich nicht gerade selten, dass man beim Programmieren mal auf mathematische Probleme stößt. |
|
Nach oben |
|
 |
Dr. Best Senior JLI'ler

Alter: 35 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 11.06.2006, 03:16 Titel: |
|
|
Ich habe jetzt erfolgreich folgende Formel implementiert:
(x-1)²*8 = 8x²-16x+8
Anders ging es nicht. Das funktioniert ganz ordentlich aber es weicht doch ziemlich weit von dem korrekten Ergebnis ab. Also bleibt die Frage dieses Topics im Prinzip bestehen. Also wenn irgendwer vielleicht mal zufällig über so etwas stolpert dann wäre ich dankbar wenn er's hier reinposten könnte.
Hier mal ein Screenshot. Das ganze besteht halt wirklich nur aus 24 Vertices und 12 Dreiecken. Und die Abschwächung der Lichthelligkeit über die Distanz wird auf Pixelbasis berechnet. Genau das ist es halt wozu ich irgendeine Annäherung brauchte bzw. immernoch eine bessere brauche.
Danke für eure Hilfe. |
|
Nach oben |
|
 |
GreveN JLI Master

Alter: 38 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 11.06.2006, 12:17 Titel: |
|
|
Also, wenn du das irgendwie implementieren kannst:
Zitat: | y = 4,5(x-1,2)^6+1 |
...liefert bei mir eine ziemlich brauchbare Annäherung, wenn die 6 Multiplikation bei dem Exponenten schon zu lahm sein sollten, könntest du auch mal den Exponenten 4 testen, liefert auch schon recht brauchbare Ergebnisse. Aber "nur" 2 scheint mir zuwenig zusein.
Achja: Die Konstanten waren da auch eher grobe "Schätzwerte", etwas Feintuning wirkt da vielleicht noch Wunder. |
|
Nach oben |
|
 |
Dr. Best Senior JLI'ler

Alter: 35 Anmeldedatum: 17.06.2004 Beiträge: 269 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 11.06.2006, 21:17 Titel: |
|
|
Also der Shadercode den ich jetzt verwende nutzt eigentlich schon so ziemlich alle Möglichkeiten irgendeine Rechenoperation durchzuführen, die ein Pixelshader 1.4 zu bieten hat:
Code: | // Scale each difference vector to it's approximate inverse lenth using this formula:
// 1/x ~= (x-1)²*8 = 8x²-16x+8 = ((x*x-2x)*2+2)*4
// Calculate the squared length of the first difference vector
dp3_sat r0.rgb, r3, r3
// Begin approximating the reciprocal of the first light's squared length
mad_x2 r3.a, r0.r, r0.r, -r0_x2.r
// Invert the length of the first difference vector
mad_x4 r3.rgb, r3, r3.a, r3_x2 |
Bei mehr als einer Lichtquelle verwende ich dann auch noch Instruction Pairing damit das alles passt. So etwas wie du vorgeschlagen hast ist also eindeutig zu kompliziert.
Allgeimein kann ich auf diese Weise Formeln folgender Form basteln:
m und n müssen Element der ganzen Zahlen und betragsmäßig kleiner gleich 3 sein.
p, o, q und r müssen Element der ganzen Zahlen und betragsmäßig kleiner gleich 2 sein.
( (px*ox + qx) * 2^m + r )*2^n
Versuche ich irgendwo noch Platz für weitere Rechenoperationen zu finden scheitert das daran, dass es nicht genug Register gibt um alle benötigten Werte zu speichern.
Ich habe heute nochmal den ganzen Tag versucht mit den vorhandenen Mitteln irgendeine bessere Annäherung hinzubiegen, aber bin dabei zu keinem wirklich brauchbaren Ergebnis gekommen. Also werde ich jetzt wahrscheinlich bei der Formel die ich jetzt habe bleiben. Im Moment checke ich sie noch ein bisschen auf verschiedene mögliche Probleme.
Ein Problem ist auf jeden Fall, dass die Lichtstärke wenn das Licht sehr nah kommt irgendwann wieder abnimmt. Bei x=0.2 also einem Fünftel der definierten Reichweite hat die Lichtstärke ihr Maximum erreicht. Kommt das Licht noch näher geht sie wieder gegen null wobei sie allerdings erst bei 0.016 unter eins fällt . Das ist wirklich nicht gerade optimal aber eine bessere Lösung fällt mir einfach nicht ein. Und es ist immernoch besser als Vertexbasierte Beleuchtung. Ich werde die Nutzer meiner Engine halt in der Hilfedatei darauf hinweisen müssen bei Verwendung des Per Pixel Lightings keine zu hohen Lichtreichweiten anzugeben. |
|
Nach oben |
|
 |
PeaceKiller JLI Master

Alter: 36 Anmeldedatum: 28.11.2002 Beiträge: 970
Medaillen: Keine
|
Verfasst am: 11.06.2006, 21:23 Titel: |
|
|
Mit gnuplot kannst du für beliebige Punkte und Formel Näherungswerte berechnen. _________________ »If the automobile had followed the same development cycle as the computer, a Rolls-Royce would today cost $100, get a million miles per gallon, and explode once a year, killing everyone inside.«
– Robert X. Cringely, InfoWorld magazine |
|
Nach oben |
|
 |
Fallen JLI MVP


Alter: 41 Anmeldedatum: 08.03.2003 Beiträge: 2860 Wohnort: Münster Medaillen: 1 (mehr...)
|
Verfasst am: 11.06.2006, 21:53 Titel: |
|
|
Schau dir doch hier mal die verschiedenen Verfahren an zur Berechnung der Abschwächung des Lichtes:
http://www.zanir.szm.sk/dx/016_Per_Pixel_Lighting.zip _________________ "I have a Core2Quad at 3.2GHz, 4GB of RAM at 1066 and an Nvidia 8800 GTS 512 on Vista64 and this game runs like ass whereas everything else I own runs like melted butter over a smokin' hot 18 year old catholic schoolgirl's arse." |
|
Nach oben |
|
 |
|