PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Beliebigen orthogonalen Vektor berechnen


AlSvartr
2006-11-02, 15:52:48
Hallo zusammen,

ich habe ein kleines auf-dem-Schlauch-steh-Problem..und zwar möchte ich zu einem Vektor einen beliebigen orthogonalen Vektor berechnen. Da ich ihn nur zu diesem einen Vektor errechnen möchte, kann ich natürlich nicht auf das Kreuzprodukt zurückgreifen. Also dachte ich mir, ich nehme mir das Skalarprodukt, setze es gleich 0 und mache Fallunterscheidungen je nach Eingabevektor...das ganze resultierte dann in 7 Fallunterscheidungen (8, wenn man berücksichtigt, dass alle Komponenten des Vektors 0 sein könnten...):


public Vector3d getRandomOrthogonal(Vector3d v) {
Vector3d u=new Vector3d();
int vCase=0;
if (v.x==0)
vCase+=1;
if (v.y==0)
vCase+=2;
if (v.z==0)
vCase+=4;
switch (vCase) {
case 0: //Nothing's zero
u.x=Math.random();
u.y=Math.random();
u.z=-(v.x*u.x+v.y*u.y)/v.z;
break;
case 1: //v.x is zero
u.x=0;
u.y=Math.random();
u.z=-(v.y*u.y)/v.z;
break;
case 2: //v.y is zero
u.x=Math.random();
u.y=0;
u.z=-(v.x*u.x)/v.z;
break;
case 4: //v.z is zero
u.x=Math.random();
u.z=0;
u.y=-(v.x*u.x)/v.y;
break;
case 3: //v.x and v.y are zero
u.set(v.z,0,0);
break;
case 5: //v.x and v.z are zero
u.set(v.y,0,0);
break;
case 6: //v.y and v.z are zero
u.set(0,v.x,0);
break;
case 7: //Everything is zero
break;
default:
break;
}
u.normalize();
return u;
}


Nun ist meine Frage: Geht das nicht einfacher? :wink: ... mir kommt das wesentlich zu fummelig vor, nur um eine einfache Orthogonale zu bekommen..in 2d ist das ja ganz einfach mit u=(v_y -v_x)^T möglich..

<edit>Das Math.random() kann ich natürlich auch jeweils durch 1 ersetzen...pseudozufällig muss der Vektor nämlich eigentlich nicht unbedingt sein..

Xmas
2006-11-02, 16:28:25
if (v.y == 0)
u = cross(v, new vec3(0, 1, 0));
else
u = cross(v, new vec3(1, 0, 0);
u.normalize();

AlSvartr
2006-11-02, 17:05:00
Au Backe...danke :D

HajottV
2006-11-02, 18:14:50
Argh!

Xmas schäm Dich! :P

if (v.x == 0)
u = new vec3(1, 0, 0));
else {
u = new vec3(-v.y, v.x, 0);
u.normalize();
}

Gruß

Jörg

Xmas
2006-11-02, 18:25:19
Hach ja... schon viel zu lange nicht mehr wirklich mit Vektoren gerechnet. :redface:

AlSvartr
2006-11-03, 01:59:44
Da ich bei Euch ja scheinbar an der richtigen Adresse bin, wage ich mal gleich noch eine Frage..und zwar möchte ich von einer Normalen ausgehend Punkte auf deren Hemisphäre finden..ich hab das jetzt megaumständlich folgendermaßen gemacht: Ich bilde mir die beiden Orthogonalen, wähle innerhalb eines Einheitskreises auf der durch diese beschriebenen Ebene einen zufälligen Punkt und errechne den für eine Kugel mit dem Radius 1 zugehörigen Punkt auf eben dieser.

Das geht doch bestimmt auch einfacher? (benötige das für Ambient Occlusion, heißt, ich mach es schon einige Male pro Pixel :wink:)

Also wenns da nen wesentlich einfacheren Ansatz gibt..immer her damit :D

ScottManDeath
2006-11-03, 07:46:24
Wenn Du für AO eine Cosine Distribution hast, geht es AFAIK nur so.

Ich mach das auch so in meinem Path tracer, allerdings berechne ich den Tangent Space in Abhängigkeit von der 2D UV Parametrisierung.

Für eine Uniform Distribution dagegen generiert man einfach einen Vektor auf der kompletten Sphere und multipliziert ihn mit -1, wenn dot(vector, normal) < 0 ist.

AlSvartr
2006-11-03, 12:06:12
Für eine Uniform Distribution dagegen generiert man einfach einen Vektor auf der kompletten Sphere und multipliziert ihn mit -1, wenn dot(vector, normal) < 0 ist.
Das macht man tatsächlich..? Ich hatte mir sowas schon gedacht, aber das klang für mich irgendwie einfach zu grenzbanal, so dass ich es nicht hinnehmen wollte.. ;)

Xmas
2006-11-03, 12:10:48
Kommt auf die Verteilung an die du willst. Eine Möglichkeit wäre eine Lookup-Table mit 2^n Vektoren für einen Oktant der Hemisphäre zu (0, 0, 1). Dann erzeugst du einen Zufalls-Integer, von dem du n Bits zum Indizieren der LUT verwendest, ein Bit entscheidet ob x und y getauscht werden sollen, und jeweils ein Bit entscheidet über einen Vorzeichenwechsel für x und y. Dann transformierst du den Vektor in deinen Tangent Space indem du die Komponenten mit den Achsen multiplizierst und aufsummierst.

const int IndexBits = 8;
vec3 Lut[1 << IndexBits] = { ... };

vec3 n, t1, t2; // normale und 2 orthogonalen
int i = randomInt();
vec3 v = Lut[i & ((1 << IndexBits) - 1)];
if (i & (1 << (IndexBits + 1))) swap(v.x, v.y);
if (i & (1 << (IndexBits + 2))) v.x = -v.x;
if (i & (1 << (IndexBits + 3))) v.y = -v.y;
v = v.x * t1 + v.y * t2 + v.z * n;
Bin mir allerdings nicht sicher ob das wirklich effizienter wäre.

ScottManDeath
2006-11-03, 19:06:03
Path tracing / Adjoint Photons ist eh langsam, da kommts auf solche Mikrooptimierungen nicht wirklich an. Flaschen hals sind die Ray/ Object intersections.....

Raytracing auf Nextgeneration HW macht 1 Milliarde Ray/Triangle intersections pro Sekunde..... (ohne Shading)