Kugel: Unterschied zwischen den Versionen
(Eine erste Variante) |
K (Aussen -> Außen) |
||
(15 dazwischenliegende Versionen von 5 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
− | Port von [http:// | + | ==Variante 1== |
+ | Der nachfolgende Code ist ein Port von [http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/sphere_cylinder/index.html http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/sphere_cylinder/index.html]. | ||
− | <pascal>procedure CreateSphere(c: TVector3f; r: Single; n: Integer); | + | Neben den Vertexpositionen werden die Normalen und Texturkoordinaten berechnet. |
+ | |||
+ | {{Hinweis|TVector3f ist ein einfaches Feld mit 3 Floats. (array[0..2] of float)}} | ||
+ | |||
+ | |||
+ | <source lang="pascal">procedure CreateSphere(c: TVector3f; r: Single; n: Integer); | ||
const | const | ||
TWOPI = PI*2; | TWOPI = PI*2; | ||
Zeile 54: | Zeile 60: | ||
glEnd; | glEnd; | ||
end; | end; | ||
− | end;</pascal> | + | end;</source> |
+ | |||
+ | |||
+ | |||
+ | ==Variante 2== | ||
+ | '''Der nachfolgende Code ist selbst geschrieben (MatReno)''' | ||
+ | |||
+ | Er ermöglicht das Zeichnen einer Kugel, oder beliebigen Halbkugel, mit | ||
+ | Texturkoordinaten und Normalen. | ||
+ | |||
+ | |||
+ | ===Benötigte Typen=== | ||
+ | |||
+ | <source lang="pascal"> | ||
+ | TVector2f : Array [0..1] of Single; | ||
+ | TVector3f : Array [0..2] of Single; | ||
+ | TVector4i : Array [0..3] of Integer; | ||
+ | </source> | ||
+ | |||
+ | |||
+ | ===Zusätzlich benötigte Methoden=== | ||
+ | |||
+ | <source lang="pascal"> | ||
+ | Function VectorAdd(const vector: TVector3f; Value: Single): TVector3f; | ||
+ | Begin | ||
+ | Result[0] := vector[0] + Value; | ||
+ | Result[1] := vector[1] + Value; | ||
+ | Result[2] := vector[2] + Value; | ||
+ | End; | ||
+ | </source> | ||
+ | |||
+ | |||
+ | <source lang="pascal"> | ||
+ | Function VectorMult(const vector: TVector3f; Value: Single): TVector3f; | ||
+ | Begin | ||
+ | Result[0] := vector[0] * Value; | ||
+ | Result[1] := vector[1] * Value; | ||
+ | Result[2] := vector[2] * Value; | ||
+ | End; | ||
+ | </source> | ||
+ | |||
+ | |||
+ | <source lang="pascal"> | ||
+ | Function ToVector2f(x, y: Single): TVector2f; | ||
+ | Begin | ||
+ | Result[0] := x; | ||
+ | Result[1] := y; | ||
+ | End; | ||
+ | </source> | ||
+ | |||
+ | |||
+ | <source lang="pascal"> | ||
+ | Function ToVector3f(x, y, z: Single): TVector3f; | ||
+ | Begin | ||
+ | Result[0] := x; | ||
+ | Result[1] := y; | ||
+ | Result[2] := z; | ||
+ | End; | ||
+ | </source> | ||
+ | |||
+ | |||
+ | <source lang="pascal"> | ||
+ | Function ToVector4i(x, y, z, w: Integer): TVector4i; | ||
+ | Begin | ||
+ | Result[0] := x; | ||
+ | Result[1] := y; | ||
+ | Result[2] := z; | ||
+ | Result[3] := w; | ||
+ | End; | ||
+ | </source> | ||
+ | |||
+ | |||
+ | ===Parametererklärung und Prozedur=== | ||
+ | |||
+ | radius: Radius der Kugel in OGL-Units | ||
+ | |||
+ | n: Genauigkeit | ||
+ | |||
+ | typ: Art (siehe Procedure Kommentar) | ||
+ | |||
+ | inverted: | ||
+ | |||
+ | = false -> FrontFace außen | ||
+ | |||
+ | = true -> FrontFace innen | ||
+ | |||
+ | voffset: Vektor (X, Y, Z) um den die Kugel verschoben wird | ||
+ | |||
+ | toffset: Vektor (U, V) um den die Textur verschoben wird | ||
+ | |||
+ | tscale: Textur-skalierung | ||
+ | |||
+ | |||
+ | <source lang="pascal"> | ||
+ | Procedure DrawSphereObject(radius: Single; n: word; | ||
+ | typ: byte; inverted: boolean; | ||
+ | voffset: TVector3f; toffset, tscale: TVector2f); | ||
+ | Var alpha : TVector2f; // i*beta around x axis | ||
+ | SinAlpha: TVector2f; // sin(alpha) | ||
+ | CosAlpha: TVector2f; // cos(alpha) | ||
+ | beta : Single; // DegToRad(360° / n) | ||
+ | delta : Single; // j*beta around z axis | ||
+ | SinDelta: Single; // sin(delta) | ||
+ | CosDelta: Single; // cos(delta) | ||
+ | h, q : word; // half, quarter | ||
+ | v : TVector3f; // vector for normal and vertex | ||
+ | border : TVector4i; // for-loop borders | ||
+ | i, j : Integer; | ||
+ | k : Byte; | ||
+ | Begin | ||
+ | radius := abs(radius); | ||
+ | |||
+ | If (n < 4) Or (Odd(n)) Or (radius = 0) Then Exit; | ||
+ | |||
+ | h := n div 2; | ||
+ | q := n div 4; | ||
+ | If (Odd(h)) Then inc(q); | ||
+ | |||
+ | Case typ of | ||
+ | 0: border := ToVector4i( -h, h-1, -q, q); // sphere | ||
+ | 1: border := ToVector4i( -h, h-1, -q, 0); // hemisphere x- | ||
+ | 2: border := ToVector4i( -h, h-1, 0, q); // hemisphere x+ | ||
+ | 3: border := ToVector4i(-h-q, -h+q-1, -q, q); // hemisphere y- | ||
+ | 4: border := ToVector4i( -q, q-1, -q, q); // hemisphere y+ | ||
+ | 5: border := ToVector4i( -h, -1, -q, q); // hemisphere z- | ||
+ | 6: border := ToVector4i( 0, h-1, -q, q); // hemisphere z+ | ||
+ | else Exit; | ||
+ | End; | ||
+ | |||
+ | beta := 2*PI / n; | ||
+ | |||
+ | For i:=border[0] to border[1] do Begin | ||
+ | alpha := ToVector2f(i*beta, (i+1)*beta); | ||
+ | |||
+ | SinAlpha := ToVector2f(sin(alpha[0]), sin(alpha[1])); | ||
+ | CosAlpha := ToVector2f(cos(alpha[0]), cos(alpha[1])); | ||
+ | |||
+ | glBegin(GL_TRIANGLE_STRIP); | ||
+ | For j:=border[2] to border[3] do Begin | ||
+ | delta := j*beta; | ||
+ | |||
+ | SinDelta := sin(delta); | ||
+ | CosDelta := cos(delta); | ||
+ | |||
+ | If (inverted) Then | ||
+ | For k:=1 downto 0 do Begin | ||
+ | v := ToVector3f(-SinDelta, -CosAlpha[k]*CosDelta, -SinAlpha[k]*CosDelta); | ||
+ | glNormal3fv(@v); | ||
+ | v := VectorAdd(VectorMult(v, -radius), voffset); | ||
+ | glTexCoord2f((j/n + 0.25)*tscale[0] + toffset[0], ((i+k)/n)*tscale[1] + toffset[1]); | ||
+ | glvertex3fv(@v); | ||
+ | End; | ||
+ | |||
+ | If (not inverted) Then | ||
+ | For k:=0 to 1 do Begin | ||
+ | v := ToVector3f(SinDelta, CosAlpha[k]*CosDelta, SinAlpha[k]*CosDelta); | ||
+ | glNormal3fv(@v); | ||
+ | v := VectorAdd(VectorMult(v, radius), voffset); | ||
+ | glTexCoord2f((j/n + 0.25)*tscale[0] + toffset[0], ((i+k)/n)*tscale[1] + toffset[1]); | ||
+ | glvertex3fv(@v); | ||
+ | End | ||
+ | End; | ||
+ | glEnd; | ||
+ | End; | ||
+ | End; | ||
+ | </source> | ||
+ | |||
+ | |||
+ | ===Beispielaufruf=== | ||
+ | |||
+ | <source lang="pascal"> | ||
+ | Const | ||
+ | ONE_VECTOR_2f : TVector2f = (1, 1); | ||
+ | NULL_VECTOR_2f : TVector2f = (0, 0); | ||
+ | NULL_VECTOR_3f : TVector3f = (0, 0, 0); | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Um eine Kugel zu rendern muss man z.B. folgendes aufrufen: | ||
+ | <source lang="pascal"> | ||
+ | DrawSphereObject(5, | ||
+ | 32, | ||
+ | 0, | ||
+ | false, | ||
+ | NULL_VECTOR_3f, | ||
+ | NULL_VECTOR_2f, | ||
+ | ONE_VECTOR_2f); | ||
+ | </source> | ||
+ | |||
+ | == Alternative == | ||
+ | |||
+ | Als Alternative zu selbstgeschrieben Code bieten sich die [[Quadrik|Quadriken]] an, mit denen sich mit verhältnissmäßig wenigen Aufrufen verschiedene Formen erzeugen lassen. | ||
+ | |||
+ | [[Kategorie:Technik_oder_Algorithmus]] [[Kategorie:Anleitung]] |
Aktuelle Version vom 21. März 2012, 15:35 Uhr
Inhaltsverzeichnis
Variante 1
Der nachfolgende Code ist ein Port von http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/sphere_cylinder/index.html.
Neben den Vertexpositionen werden die Normalen und Texturkoordinaten berechnet.
TVector3f ist ein einfaches Feld mit 3 Floats. (array[0..2] of float) |
procedure CreateSphere(c: TVector3f; r: Single; n: Integer);
const
TWOPI = PI*2;
PID2 = PI/2;
var
i,j: Integer;
theta1,theta2,theta3: Single;
e,p:TVector3f;
begin
if (r < 0) then r := -r;
if (n < 0) then n := -n;
if (n < 4) or (r <= 0) then
begin
glBegin(GL_POINTS);
glVertex3f(c[0],c[1],c[2]);
glEnd;
exit;
end;
for j:=0 to n div 2 do
begin
theta1 := j * TWOPI / n - PID2;
theta2 := (j + 1) * TWOPI / n - PID2;
glBegin(GL_QUAD_STRIP);
for i:=0 to n do
begin
theta3 := i * TWOPI / n;
e[0] := cos(theta2) * cos(theta3);
e[1] := sin(theta2);
e[2] := cos(theta2) * sin(theta3);
p[0] := c[0] + r * e[0];
p[1] := c[1] + r * e[1];
p[2] := c[2] + r * e[2];
glNormal3f(e[0],e[1],e[2]);
glTexCoord2f(i/n,2*(j+1)/n);
glVertex3f(p[0],p[1],p[2]);
e[0] := cos(theta1) * cos(theta3);
e[1] := sin(theta1);
e[2] := cos(theta1) * sin(theta3);
p[0] := c[0] + r * e[0];
p[1] := c[1] + r * e[1];
p[2] := c[2] + r * e[2];
glNormal3f(e[0],e[1],e[2]);
glTexCoord2f(i/n,2*j/n);
glVertex3f(p[0],p[1],p[2]);
end;
glEnd;
end;
end;
Variante 2
Der nachfolgende Code ist selbst geschrieben (MatReno)
Er ermöglicht das Zeichnen einer Kugel, oder beliebigen Halbkugel, mit Texturkoordinaten und Normalen.
Benötigte Typen
TVector2f : Array [0..1] of Single;
TVector3f : Array [0..2] of Single;
TVector4i : Array [0..3] of Integer;
Zusätzlich benötigte Methoden
Function VectorAdd(const vector: TVector3f; Value: Single): TVector3f;
Begin
Result[0] := vector[0] + Value;
Result[1] := vector[1] + Value;
Result[2] := vector[2] + Value;
End;
Function VectorMult(const vector: TVector3f; Value: Single): TVector3f;
Begin
Result[0] := vector[0] * Value;
Result[1] := vector[1] * Value;
Result[2] := vector[2] * Value;
End;
Function ToVector2f(x, y: Single): TVector2f;
Begin
Result[0] := x;
Result[1] := y;
End;
Function ToVector3f(x, y, z: Single): TVector3f;
Begin
Result[0] := x;
Result[1] := y;
Result[2] := z;
End;
Function ToVector4i(x, y, z, w: Integer): TVector4i;
Begin
Result[0] := x;
Result[1] := y;
Result[2] := z;
Result[3] := w;
End;
Parametererklärung und Prozedur
radius: Radius der Kugel in OGL-Units
n: Genauigkeit
typ: Art (siehe Procedure Kommentar)
inverted:
= false -> FrontFace außen
= true -> FrontFace innen
voffset: Vektor (X, Y, Z) um den die Kugel verschoben wird
toffset: Vektor (U, V) um den die Textur verschoben wird
tscale: Textur-skalierung
Procedure DrawSphereObject(radius: Single; n: word;
typ: byte; inverted: boolean;
voffset: TVector3f; toffset, tscale: TVector2f);
Var alpha : TVector2f; // i*beta around x axis
SinAlpha: TVector2f; // sin(alpha)
CosAlpha: TVector2f; // cos(alpha)
beta : Single; // DegToRad(360° / n)
delta : Single; // j*beta around z axis
SinDelta: Single; // sin(delta)
CosDelta: Single; // cos(delta)
h, q : word; // half, quarter
v : TVector3f; // vector for normal and vertex
border : TVector4i; // for-loop borders
i, j : Integer;
k : Byte;
Begin
radius := abs(radius);
If (n < 4) Or (Odd(n)) Or (radius = 0) Then Exit;
h := n div 2;
q := n div 4;
If (Odd(h)) Then inc(q);
Case typ of
0: border := ToVector4i( -h, h-1, -q, q); // sphere
1: border := ToVector4i( -h, h-1, -q, 0); // hemisphere x-
2: border := ToVector4i( -h, h-1, 0, q); // hemisphere x+
3: border := ToVector4i(-h-q, -h+q-1, -q, q); // hemisphere y-
4: border := ToVector4i( -q, q-1, -q, q); // hemisphere y+
5: border := ToVector4i( -h, -1, -q, q); // hemisphere z-
6: border := ToVector4i( 0, h-1, -q, q); // hemisphere z+
else Exit;
End;
beta := 2*PI / n;
For i:=border[0] to border[1] do Begin
alpha := ToVector2f(i*beta, (i+1)*beta);
SinAlpha := ToVector2f(sin(alpha[0]), sin(alpha[1]));
CosAlpha := ToVector2f(cos(alpha[0]), cos(alpha[1]));
glBegin(GL_TRIANGLE_STRIP);
For j:=border[2] to border[3] do Begin
delta := j*beta;
SinDelta := sin(delta);
CosDelta := cos(delta);
If (inverted) Then
For k:=1 downto 0 do Begin
v := ToVector3f(-SinDelta, -CosAlpha[k]*CosDelta, -SinAlpha[k]*CosDelta);
glNormal3fv(@v);
v := VectorAdd(VectorMult(v, -radius), voffset);
glTexCoord2f((j/n + 0.25)*tscale[0] + toffset[0], ((i+k)/n)*tscale[1] + toffset[1]);
glvertex3fv(@v);
End;
If (not inverted) Then
For k:=0 to 1 do Begin
v := ToVector3f(SinDelta, CosAlpha[k]*CosDelta, SinAlpha[k]*CosDelta);
glNormal3fv(@v);
v := VectorAdd(VectorMult(v, radius), voffset);
glTexCoord2f((j/n + 0.25)*tscale[0] + toffset[0], ((i+k)/n)*tscale[1] + toffset[1]);
glvertex3fv(@v);
End
End;
glEnd;
End;
End;
Beispielaufruf
Const
ONE_VECTOR_2f : TVector2f = (1, 1);
NULL_VECTOR_2f : TVector2f = (0, 0);
NULL_VECTOR_3f : TVector3f = (0, 0, 0);
Um eine Kugel zu rendern muss man z.B. folgendes aufrufen:
DrawSphereObject(5,
32,
0,
false,
NULL_VECTOR_3f,
NULL_VECTOR_2f,
ONE_VECTOR_2f);
Alternative
Als Alternative zu selbstgeschrieben Code bieten sich die Quadriken an, mit denen sich mit verhältnissmäßig wenigen Aufrufen verschiedene Formen erzeugen lassen.