Kreuz- und Skalarprodukt, welcher Operator?
-
Ich schreibe gerade eine Vektorklasse für eine 3D Anwendung und frage mich gerade welche Operatoren ich für das Kreuz- und das Skalarprodukt überladen soll. Gibt es da einen inoffiziellen Standard?
-
Wie waere es mit freien Funktionen?
-
knivil schrieb:
Wie waere es mit freien Funktionen?
-
Welchen Vorteil bringen die freien Funktionen?
-
Welchen Vorteil bringt dir eine Methode bzw. ein Operator gegenueber 'cross_prod' oder 'scalar_prod'? Dann gibt es auch noch die Multiplikation mit Zahlen. Angenommen du moechtes v*5 schreiben -> geht mittels Methode. Aber 5*v kannst du nicht als Methode implementieren. Und konsequenterweise wuerde ich die anderen beiden auch als freie Funktionen implementieren.
-
Ich glaub, das war nicht seine Frage. knivil hat erklärt, warum man Operatoren eher als freie Funktionen und nicht als Methoden implementieren sollte.
Aber ich glaub, die Frage war eher, welchen Operator man verwenden sollte. Sowohl Skalarprodukt als auch Vektorprodukt bekommen als Eingabe zwei Vektoren, alsov * v
Und irgendwie muss man das ja unterscheiden, da braucht man zwei Operatoren.
Ich hab keine Ahnung, was man dafür nehmen könnte, mir fällt jetzt spontan nichts ein.
-
Wenn man wirklich unbedingt Operatoren haben will, dann wäre wohl * für dot() und ^ für cross() noch die gängigste Variante. Ich persönlich würd aber einfach keine Operatoren dafür verwenden, sondern zwei freie Funktionen und fertig...
-
Ich würde zwei freie (normale, nicht-operator) Funktionen machen, und dann nen
operator *
der diedot
-Funktion aufruft.
Zusätzlichoperator *
Überladungen für Skalare.operator ^
fürcross
kommt mir komisch vor, würde ich daher weglassen.
-
hab oeffter gesehen dass man % fuer cross und ^ fuer scalar product nutzt (weil ^ quasi ein winkel berechnet.
* wuerde ich als multiplikation behalten, da es nicht komplett absurd ist, dass man vektoren auch skaliert z.b. kann man dieselbe lib auch fuer farben nutzen.zudem, auch wenn es nicht offensichtlich erscheint erstmal, wuerde ich bei vector operatoren auch immer nur vector parameter akzeptieren und zurueckgeben, weil man dann durchgaengig auf SIMD arbeiten kann, ansonsten kann es oefter vorkommen dass man aus simd zu float konvertiert nur um dann wieder auf simd zu konvertieren
z.b. normalisieren eines vectors
n=n/sqrt(n^n);
-
rapso schrieb:
hab oeffter gesehen dass man % fuer cross und ^ fuer scalar product nutzt (weil ^ quasi ein winkel berechnet.
* wuerde ich als multiplikation behalten, da es nicht komplett absurd ist, dass man vektoren auch skaliert z.b. kann man dieselbe lib auch fuer farben nutzen.Was spricht dagegen * für normale Multiplikation und Dot-Product zu verwenden?
Is ja beides ein Produkt, wird in der Mathematik beides mit * geschrieben (bzw. auch beides mit weglassen des Operator-Zeichens).
Und es kann ja auch zu keiner Zweideutigkeit kommen - wenn man dotten kann kann man net multiplizieren und umgekehrt.Und natürlich skaliert man Vektoren auch öfter mal. Auch ganz normale Punktvektoren oder Richtungsvektoren, nicht bloss Farben.
-
hustbaer schrieb:
rapso schrieb:
hab oeffter gesehen dass man % fuer cross und ^ fuer scalar product nutzt (weil ^ quasi ein winkel berechnet.
* wuerde ich als multiplikation behalten, da es nicht komplett absurd ist, dass man vektoren auch skaliert z.b. kann man dieselbe lib auch fuer farben nutzen.Was spricht dagegen * für normale Multiplikation und Dot-Product zu verwenden?
siehe markeirung
Is ja beides ein Produkt, wird in der Mathematik beides mit * geschrieben (bzw. auch beides mit weglassen des Operator-Zeichens).
Und es kann ja auch zu keiner Zweideutigkeit kommen - wenn man dotten kann kann man net multiplizieren und umgekehrt.vec4 Normal=Normalmap... vec4 Color=Texture... vec4 Diffuse=Light*Normal; vec4 FinalColor=Color*Diffuse;
woher weiss der compiler bei dir hier dass ersteres ein dot fuer lichtintensitaet ist, beim zweiten * kein dot gewollt ist?
oder meinst du man muesste eine extra klasse fuer sowas schreiben die recht gleich ausschaut, lediglich ein paar operatoren unterschiedlich hat, notfalls mit basisklasse? und dann sieht man im code mehrere * und muss immer checken welche typen involviert sind?
falls man nur trigonometrie berechnen will, ist es wohl wuppe, fuer graphik-/spieleprogrammierung ist ein vector mul wie auch dot finde ich gleichermassen wichtig, so erklaere ich mir den operator gebrauch von % und ^ in einigen libs.
-
OK, jetzt verstehe ich was du meinst.
Wobei ich das Beispiel schlecht finde.
Das Ergebnis von nem dot ist ein Skalar, kein Vektor. Also tut man es auch in einen Skalar reinmachen:vec4 Normal=Normalmap... vec4 Color=Texture... float Diffuse=Light*Normal; vec4 FinalColor=Color*Diffuse;
Und schon passt alles wieder.
Natürlich gibt es bei Farb-Berechnungen auch Fälle wo man wirklich zwei Vektoren (Farben) komponentenweise multiplizieren will (muss). Daran hatte ich nicht gedacht.
oder meinst du man muesste eine extra klasse fuer sowas schreiben die recht gleich ausschaut, lediglich ein paar operatoren unterschiedlich hat, notfalls mit basisklasse? und dann sieht man im code mehrere * und muss immer checken welche typen involviert sind?
*schauder*, nein
Wenn dann ne freie Funktion definieren die das komponentenweise multiplizieren übernimmt - unabhängig vom Typ.Vermutlich ist es aber mittlerweile schlauer sich an bestehende Dinge wie HLSL/Cg zu halten... und dort ist * ja glaube ich immer komponentenweise.
-
hustbaer schrieb:
Vermutlich ist es aber mittlerweile schlauer sich an bestehende Dinge wie HLSL/Cg zu halten... und dort ist * ja glaube ich immer komponentenweise.
In HLSL ja, in GLSL ist * bei zwei Vektoren komponentenweise, wenn mindestens ein Operand eine Matrix ist, dann ist es eine Matritzenmultiplikation...
-
hustbaer schrieb:
Natürlich gibt es bei Farb-Berechnungen auch Fälle wo man wirklich zwei Vektoren (Farben) komponentenweise multiplizieren will (muss). Daran hatte ich nicht gedacht.
Ich bin ja ein starker verfechter für * als das Hadamard product (da sheißt komponntenweise multiplizieren). Es kommt wesntlich häufiger vor, als nur Farben zu multiplizieren und macht mehr sinn als * für dot oder skalarprodukt:Der ergebnistyp ist der selbe wie der Typ der Vektoren/matrizen und es gelten sogut wie alle mathematischen Axiome aus der Algebra. Afaik ist das Einzige, das nicht gilt a*b = 0 <=> a= 0 oder b= 0. Insofern ist es dem Kreuzprodukt oder dem äußeren Produkt klar zu bevorzugen. Was das Punktprodukt angeht: In C++ kriegt man ja beides gleichzeitig hin, wenn man es unbedingt will. ich halte aber inner_prod(a,b) schon für besser. Oder trans(a)*b für inneres und b*trans(a) für äußeres produkt, dann emuliert man die a^T b Notation (kriegt aber probleme mit der matrixmultiplikation, welche ich unter gar keinen Umständen als Operator defineiren würde)
-
otze schrieb:
[...] und b*trans(a) für äußeres produkt [...]
Das ist dann aber das dyadische Produkt und nicht das Kreuzprodukt, oder!?
-
hustbaer schrieb:
OK, jetzt verstehe ich was du meinst.
Wobei ich das Beispiel schlecht finde.
Das Ergebnis von nem dot ist ein Skalar, kein Vektor.zudem, auch wenn es nicht offensichtlich erscheint erstmal, wuerde ich bei vector operatoren auch immer nur vector parameter akzeptieren und zurueckgeben, weil man dann durchgaengig auf SIMD arbeiten kann, ansonsten kann es oefter vorkommen dass man aus simd zu float konvertiert nur um dann wieder auf simd zu konvertieren
hustbaer schrieb:
Also tut man es auch in einen Skalar reinmachen:
vec4 Radiosity=Lightmap... vec4 Normal=Normalmap... vec4 Color=Texture... float Diffuse=Light*Normal; vec4 FinalColor=Radiosity*Color*Diffuse;
Und schon passt es wieder nicht.
Vermutlich ist es aber mittlerweile schlauer sich an bestehende Dinge wie HLSL/Cg zu halten... und dort ist * ja glaube ich immer komponentenweise.
was schade ist, ist dass es nur diese primitiven operatoren gibt, eigentlich sollten ein paar mehr mathematische funktionen als operatoren definiert sein.
frueher hab ich ein wenig "profan" programmiert, bis version 4.2 oder so, gab es keine operatoren, ein dot war sowas wie
declare foo; foo=@add(@add(@mul(x0,x1),@mul(y0,y1)),@mul(z0,z1));
das hat mich ein wenig gelehrt, dass man fuer simple dinge die oft verwendet eher operatoren statt funktionen macht. und dot, cross, normalize, inverse finde ich zu gaengig fuer funktionen
-
rapso schrieb:
was schade ist, ist dass es nur diese primitiven operatoren gibt, eigentlich sollten ein paar mehr mathematische funktionen als operatoren definiert sein.
Meinst du Dinge wie z.B. symbolische Differentiation!?
-
rapso schrieb:
hustbaer schrieb:
OK, jetzt verstehe ich was du meinst.
Wobei ich das Beispiel schlecht finde.
Das Ergebnis von nem dot ist ein Skalar, kein Vektor.zudem, auch wenn es nicht offensichtlich erscheint erstmal, wuerde ich bei vector operatoren auch immer nur vector parameter akzeptieren und zurueckgeben, weil man dann durchgaengig auf SIMD arbeiten kann, ansonsten kann es oefter vorkommen dass man aus simd zu float konvertiert nur um dann wieder auf simd zu konvertieren
Ist v/vec4(x, x, x, x) wirklich schneller als v/x?
Ich meine v/x wird gerne mal zutemp = 1.0/x; v * vec4(temp, temp, temp, temp)
und das sollte doch eigentlich schneller sein.
Und durchgängig auf SIMD arbeiten... können aktuelle Compiler keinen Code erzeugen der SSE2 auch für einzelne floats verwendet? Ich dachte nämlich dass die das können, und dann wäre es ziemlich schnuppe ... bzw. sogar besser wenn man einzelne floats nimmt wo man nur einzelne floats braucht.Und auf GPUs ist es ja, soweit ich weiss, auch mittlerweile zur Sünde geworden mehr Komponenten zu verwenden als man eigentlich braucht. Skalare Shader Units und so...
Oder hab' ich da was falsch mitbekommen?
-
hustbaer schrieb:
Ist v/vec4(x, x, x, x) wirklich schneller als v/x?
Ich meine v/x wird gerne mal zutemp = 1.0/x; v * vec4(temp, temp, temp, temp)
und das sollte doch eigentlich schneller sein.
MSVC sollte das tun...
hustbaer schrieb:
Und durchgängig auf SIMD arbeiten... können aktuelle Compiler keinen Code erzeugen der SSE2 auch für einzelne floats verwendet? Ich dachte nämlich dass die das können, und dann wäre es ziemlich schnuppe ... bzw. sogar besser wenn man einzelne floats nimmt wo man nur einzelne floats braucht.
Unter x64 kann man mehr oder weniger davon ausgehen, dass der Compiler auch für skalare Operationen SSE verwendet. Unter x86 nicht unbedingt, zumindest MSVC scheint mir dort immer noch zumindest meistens die FPU zu verwenden, vermutlich vor allem aus Kompatibilitätsgründen.
hustbaer schrieb:
Und auf GPUs ist es ja, soweit ich weiss, auch mittlerweile zur Sünde geworden mehr Komponenten zu verwenden als man eigentlich braucht. Skalare Shader Units und so...
Oder hab' ich da was falsch mitbekommen?Auf NVIDIA Hardware >= GeForce 8 prinzipiell wohl ja, bei ATI schaut's dagegen anders aus, die verwenden afaik zumindest bis vor kurzem noch VLIW Vektorhardware, wobei iirc zumindest eine ihrer allerletzten Architekturen auch eher in die skalare Richtung ging...
-
dot schrieb:
hustbaer schrieb:
Und durchgängig auf SIMD arbeiten... können aktuelle Compiler keinen Code erzeugen der SSE2 auch für einzelne floats verwendet? Ich dachte nämlich dass die das können, und dann wäre es ziemlich schnuppe ... bzw. sogar besser wenn man einzelne floats nimmt wo man nur einzelne floats braucht.
Unter x64 kann man mehr oder weniger davon ausgehen, dass der Compiler auch für skalare Operationen SSE verwendet. Unter x86 nicht unbedingt, zumindest MSVC scheint mir dort immer noch zumindest meistens die FPU zu verwenden, vermutlich vor allem aus Kompatibilitätsgründen.
MSVC verwendet im x86 Mode SSE2 nur wenn man es ihm erlaubt. Hast du bei deinen Experimenten auch den nötigen Switch mitgegeben? Wäre dann schade, aber OK, wegen eines einzigen Compilers werd ich jetzt auch nicht Code schreiben der komisch riecht und auf anderen Compilern im Falle des Falles sogar langsamer ist.
hustbaer schrieb:
Und auf GPUs ist es ja, soweit ich weiss, auch mittlerweile zur Sünde geworden mehr Komponenten zu verwenden als man eigentlich braucht. Skalare Shader Units und so...
Oder hab' ich da was falsch mitbekommen?Auf NVIDIA Hardware >= GeForce 8 prinzipiell wohl ja, bei ATI schaut's dagegen anders aus, die verwenden afaik zumindest bis vor kurzem noch VLIW Vektorhardware, wobei iirc zumindest eine ihrer allerletzten Architekturen auch eher in die skalare Richtung ging...
Auch interessant, danke.
Wobei... wenn es auf NIVEA Karten pöse ist, dann ist es pöse und aus
(Und nicht pöse zu sein wird einem auf ATI Karten vermutlich auch keine Probleme machen, oder etwa doch?)